diff --git a/DEPS b/DEPS
index 2dbff98..067bcc2 100644
--- a/DEPS
+++ b/DEPS
@@ -52,7 +52,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': 'fd8b469ebc8f63d0579cb62da94fe5d393503a78',
+  'angle_revision': 'c1a5d16e964ad524487eac9d2e4b5a65d837ff27',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling build tools
   # and whatever else without interference from each other.
@@ -64,7 +64,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': '95bec8046a28928df627ce4d48eee8b209b3e36e',
+  'pdfium_revision': '341b5c2c1cbd310d29ef3db2dbea1ec9b1b981ec',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling openmax_dl
   # and whatever else without interference from each other.
@@ -96,7 +96,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '1e05d2f8401ce9b112c2f0e21269f1d7493ce88b',
+  'catapult_revision': 'fe2fa4bc83c5a2ffbc1be54ebbdece0db8473335',
   # 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/ash/common/wm_shell.cc b/ash/common/wm_shell.cc
index 075d6d2b..0674f7a 100644
--- a/ash/common/wm_shell.cc
+++ b/ash/common/wm_shell.cc
@@ -293,13 +293,13 @@
           base::MakeUnique<WindowSelectorController>()) {
   session_controller_->AddSessionStateObserver(this);
 
-  prefs::mojom::PreferencesManagerPtr pref_manager_ptr;
+  prefs::mojom::PreferencesFactoryPtr pref_factory_ptr;
   // Can be null in tests.
   if (!delegate_->GetShellConnector())
     return;
   delegate_->GetShellConnector()->BindInterface(prefs::mojom::kServiceName,
-                                                &pref_manager_ptr);
-  pref_store_ = new preferences::PrefObserverStore(std::move(pref_manager_ptr));
+                                                &pref_factory_ptr);
+  pref_store_ = new preferences::PrefObserverStore(std::move(pref_factory_ptr));
 }
 
 RootWindowController* WmShell::GetPrimaryRootWindowController() {
diff --git a/ash/content/keyboard_overlay/keyboard_overlay_delegate.cc b/ash/content/keyboard_overlay/keyboard_overlay_delegate.cc
index 14af0f5..bc79aca67 100644
--- a/ash/content/keyboard_overlay/keyboard_overlay_delegate.cc
+++ b/ash/content/keyboard_overlay/keyboard_overlay_delegate.cc
@@ -78,10 +78,9 @@
   // Show the widget at the bottom of the work area.
   gfx::Size size;
   GetDialogSize(&size);
-  const gfx::Rect& rect =
-      display::Screen::GetScreen()
-          ->GetDisplayNearestWindow(widget_->GetNativeView())
-          .work_area();
+  const gfx::Rect rect = display::Screen::GetScreen()
+                             ->GetDisplayNearestWindow(widget_->GetNativeView())
+                             .work_area();
   gfx::Rect bounds(rect.x() + (rect.width() - size.width()) / 2,
                    rect.y() + (rect.height() - size.height()) / 2, size.width(),
                    size.height());
diff --git a/ash/frame/caption_buttons/frame_size_button_unittest.cc b/ash/frame/caption_buttons/frame_size_button_unittest.cc
index a14c83d6..7674b9b 100644
--- a/ash/frame/caption_buttons/frame_size_button_unittest.cc
+++ b/ash/frame/caption_buttons/frame_size_button_unittest.cc
@@ -331,9 +331,9 @@
   EXPECT_EQ(CAPTION_BUTTON_ICON_LEFT_SNAPPED, minimize_button()->icon());
   EXPECT_EQ(CAPTION_BUTTON_ICON_RIGHT_SNAPPED, close_button()->icon());
 
-  const gfx::Rect& kWorkAreaBoundsInScreen =
+  const gfx::Rect work_area_bounds_in_screen =
       display::Screen::GetScreen()->GetPrimaryDisplay().work_area();
-  generator.MoveMouseTo(kWorkAreaBoundsInScreen.bottom_left());
+  generator.MoveMouseTo(work_area_bounds_in_screen.bottom_left());
 
   // None of the buttons should be pressed because we are really far away from
   // any of the caption buttons. The minimize and close button icons should
@@ -382,9 +382,9 @@
   // Moving the mouse far away from the caption buttons and then moving it over
   // the close button (snap right button) should hover the close button and
   // keep the size button pressed.
-  const gfx::Rect& kWorkAreaBoundsInScreen =
+  const gfx::Rect work_area_bounds_in_screen =
       display::Screen::GetScreen()->GetPrimaryDisplay().work_area();
-  generator.MoveMouseTo(kWorkAreaBoundsInScreen.bottom_left());
+  generator.MoveMouseTo(work_area_bounds_in_screen.bottom_left());
   EXPECT_TRUE(AllButtonsInNormalState());
   generator.MoveMouseTo(CenterPointInScreen(close_button()));
   EXPECT_EQ(views::Button::STATE_NORMAL, minimize_button()->state());
diff --git a/ash/system/web_notification/ash_popup_alignment_delegate_unittest.cc b/ash/system/web_notification/ash_popup_alignment_delegate_unittest.cc
index d40daa8..3ae5f22f 100644
--- a/ash/system/web_notification/ash_popup_alignment_delegate_unittest.cc
+++ b/ash/system/web_notification/ash_popup_alignment_delegate_unittest.cc
@@ -71,7 +71,7 @@
   }
 
   Position GetPositionInDisplay(const gfx::Point& point) {
-    const gfx::Rect& work_area =
+    const gfx::Rect work_area =
         display::Screen::GetScreen()->GetPrimaryDisplay().work_area();
     const gfx::Point center_point = work_area.CenterPoint();
     if (work_area.x() > point.x() || work_area.y() > point.y() ||
diff --git a/build/android/pylib/local/device/local_device_environment.py b/build/android/pylib/local/device/local_device_environment.py
index 31eba17..2aaf88b 100644
--- a/build/android/pylib/local/device/local_device_environment.py
+++ b/build/android/pylib/local/device/local_device_environment.py
@@ -2,6 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import contextlib
 import datetime
 import functools
 import logging
@@ -20,6 +21,8 @@
 from devil.utils import parallelizer
 from pylib import constants
 from pylib.base import environment
+from py_trace_event import trace_event
+from tracing_build import trace2html
 
 
 def _DeviceCachePath(device):
@@ -90,6 +93,7 @@
     self._skip_clear_data = args.skip_clear_data
     self._target_devices_file = args.target_devices_file
     self._tool_name = args.tool
+    self._trace_output = args.trace_output
 
   #override
   def SetUp(self):
@@ -144,6 +148,15 @@
 
     self.parallel_devices.pMap(prepare_device)
 
+  @staticmethod
+  def _JsonToTrace(json_path, html_path, delete_json=True):
+    # First argument is call site.
+    cmd = [__file__, json_path, '--title', 'Android Test Runner Trace',
+           '--output', html_path]
+    trace2html.Main(cmd)
+    if delete_json:
+      os.remove(json_path)
+
   @property
   def blacklist(self):
     return self._blacklist
@@ -178,6 +191,10 @@
   def tool(self):
     return self._tool_name
 
+  @property
+  def trace_output(self):
+    return self._trace_output
+
   #override
   def TearDown(self):
     if self._devices is None:
@@ -231,3 +248,24 @@
     with self._devices_lock:
       self._devices = [d for d in self._devices if str(d) != device_serial]
 
+  def DisableTracing(self):
+    if not trace_event.trace_is_enabled():
+      logging.warning('Tracing is not running.')
+    else:
+      trace_event.trace_disable()
+    self._JsonToTrace(self._trace_output + '.json',
+                      self._trace_output)
+
+  def EnableTracing(self):
+    if trace_event.trace_is_enabled():
+      logging.warning('Tracing is already running.')
+    else:
+      trace_event.trace_enable(self._trace_output + '.json')
+
+  @contextlib.contextmanager
+  def Tracing(self):
+    try:
+      self.EnableTracing()
+      yield
+    finally:
+      self.DisableTracing()
diff --git a/build/android/pylib/local/device/local_device_gtest_run.py b/build/android/pylib/local/device/local_device_gtest_run.py
index b25b1762..e99c4a55 100644
--- a/build/android/pylib/local/device/local_device_gtest_run.py
+++ b/build/android/pylib/local/device/local_device_gtest_run.py
@@ -19,6 +19,8 @@
 from pylib.local import local_test_server_spawner
 from pylib.local.device import local_device_environment
 from pylib.local.device import local_device_test_run
+from py_trace_event import trace_event
+from py_utils import contextlib_ext
 import tombstones
 
 _MAX_INLINE_FLAGS_LENGTH = 50  # Arbitrarily chosen.
@@ -371,29 +373,35 @@
   #override
   def _RunTest(self, device, test):
     # Run the test.
-    timeout = (self._test_instance.shard_timeout
-               * self.GetTool(device).GetTimeoutScale())
-    if self._test_instance.store_tombstones:
-      tombstones.ClearAllTombstones(device)
-    with device_temp_file.DeviceTempFile(
-        adb=device.adb,
-        dir=self._delegate.ResultsDirectory(device),
-        suffix='.xml') as device_tmp_results_file:
+    with contextlib_ext.Optional(
+        self._env.Tracing(),
+        self._env.trace_output):
+      timeout = (self._test_instance.shard_timeout
+                 * self.GetTool(device).GetTimeoutScale())
+      if self._test_instance.store_tombstones:
+        tombstones.ClearAllTombstones(device)
+      with device_temp_file.DeviceTempFile(
+          adb=device.adb,
+          dir=self._delegate.ResultsDirectory(device),
+          suffix='.xml') as device_tmp_results_file:
 
-      flags = self._test_instance.test_arguments or ''
-      if self._test_instance.enable_xml_result_parsing:
-        flags += ' --gtest_output=xml:%s' % device_tmp_results_file.name
-      if self._test_instance.gtest_also_run_disabled_tests:
-        flags += ' --gtest_also_run_disabled_tests'
+        flags = self._test_instance.test_arguments or ''
+        if self._test_instance.enable_xml_result_parsing:
+          flags += ' --gtest_output=xml:%s' % device_tmp_results_file.name
+        if self._test_instance.gtest_also_run_disabled_tests:
+          flags += ' --gtest_also_run_disabled_tests'
 
-      output = self._delegate.Run(
-          test, device, flags=flags,
-          timeout=timeout, retries=0)
+        with contextlib_ext.Optional(
+            trace_event.trace(str(test)),
+            self._env.trace_output):
+          output = self._delegate.Run(
+              test, device, flags=flags,
+              timeout=timeout, retries=0)
 
-      if self._test_instance.enable_xml_result_parsing:
-        gtest_xml = device.ReadFile(
-            device_tmp_results_file.name,
-            as_root=True)
+        if self._test_instance.enable_xml_result_parsing:
+          gtest_xml = device.ReadFile(
+              device_tmp_results_file.name,
+              as_root=True)
 
     for s in self._servers[str(device)]:
       s.Reset()
diff --git a/build/android/pylib/local/device/local_device_perf_test_run.py b/build/android/pylib/local/device/local_device_perf_test_run.py
index b34c360..77f1a4e 100644
--- a/build/android/pylib/local/device/local_device_perf_test_run.py
+++ b/build/android/pylib/local/device/local_device_perf_test_run.py
@@ -102,7 +102,7 @@
 
       with contextlib_ext.Optional(
           trace_event.trace(test),
-          self._test_instance.trace_output):
+          self._env.trace_output):
         exit_code, output = cmd_helper.GetCmdStatusAndOutputWithTimeout(
             cmd, timeout, cwd=cwd, shell=True)
       end_time = time.time()
@@ -424,14 +424,6 @@
 
   #override
   def RunTests(self):
-    # Affinitize the tests.
-    if self._test_instance.trace_output:
-      assert not trace_event.trace_is_enabled(), 'Tracing already running.'
-      trace_event.trace_enable(self._test_instance.trace_output + '.json')
-    self._SplitTestsByAffinity()
-    if not self._test_buckets and not self._no_device_tests:
-      raise local_device_test_run.NoTestsError()
-
     def run_no_devices_tests():
       if not self._no_device_tests:
         return []
@@ -463,14 +455,17 @@
           device_shard_helper)
       return [x for x in shards.pGet(self._timeout) if x is not None]
 
-    host_test_results, device_test_results = reraiser_thread.RunAsync(
-        [run_no_devices_tests, run_devices_tests])
-    if self._test_instance.trace_output:
-      assert trace_event.trace_is_enabled(), 'Tracing not running.'
-      trace_event.trace_disable()
-      local_device_test_run.LocalDeviceTestRun._JsonToTrace(
-          self._test_instance.trace_output + '.json',
-          self._test_instance.trace_output)
+    # Run the tests.
+    with contextlib_ext.Optional(
+        self._env.Tracing(),
+        self._env.trace_output):
+      # Affinitize the tests.
+      self._SplitTestsByAffinity()
+      if not self._test_buckets and not self._no_device_tests:
+        raise local_device_test_run.NoTestsError()
+      host_test_results, device_test_results = reraiser_thread.RunAsync(
+          [run_no_devices_tests, run_devices_tests])
+
     return host_test_results + device_test_results
 
   # override
diff --git a/build/android/pylib/local/device/local_device_test_run.py b/build/android/pylib/local/device/local_device_test_run.py
index 2b82c8e..1d7ebdf8 100644
--- a/build/android/pylib/local/device/local_device_test_run.py
+++ b/build/android/pylib/local/device/local_device_test_run.py
@@ -5,7 +5,6 @@
 import fnmatch
 import imp
 import logging
-import os
 import posixpath
 import signal
 import thread
@@ -17,7 +16,6 @@
 from pylib.base import test_run
 from pylib.base import test_collection
 from pylib.local.device import local_device_environment
-from tracing_build import trace2html
 
 
 _SIGTERM_TEST_LOG = (
@@ -205,15 +203,6 @@
   def _ShouldShard(self):
     raise NotImplementedError
 
-  @staticmethod
-  def _JsonToTrace(json_path, html_path, delete_json=True):
-    # First argument is call site.
-    cmd = [__file__, json_path, '--title', 'Android Test Runner Trace',
-           '--output', html_path]
-    trace2html.Main(cmd)
-    if delete_json:
-      os.remove(json_path)
-
 
 class NoTestsError(Exception):
   """Error for when no tests are found."""
diff --git a/build/android/pylib/perf/perf_test_instance.py b/build/android/pylib/perf/perf_test_instance.py
index 3ccc8d3..c897f18 100644
--- a/build/android/pylib/perf/perf_test_instance.py
+++ b/build/android/pylib/perf/perf_test_instance.py
@@ -81,7 +81,6 @@
         ' '.join(args.single_step_command) if args.single_step else None)
     self._steps = args.steps
     self._test_filter = args.test_filter
-    self._trace_output = args.trace_output
     self._write_buildbot_json = args.write_buildbot_json
 
   #override
@@ -266,10 +265,6 @@
   def test_filter(self):
     return self._test_filter
 
-  @property
-  def trace_output(self):
-    return self._trace_output
-
 
 class PersistentDataError(base_error.BaseError):
   def __init__(self, message):
diff --git a/build/android/test_runner.py b/build/android/test_runner.py
index b5b4da12..37d565a 100755
--- a/build/android/test_runner.py
+++ b/build/android/test_runner.py
@@ -110,6 +110,10 @@
                      dest='json_results_file', type=os.path.realpath,
                      help='If set, will dump results in JSON form '
                           'to specified file.')
+  group.add_argument('--trace-output', metavar='FILENAME',
+                     type=os.path.realpath,
+                     help='Path to save test_runner trace data to. This option '
+                          'has been implemented for gtest and perf test.')
 
   logcat_output_group = group.add_mutually_exclusive_group()
   logcat_output_group.add_argument(
@@ -537,10 +541,6 @@
   group.add_argument(
       '--write-buildbot-json', action='store_true',
       help='Whether to output buildbot json.')
-  # TODO(rnephew): Move up to top level options when implemented on all tests.
-  group.add_argument(
-      '--trace-output', metavar='FILENAME', type=os.path.realpath,
-      help='Path to save test_runner trace data to.')
   AddCommonOptions(parser)
   AddDeviceOptions(parser)
 
diff --git a/chrome/android/java/res/layout/custom_tabs_bottombar.xml b/chrome/android/java/res/layout/custom_tabs_bottombar.xml
index 18f99ecd..d322e86 100644
--- a/chrome/android/java/res/layout/custom_tabs_bottombar.xml
+++ b/chrome/android/java/res/layout/custom_tabs_bottombar.xml
@@ -4,7 +4,6 @@
      found in the LICENSE file. -->
 <org.chromium.chrome.browser.widget.BoundedLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:chrome="http://schemas.android.com/apk/res-auto"
-    android:id="@+id/bottombar"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:orientation="vertical"
@@ -14,7 +13,6 @@
         android:id="@+id/bottombar_shadow"
         android:layout_width="match_parent"
         android:layout_height="4dp"
-        android:background="@drawable/toolbar_shadow_normal"
-        android:scaleY="-1" />
+        android:background="@drawable/infobar_shadow_top" />
 
 </org.chromium.chrome.browser.widget.BoundedLinearLayout>
\ No newline at end of file
diff --git a/chrome/android/java/res/layout/main.xml b/chrome/android/java/res/layout/main.xml
index 15801a3..0cec21d 100644
--- a/chrome/android/java/res/layout/main.xml
+++ b/chrome/android/java/res/layout/main.xml
@@ -21,6 +21,15 @@
                 android:layout_height="match_parent" />
 
             <ViewStub
+                android:id="@+id/bottombar_stub"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="-4dp"
+                android:layout_gravity="start|bottom"
+                android:inflatedId="@+id/bottombar"
+                android:layout="@layout/custom_tabs_bottombar" />
+
+            <ViewStub
                 android:id="@+id/omnibox_results_container_stub"
                 android:layout_width="match_parent"
                 android:layout_height="match_parent"
@@ -65,12 +74,6 @@
             android:fillViewport="true"
             android:scrollbars="none"
             android:visibility="gone" />
-
-        <ViewStub
-            android:id="@+id/bottombar_stub"
-            android:layout_width="match_parent"
-            android:layout_marginTop="-4dp"
-            android:layout_height="wrap_content" />
     </LinearLayout>
 
     <!-- This empty view is used as the anchor for custom menu -->
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java
index 936ea13..593dcc21 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java
@@ -100,7 +100,6 @@
     private View mAccessibilityView;
     private CompositorAccessibilityProvider mNodeProvider;
     private float mLastContentOffset;
-    private float mLastVisibleContentOffset;
 
     /** The toolbar control container. **/
     private ControlContainer mControlContainer;
@@ -443,7 +442,6 @@
     public void onStart() {
         if (mFullscreenManager != null) {
             mLastContentOffset = mFullscreenManager.getContentOffset();
-            mLastVisibleContentOffset = mFullscreenManager.getTopVisibleContentOffset();
             mFullscreenManager.addListener(this);
         }
         requestRender();
@@ -463,8 +461,7 @@
     }
 
     @Override
-    public void onVisibleContentOffsetChanged(float offset, boolean needsAnimate) {
-        mLastVisibleContentOffset = offset;
+    public void onControlsOffsetChanged(float topOffset, float bottomOffset, boolean needsAnimate) {
         onViewportChanged();
         if (needsAnimate) requestRender();
     }
@@ -662,7 +659,6 @@
         mFullscreenManager = fullscreen;
         if (mFullscreenManager != null) {
             mLastContentOffset = mFullscreenManager.getContentOffset();
-            mLastVisibleContentOffset = mFullscreenManager.getTopVisibleContentOffset();
             mFullscreenManager.addListener(this);
         }
         onViewportChanged();
@@ -704,7 +700,7 @@
     public float getOverlayTranslateY() {
         return areBrowserControlsPermanentlyHidden()
                 ? getTopControlsHeightPixels()
-                : mLastVisibleContentOffset;
+                : mFullscreenManager.getTopVisibleContentOffset();
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuItemDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuItemDelegate.java
index 765210e6..1e622413 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuItemDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuItemDelegate.java
@@ -153,9 +153,4 @@
      * @param pageUrl URL of the current page.
      */
     void onOpenInChrome(String linkUrl, String pageUrl);
-
-    /**
-     * Called to queue a task to sometime later make an offline page for this url.
-     */
-    void onSavePageLater(String linkUrl);
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
index 0a7e2e0..dc3c7dc 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
@@ -173,6 +173,8 @@
         public void didAddTab(Tab tab, TabLaunchType type) {
             PageLoadMetrics.addObserver(mMetricsObserver);
             tab.addObserver(mTabObserver);
+            getFullscreenManager().setBottomControlsHeight(mBottomBarDelegate.getBottomBarHeight());
+            getFullscreenManager().addListener(mBottomBarDelegate);
         }
 
         @Override
@@ -433,6 +435,7 @@
                         finishAndClose(false);
                     }
                 });
+        getFullscreenManager().setBottomControlsHeight(mBottomBarDelegate.getBottomBarHeight());
 
         mCustomTabContentHandler = new CustomTabContentHandler() {
             @Override
@@ -689,7 +692,9 @@
         return new CustomTabAppMenuPropertiesDelegate(this, mIntentDataProvider.getMenuTitles(),
                 mIntentDataProvider.shouldShowShareMenuItem(),
                 mIntentDataProvider.isOpenedByChrome(),
-                mIntentDataProvider.isMediaViewer());
+                mIntentDataProvider.isMediaViewer(),
+                mIntentDataProvider.shouldShowStarButton(),
+                mIntentDataProvider.shouldShowDownloadButton());
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabAppMenuPropertiesDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabAppMenuPropertiesDelegate.java
index e264a259..706fbcf 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabAppMenuPropertiesDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabAppMenuPropertiesDelegate.java
@@ -35,6 +35,8 @@
 
     private final boolean mShowShare;
     private final boolean mIsMediaViewer;
+    private final boolean mShowStar;
+    private final boolean mShowDownload;
 
     private final List<String> mMenuEntries;
     private final Map<MenuItem, Integer> mItemToIndexMap = new HashMap<MenuItem, Integer>();
@@ -47,11 +49,13 @@
      */
     public CustomTabAppMenuPropertiesDelegate(final ChromeActivity activity,
             List<String> menuEntries, boolean showShare, final boolean isOpenedByChrome,
-            final boolean isMediaViewer) {
+            final boolean isMediaViewer, boolean showStar, boolean showDownload) {
         super(activity);
         mMenuEntries = menuEntries;
         mShowShare = showShare;
         mIsMediaViewer = isMediaViewer;
+        mShowStar = showStar;
+        mShowDownload = showDownload;
 
         mDefaultBrowserFetcher = new AsyncTask<Void, Void, String>() {
             @Override
@@ -123,7 +127,8 @@
                 }
                 updateBookmarkMenuItem(bookmarkItem, currentTab);
             }
-
+            bookmarkItem.setVisible(mShowStar);
+            downloadItem.setVisible(mShowDownload);
             if (!FirstRunStatus.getFirstRunFlowComplete()) {
                 openInChromeItem.setVisible(false);
                 bookmarkItem.setVisible(false);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabBottomBarDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabBottomBarDelegate.java
index e1df0422..3332351 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabBottomBarDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabBottomBarDelegate.java
@@ -25,6 +25,7 @@
 import org.chromium.base.metrics.CachedMetrics;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeActivity;
+import org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager.FullscreenListener;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.ui.interpolators.BakedBezierInterpolator;
 
@@ -33,7 +34,7 @@
 /**
  * Delegate that manages bottom bar area inside of {@link CustomTabActivity}.
  */
-class CustomTabBottomBarDelegate {
+class CustomTabBottomBarDelegate implements FullscreenListener {
     private static final String TAG = "CustomTab";
     private static final CachedMetrics.ActionEvent REMOTE_VIEWS_SHOWN =
             new CachedMetrics.ActionEvent("CustomTabsRemoteViewsShown");
@@ -138,12 +139,22 @@
     }
 
     /**
+     * @return The height of the bottom bar, excluding its top shadow.
+     */
+    public int getBottomBarHeight() {
+        if (!mDataProvider.shouldShowBottomBar() || mBottomBarView == null
+                || mBottomBarView.getChildCount() < 2) {
+            return 0;
+        }
+        return mBottomBarView.getChildAt(1).getHeight();
+    }
+
+    /**
      * Gets the {@link ViewGroup} of the bottom bar. If it has not been inflated, inflate it first.
      */
     private ViewGroup getBottomBarView() {
         if (mBottomBarView == null) {
             ViewStub bottomBarStub = ((ViewStub) mActivity.findViewById(R.id.bottombar_stub));
-            bottomBarStub.setLayoutResource(R.layout.custom_tabs_bottombar);
             mBottomBarView = (ViewGroup) bottomBarStub.inflate();
         }
         return mBottomBarView;
@@ -199,4 +210,17 @@
             Log.e(TAG, "CanceledException when sending pending intent.");
         }
     }
+
+    // FullscreenListener methods
+    @Override
+    public void onControlsOffsetChanged(float topOffset, float bottomOffset,
+            boolean needsAnimate) {
+        if (mBottomBarView != null) mBottomBarView.setTranslationY(bottomOffset);
+    }
+
+    @Override
+    public void onContentOffsetChanged(float offset) { }
+
+    @Override
+    public void onToggleOverlayVideoMode(boolean enabled) { }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java
index d262fd9..4e474fa5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java
@@ -66,6 +66,14 @@
     public static final String EXTRA_INITIAL_BACKGROUND_COLOR =
             "org.chromium.chrome.browser.customtabs.EXTRA_INITIAL_BACKGROUND_COLOR";
 
+    /** Extra that enables the client to disable the star button in menu. */
+    public static final String EXTRA_DISABLE_STAR_BUTTON =
+            "org.chromium.chrome.browser.customtabs.EXTRA_DISABLE_STAR_BUTTON";
+
+    /** Extra that enables the client to disable the download button in menu. */
+    public static final String EXTRA_DISABLE_DOWNLOAD_BUTTON =
+            "org.chromium.chrome.browser.customtabs.EXTRA_DISABLE_DOWNLOAD_BUTTON";
+
     //TODO(yusufo): Move this to CustomTabsIntent.
     /** Signals custom tabs to favor sending initial urls to external handler apps if possible. */
     public static final String EXTRA_SEND_TO_EXTERNAL_DEFAULT_HANDLER =
@@ -87,6 +95,8 @@
     private final boolean mIsMediaViewer;
     private final boolean mIsInfoPage;
     private final int mInitialBackgroundColor;
+    private final boolean mDisableStar;
+    private final boolean mDisableDownload;
 
     private int mToolbarColor;
     private int mBottomBarColor;
@@ -169,6 +179,9 @@
                 && IntentUtils.safeGetBooleanExtra(intent, EXTRA_IS_MEDIA_VIEWER, false);
         mIsInfoPage = mIsTrustedIntent
                 && IntentUtils.safeGetBooleanExtra(intent, EXTRA_IS_INFO_PAGE, false);
+        mDisableStar = IntentUtils.safeGetBooleanExtra(intent, EXTRA_DISABLE_STAR_BUTTON, false);
+        mDisableDownload = IntentUtils.safeGetBooleanExtra(intent, EXTRA_DISABLE_DOWNLOAD_BUTTON,
+                false);
     }
 
     /**
@@ -484,4 +497,18 @@
     int getInitialBackgroundColor() {
         return mInitialBackgroundColor;
     }
+
+    /**
+     * @return Whether there should be a star button in the menu.
+     */
+    boolean shouldShowStarButton() {
+        return !mDisableStar;
+    }
+
+    /**
+     * @return Whether there should be a download button in the menu.
+     */
+    boolean shouldShowDownloadButton() {
+        return !mDisableDownload;
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/ChromeFullscreenManager.java b/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/ChromeFullscreenManager.java
index 518d9d44..94e1e69 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/ChromeFullscreenManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/ChromeFullscreenManager.java
@@ -83,11 +83,13 @@
         public void onContentOffsetChanged(float offset);
 
         /**
-         * Called whenever the content's visible offset changes.
-         * @param offset The new offset of the visible content from the top of the screen.
+         * Called whenever the controls' offset changes.
+         * @param topOffset    The new value of the offset from the top of the top control.
+         * @param bottomOffset The new value of the offset from the top of the bottom control.
          * @param needsAnimate Whether the caller is driving an animation with further updates.
          */
-        public void onVisibleContentOffsetChanged(float offset, boolean needsAnimate);
+        public void onControlsOffsetChanged(float topOffset, float bottomOffset,
+                boolean needsAnimate);
 
         /**
          * Called when a ContentVideoView is created/destroyed.
@@ -312,6 +314,13 @@
         return getBrowserControlHiddenRatio() > 0;
     }
 
+    /**
+     * Sets the height of the bottom controls.
+     */
+    public void setBottomControlsHeight(int bottomControlsHeight) {
+        mBottomControlContainerHeight = bottomControlsHeight;
+    }
+
     @Override
     public int getTopControlsHeight() {
         return mTopControlContainerHeight;
@@ -462,11 +471,8 @@
             // scrolling.
             boolean needsAnimate = shouldShowAndroidControls();
             for (int i = 0; i < mListeners.size(); i++) {
-                // Since, in the case of bottom controls, the view is never translated, we don't
-                // need to change the information passed into this method.
-                // getTopVisibleContentOffset will return 0 which is the expected result.
-                mListeners.get(i).onVisibleContentOffsetChanged(
-                        getTopVisibleContentOffset(), needsAnimate);
+                mListeners.get(i).onControlsOffsetChanged(
+                        getTopControlOffset(), getBottomControlOffset(), needsAnimate);
             }
         }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsNavigationDelegateImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsNavigationDelegateImpl.java
index 40fc5277..4db9f8b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsNavigationDelegateImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsNavigationDelegateImpl.java
@@ -16,6 +16,7 @@
 import org.chromium.chrome.browser.ntp.snippets.SnippetArticle;
 import org.chromium.chrome.browser.offlinepages.OfflinePageBridge;
 import org.chromium.chrome.browser.offlinepages.OfflinePageUtils;
+import org.chromium.chrome.browser.offlinepages.downloads.OfflinePageNotificationBridge;
 import org.chromium.chrome.browser.preferences.PrefServiceBridge;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.tab.Tab;
@@ -186,6 +187,7 @@
     }
 
     private void saveUrlForOffline(String url) {
+        OfflinePageNotificationBridge.showDownloadingToast(mActivity);
         OfflinePageBridge.getForProfile(mProfile).savePageLater(
                 url, "ntp_suggestions", true /* userRequested */);
     }
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 14643a02..9dac7b19 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
@@ -1691,11 +1691,11 @@
                     new TabContextMenuPopulator(
                             mDelegateFactory.createContextMenuPopulator(this), this));
 
-            final ViewGroup bottomContainer = (ViewGroup) getActivity()
-                    .findViewById(R.id.bottom_container);
             // In the case where restoring a Tab or showing a prerendered one we already have a
             // valid infobar container, no need to recreate one.
             if (mInfoBarContainer == null) {
+                ViewGroup bottomContainer = (ViewGroup) getActivity()
+                        .findViewById(R.id.bottom_container);
                 // The InfoBarContainer needs to be created after the ContentView has been natively
                 // initialized.
                 mInfoBarContainer = new InfoBarContainer(mThemedApplicationContext, bottomContainer,
@@ -2821,6 +2821,15 @@
     }
 
     /**
+     * Sets the TabRedirectHandler for the tab.
+     *
+     * @param tabRedirectHandler the TabRedirectHandler
+     */
+    public void setTabRedirectHandler(TabRedirectHandler tabRedirectHandler) {
+        mTabRedirectHandler = tabRedirectHandler;
+    }
+
+    /**
      * @return the AppBannerManager.
      */
     public AppBannerManager getAppBannerManager() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabContextMenuItemDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabContextMenuItemDelegate.java
index f61ce4b..0d26479 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabContextMenuItemDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabContextMenuItemDelegate.java
@@ -15,7 +15,6 @@
 import org.chromium.chrome.browser.contextmenu.ContextMenuItemDelegate;
 import org.chromium.chrome.browser.multiwindow.MultiWindowUtils;
 import org.chromium.chrome.browser.net.spdyproxy.DataReductionProxySettings;
-import org.chromium.chrome.browser.offlinepages.OfflinePageBridge;
 import org.chromium.chrome.browser.preferences.PrefServiceBridge;
 import org.chromium.chrome.browser.tabmodel.TabModel.TabLaunchType;
 import org.chromium.chrome.browser.tabmodel.document.TabDelegate;
@@ -232,12 +231,6 @@
         }
     }
 
-    @Override
-    public void onSavePageLater(String linkUrl) {
-        OfflinePageBridge.getForProfile(mTab.getProfile())
-                .savePageLater(linkUrl, "async_loading", true /* userRequested */);
-    }
-
     /**
      * Checks if spdy proxy is enabled for input url.
      * @param url Input url to check for spdy setting.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellImpl.java
index 905b8f8..5ad5b770 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellImpl.java
@@ -27,6 +27,7 @@
 import org.chromium.chrome.browser.ChromeVersionInfo;
 import org.chromium.chrome.browser.WebContentsFactory;
 import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.chrome.browser.tab.TabRedirectHandler;
 import org.chromium.content.browser.ContentView;
 import org.chromium.content.browser.ContentViewCore;
 import org.chromium.content_public.browser.WebContents;
@@ -81,6 +82,8 @@
 
     private boolean mReprojectedRendering;
 
+    private TabRedirectHandler mNonVrTabRedirectHandler;
+
     public VrShellImpl(Activity activity) {
         super(activity);
         mActivity = activity;
@@ -123,6 +126,15 @@
         mContentCVC = mTab.getContentViewCore();
         mContentVrWindowAndroid = new VrWindowAndroid(mActivity, mContentVirtualDisplay);
 
+        // Make sure we are not redirecting to another app, i.e. out of VR mode.
+        mNonVrTabRedirectHandler = mTab.getTabRedirectHandler();
+        mTab.setTabRedirectHandler(new TabRedirectHandler(mActivity) {
+            @Override
+            public boolean shouldStayInChrome(boolean hasExternalProtocol) {
+                return true;
+            }
+        });
+
         mUiVrWindowAndroid = new VrWindowAndroid(mActivity, mUiVirtualDisplay);
         mUiContents = WebContentsFactory.createWebContents(true, false);
         mUiCVC = new ContentViewCore(mActivity, ChromeVersionInfo.getProductVersion());
@@ -251,6 +263,7 @@
             nativeDestroy(mNativeVrShell);
             mNativeVrShell = 0;
         }
+        mTab.setTabRedirectHandler(mNonVrTabRedirectHandler);
         mTab.updateWindowAndroid(mOriginalWindowAndroid);
         mContentCVC.onSizeChanged(mContentCVC.getContainerView().getWidth(),
                 mContentCVC.getContainerView().getHeight(), 0, 0);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/fullscreen/FullscreenManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/fullscreen/FullscreenManagerTest.java
index 448fda67..ba1d73ba 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/fullscreen/FullscreenManagerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/fullscreen/FullscreenManagerTest.java
@@ -420,8 +420,9 @@
 
         fullscreenManager.addListener(new FullscreenListener() {
             @Override
-            public void onVisibleContentOffsetChanged(float offset, boolean needsAnimate) {
-                if (offset != initialVisibleContentOffset) {
+            public void onControlsOffsetChanged(float topOffset, float bottomOffset,
+                    boolean needsAnimate) {
+                if (fullscreenManager.getTopVisibleContentOffset() != initialVisibleContentOffset) {
                     contentMovedCallback.notifyCalled();
                     fullscreenManager.removeListener(this);
                 }
diff --git a/chrome/browser/chromeos/display/touch_calibrator/touch_calibrator_view.cc b/chrome/browser/chromeos/display/touch_calibrator/touch_calibrator_view.cc
index 32c57a3..5f6daed 100644
--- a/chrome/browser/chromeos/display/touch_calibrator/touch_calibrator_view.cc
+++ b/chrome/browser/chromeos/display/touch_calibrator/touch_calibrator_view.cc
@@ -32,7 +32,6 @@
 constexpr int kPointMoveDurationLongInMs = 500;
 
 const SkColor kExitLabelColor = SkColorSetARGBInline(255, 96, 96, 96);
-const SkColor kExitLabelShadowColor = SkColorSetARGBInline(255, 11, 11, 11);
 constexpr int kExitLabelWidth = 300;
 constexpr int kExitLabelHeight = 20;
 
@@ -414,10 +413,9 @@
   exit_label_->SetBounds((display_.bounds().width() - kExitLabelWidth) / 2,
                          display_.bounds().height() * 3.f / 4, kExitLabelWidth,
                          kExitLabelHeight);
+  exit_label_->SetAutoColorReadabilityEnabled(false);
   exit_label_->SetEnabledColor(kExitLabelColor);
   exit_label_->SetHorizontalAlignment(gfx::ALIGN_CENTER);
-  exit_label_->SetShadows(gfx::ShadowValues(
-      1, gfx::ShadowValue(gfx::Vector2d(1, 1), 1, kExitLabelShadowColor)));
   exit_label_->SetSubpixelRenderingEnabled(false);
   exit_label_->SetVisible(false);
 
diff --git a/chrome/browser/component_updater/origin_trials_component_installer.cc b/chrome/browser/component_updater/origin_trials_component_installer.cc
index 08712ea..9378dcf 100644
--- a/chrome/browser/component_updater/origin_trials_component_installer.cc
+++ b/chrome/browser/component_updater/origin_trials_component_installer.cc
@@ -44,11 +44,11 @@
 static const char kManifestDisabledFeaturesPath[] =
     "origin-trials.disabled-features";
 
-// Extension id is kfoklmclfodeliojeaekpoflbkkhojea
-const uint8_t kSha256Hash[] = {0xa5, 0xea, 0xbc, 0x2b, 0x5e, 0x34, 0xb8, 0xe9,
-                               0x40, 0x4a, 0xfe, 0x5b, 0x1a, 0xa7, 0xe9, 0x40,
-                               0xa8, 0xc5, 0xef, 0xa1, 0x9e, 0x20, 0x5a, 0x39,
-                               0x73, 0x98, 0x98, 0x0f, 0x7a, 0x76, 0x62, 0xfa};
+// Extension id is llkgjffcdpffmhiakmfcdcblohccpfmo
+const uint8_t kSha256Hash[] = {0xbb, 0xa6, 0x95, 0x52, 0x3f, 0x55, 0xc7, 0x80,
+                               0xac, 0x52, 0x32, 0x1b, 0xe7, 0x22, 0xf5, 0xce,
+                               0x6a, 0xfd, 0x9c, 0x9e, 0xa9, 0x2a, 0x0b, 0x50,
+                               0x60, 0x2b, 0x7f, 0x6c, 0x64, 0x80, 0x09, 0x04};
 
 }  // namespace
 
diff --git a/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_connection_manager.cc b/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_connection_manager.cc
index 9d2923b..b6dd2d3 100644
--- a/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_connection_manager.cc
+++ b/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_connection_manager.cc
@@ -19,6 +19,9 @@
 
 namespace extensions {
 namespace {
+
+const char kEasyUnlockFeatureName[] = "easy_unlock";
+
 api::easy_unlock_private::ConnectionStatus ToApiConnectionStatus(
     Connection::Status status) {
   switch (status) {
@@ -31,6 +34,7 @@
   }
   return api::easy_unlock_private::CONNECTION_STATUS_NONE;
 }
+
 }  // namespace
 
 EasyUnlockPrivateConnectionManager::EasyUnlockPrivateConnectionManager(
@@ -98,7 +102,8 @@
     const std::string& payload) {
   Connection* connection = GetConnection(extension->id(), connection_id);
   if (connection && connection->IsConnected()) {
-    connection->SendMessage(base::MakeUnique<WireMessage>(payload));
+    connection->SendMessage(base::MakeUnique<WireMessage>(
+        payload, std::string(kEasyUnlockFeatureName)));
     return true;
   }
   return false;
@@ -123,6 +128,11 @@
 void EasyUnlockPrivateConnectionManager::OnMessageReceived(
     const Connection& connection,
     const WireMessage& message) {
+  if (message.feature() != std::string(kEasyUnlockFeatureName)) {
+    // Only process messages received as part of EasyUnlock.
+    return;
+  }
+
   std::string event_name = api::easy_unlock_private::OnDataReceived::kEventName;
   events::HistogramValue histogram_value =
       events::EASY_UNLOCK_PRIVATE_ON_DATA_RECEIVED;
@@ -137,6 +147,11 @@
     const Connection& connection,
     const WireMessage& message,
     bool success) {
+  if (message.feature() != std::string(kEasyUnlockFeatureName)) {
+    // Only process messages sent as part of EasyUnlock.
+    return;
+  }
+
   std::string event_name =
       api::easy_unlock_private::OnSendCompleted::kEventName;
   events::HistogramValue histogram_value =
diff --git a/chrome/browser/metrics/perf/cpu_identity.cc b/chrome/browser/metrics/perf/cpu_identity.cc
index 24330011..db0e1d2 100644
--- a/chrome/browser/metrics/perf/cpu_identity.cc
+++ b/chrome/browser/metrics/perf/cpu_identity.cc
@@ -47,8 +47,10 @@
   {"06_46", "Haswell"},
   {"06_47", "Broadwell"},  // Broadwell-H
   {"06_4C", "Airmont"},    // Braswell
+  {"06_4D", "Silvermont"}, // Avoton/Rangely
   {"06_4E", "Skylake"},
   {"06_56", "Broadwell"},  // Broadwell-DE
+  {"06_5E", "Skylake"},
   {"0F_03", "Prescott"},
   {"0F_04", "Prescott"},
   {"0F_06", "Presler"},
diff --git a/chrome/browser/metrics/perf/perf_provider_chromeos.cc b/chrome/browser/metrics/perf/perf_provider_chromeos.cc
index f7b32db..fa4e484 100644
--- a/chrome/browser/metrics/perf/perf_provider_chromeos.cc
+++ b/chrome/browser/metrics/perf/perf_provider_chromeos.cc
@@ -121,6 +121,11 @@
 const char kPerfRecordLBRCmd[] =
   "perf record -a -e r20c4 -b -c 200011";
 
+// Silvermont, Airmont, Goldmont don't have a branches taken event. Therefore,
+// we sample on the branches retired event.
+const char kPerfRecordLBRCmdAtom[] =
+  "perf record -a -e rc4 -b -c 300001";
+
 const char kPerfRecordInstructionTLBMissesCmd[] =
   "perf record -a -e iTLB-misses -c 2003";
 
@@ -142,18 +147,26 @@
   if (intel_uarch == "IvyBridge" ||
       intel_uarch == "Haswell" ||
       intel_uarch == "Broadwell") {
-    cmds.push_back(WeightAndValue(60.0, kPerfRecordCyclesCmd));
+    cmds.push_back(WeightAndValue(50.0, kPerfRecordCyclesCmd));
     cmds.push_back(WeightAndValue(20.0, kPerfRecordCallgraphCmd));
-    cmds.push_back(WeightAndValue(5.0, kPerfRecordLBRCmd));
+    cmds.push_back(WeightAndValue(15.0, kPerfRecordLBRCmd));
     cmds.push_back(WeightAndValue(5.0, kPerfRecordInstructionTLBMissesCmd));
     cmds.push_back(WeightAndValue(5.0, kPerfRecordDataTLBMissesCmd));
     cmds.push_back(WeightAndValue(5.0, kPerfStatMemoryBandwidthCmd));
     return cmds;
   }
-  if (intel_uarch == "SandyBridge") {
-    cmds.push_back(WeightAndValue(65.0, kPerfRecordCyclesCmd));
+  if (intel_uarch == "SandyBridge" || intel_uarch == "Skylake") {
+    cmds.push_back(WeightAndValue(55.0, kPerfRecordCyclesCmd));
     cmds.push_back(WeightAndValue(20.0, kPerfRecordCallgraphCmd));
-    cmds.push_back(WeightAndValue(5.0, kPerfRecordLBRCmd));
+    cmds.push_back(WeightAndValue(15.0, kPerfRecordLBRCmd));
+    cmds.push_back(WeightAndValue(5.0, kPerfRecordInstructionTLBMissesCmd));
+    cmds.push_back(WeightAndValue(5.0, kPerfRecordDataTLBMissesCmd));
+    return cmds;
+  }
+  if (intel_uarch == "Silvermont" || intel_uarch == "Airmont") {
+    cmds.push_back(WeightAndValue(55.0, kPerfRecordCyclesCmd));
+    cmds.push_back(WeightAndValue(20.0, kPerfRecordCallgraphCmd));
+    cmds.push_back(WeightAndValue(15.0, kPerfRecordLBRCmdAtom));
     cmds.push_back(WeightAndValue(5.0, kPerfRecordInstructionTLBMissesCmd));
     cmds.push_back(WeightAndValue(5.0, kPerfRecordDataTLBMissesCmd));
     return cmds;
diff --git a/chrome/browser/payments/payment_request_web_contents_manager_browsertest.cc b/chrome/browser/payments/payment_request_web_contents_manager_browsertest.cc
deleted file mode 100644
index ccf23dd..0000000
--- a/chrome/browser/payments/payment_request_web_contents_manager_browsertest.cc
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <vector>
-
-#include "base/command_line.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chrome/test/base/in_process_browser_test.h"
-#include "chrome/test/base/ui_test_utils.h"
-#include "components/payments/payment_request.h"
-#include "components/payments/payment_request_web_contents_manager.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/common/content_switches.h"
-#include "net/test/embedded_test_server/embedded_test_server.h"
-#include "url/gurl.h"
-
-namespace payments {
-
-class PaymentRequestWebContentsManagerBrowserTest
-    : public InProcessBrowserTest {
- public:
-  PaymentRequestWebContentsManagerBrowserTest() {}
-  ~PaymentRequestWebContentsManagerBrowserTest() override {}
-
-  void SetUpCommandLine(base::CommandLine* command_line) override {
-    InProcessBrowserTest::SetUpCommandLine(command_line);
-    command_line->AppendSwitch(
-        switches::kEnableExperimentalWebPlatformFeatures);
-  }
-
-  void SetUpOnMainThread() override {
-    https_server_.reset(
-        new net::EmbeddedTestServer(net::EmbeddedTestServer::TYPE_HTTPS));
-    ASSERT_TRUE(https_server_->InitializeAndListen());
-    https_server_->ServeFilesFromSourceDirectory("chrome/test/data/payments");
-    https_server_->StartAcceptingConnections();
-  }
-
-  // Convenience method to get a list of PaymentRequest associated with
-  // |web_contents|.
-  const std::vector<PaymentRequest*> GetPaymentRequests(
-      content::WebContents* web_contents) {
-    PaymentRequestWebContentsManager* manager =
-        PaymentRequestWebContentsManager::GetOrCreateForWebContents(
-            web_contents);
-    if (!manager)
-      return std::vector<PaymentRequest*>();
-
-    std::vector<PaymentRequest*> payment_requests_ptrs;
-    for (const auto& p : manager->payment_requests_) {
-      payment_requests_ptrs.push_back(p.first);
-    }
-    return payment_requests_ptrs;
-  }
-
-  std::unique_ptr<net::EmbeddedTestServer> https_server_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(PaymentRequestWebContentsManagerBrowserTest);
-};
-
-IN_PROC_BROWSER_TEST_F(PaymentRequestWebContentsManagerBrowserTest,
-                       MultiplePaymentRequests) {
-  GURL url = https_server_->GetURL("/payment_request_multiple_requests.html");
-  ui_test_utils::NavigateToURL(browser(), url);
-
-  const std::vector<PaymentRequest*> payment_requests =
-      GetPaymentRequests(browser()->tab_strip_model()->GetActiveWebContents());
-  EXPECT_EQ(5U, payment_requests.size());
-}
-
-}  // namespace payments
diff --git a/chrome/browser/prefs/preferences_connection_manager.cc b/chrome/browser/prefs/preferences_connection_manager.cc
index 16627130..5eb57be 100644
--- a/chrome/browser/prefs/preferences_connection_manager.cc
+++ b/chrome/browser/prefs/preferences_connection_manager.cc
@@ -47,16 +47,17 @@
     mojo::StrongBindingPtr<prefs::mojom::PreferencesManager> binding) {
   if (!binding)
     return;
-  for (auto it = std::begin(bindings_); it != std::end(bindings_); ++it) {
+  for (auto it = manager_bindings_.begin(); it != manager_bindings_.end();
+       ++it) {
     if (it->get() == binding.get()) {
-      bindings_.erase(it);
+      manager_bindings_.erase(it);
       return;
     }
   }
 }
 
 void PreferencesConnectionManager::OnProfileDestroyed() {
-  for (auto& it : bindings_) {
+  for (auto& it : manager_bindings_) {
     // Shutdown any PreferenceManager that is still alive.
     if (it)
       it->Close();
@@ -66,8 +67,8 @@
 }
 
 void PreferencesConnectionManager::Create(
-    const service_manager::Identity& remote_identity,
-    prefs::mojom::PreferencesManagerRequest request) {
+    prefs::mojom::PreferencesObserverPtr observer,
+    prefs::mojom::PreferencesManagerRequest manager) {
   // Certain tests have no profiles to connect to, and static initializers
   // which block the creation of test profiles.
   if (!g_browser_process->profile_manager()->GetNumberOfProfiles())
@@ -75,13 +76,20 @@
 
   Profile* profile = ProfileManager::GetActiveUserProfile();
   mojo::StrongBindingPtr<prefs::mojom::PreferencesManager> binding =
-      mojo::MakeStrongBinding(base::MakeUnique<PreferencesManager>(profile),
-                              std::move(request));
+      mojo::MakeStrongBinding(
+          base::MakeUnique<PreferencesManager>(std::move(observer), profile),
+          std::move(manager));
   // Copying the base::WeakPtr for future deletion.
   binding->set_connection_error_handler(
       base::Bind(&PreferencesConnectionManager::OnConnectionError,
                  base::Unretained(this), binding));
-  bindings_.push_back(std::move(binding));
+  manager_bindings_.push_back(std::move(binding));
+}
+
+void PreferencesConnectionManager::Create(
+    const service_manager::Identity& remote_identity,
+    prefs::mojom::PreferencesFactoryRequest request) {
+  factory_bindings_.AddBinding(this, std::move(request));
 }
 
 void PreferencesConnectionManager::OnStart() {
@@ -101,6 +109,6 @@
 bool PreferencesConnectionManager::OnConnect(
     const service_manager::ServiceInfo& remote_info,
     service_manager::InterfaceRegistry* registry) {
-  registry->AddInterface<prefs::mojom::PreferencesManager>(this);
+  registry->AddInterface<prefs::mojom::PreferencesFactory>(this);
   return true;
 }
diff --git a/chrome/browser/prefs/preferences_connection_manager.h b/chrome/browser/prefs/preferences_connection_manager.h
index 0f9e8df..ebc85a27 100644
--- a/chrome/browser/prefs/preferences_connection_manager.h
+++ b/chrome/browser/prefs/preferences_connection_manager.h
@@ -10,6 +10,7 @@
 #include "base/compiler_specific.h"
 #include "base/macros.h"
 #include "components/keyed_service/core/keyed_service_shutdown_notifier.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
 #include "services/preferences/public/interfaces/preferences.mojom.h"
 #include "services/service_manager/public/cpp/interface_factory.h"
@@ -23,8 +24,9 @@
 // TODO(jonross): Observe profile switching and update PreferenceManager
 // connections.
 class PreferencesConnectionManager
-    : public NON_EXPORTED_BASE(
-          service_manager::InterfaceFactory<prefs::mojom::PreferencesManager>),
+    : public NON_EXPORTED_BASE(prefs::mojom::PreferencesFactory),
+      public NON_EXPORTED_BASE(
+          service_manager::InterfaceFactory<prefs::mojom::PreferencesFactory>),
       public NON_EXPORTED_BASE(service_manager::Service) {
  public:
   PreferencesConnectionManager();
@@ -39,18 +41,24 @@
   // the active PrefService is being destroyed.
   void OnProfileDestroyed();
 
-  // service_manager::InterfaceFactory<PreferencesManager>:
+  // prefs::mojom::PreferencesFactory:
+  void Create(prefs::mojom::PreferencesObserverPtr observer,
+              prefs::mojom::PreferencesManagerRequest manager) override;
+
+  // service_manager::InterfaceFactory<PreferencesFactory>:
   void Create(const service_manager::Identity& remote_identity,
-              prefs::mojom::PreferencesManagerRequest request) override;
+              prefs::mojom::PreferencesFactoryRequest request) override;
 
   // service_manager::Service:
   void OnStart() override;
   bool OnConnect(const service_manager::ServiceInfo& remote_info,
                  service_manager::InterfaceRegistry* registry) override;
 
+  mojo::BindingSet<prefs::mojom::PreferencesFactory> factory_bindings_;
+
   // Bindings that automatically cleanup during connection errors.
   std::vector<mojo::StrongBindingPtr<prefs::mojom::PreferencesManager>>
-      bindings_;
+      manager_bindings_;
 
   // Observes shutdown, when PrefService is being destroyed.
   std::unique_ptr<KeyedServiceShutdownNotifier::Subscription>
diff --git a/chrome/browser/prefs/preferences_manager.cc b/chrome/browser/prefs/preferences_manager.cc
index 13eb402d..caf40d2 100644
--- a/chrome/browser/prefs/preferences_manager.cc
+++ b/chrome/browser/prefs/preferences_manager.cc
@@ -12,10 +12,14 @@
 #include "components/prefs/pref_change_registrar.h"
 #include "components/prefs/pref_service.h"
 
-PreferencesManager::PreferencesManager(Profile* profile)
+PreferencesManager::PreferencesManager(
+    prefs::mojom::PreferencesObserverPtr client,
+    Profile* profile)
     : preferences_change_registrar_(new PrefChangeRegistrar),
+      client_(std::move(client)),
       setting_preferences_(false) {
   DCHECK(profile);
+  DCHECK(client_.is_bound());
   service_ = profile->GetPrefs();
   preferences_change_registrar_->Init(service_);
 }
@@ -33,18 +37,8 @@
   client_->OnPreferencesChanged(std::move(dictionary));
 }
 
-void PreferencesManager::AddObserver(
-    prefs::mojom::PreferencesObserverPtr client) {
-  // TODO(jonross): once service_manager::Connector supports enforcing two-way
-  // binding at connection time, update PreferencesManager to use that approach.
-  // After which enforcing bind checks will not be needed (crbug.com/674140)
-  client_ = std::move(client);
-}
-
 void PreferencesManager::SetPreferences(
     std::unique_ptr<base::DictionaryValue> preferences) {
-  if (!client_.is_bound())
-    return;
   DCHECK(!setting_preferences_);
   // We ignore preference changes caused by us.
   base::AutoReset<bool> setting_preferences(&setting_preferences_, true);
@@ -65,8 +59,6 @@
 
 void PreferencesManager::Subscribe(
     const std::vector<std::string>& preferences) {
-  if (!client_.is_bound())
-    return;
   std::unique_ptr<base::DictionaryValue> dictionary =
       base::MakeUnique<base::DictionaryValue>();
   for (auto& it : preferences) {
diff --git a/chrome/browser/prefs/preferences_manager.h b/chrome/browser/prefs/preferences_manager.h
index 9ffc67a..8f2272a 100644
--- a/chrome/browser/prefs/preferences_manager.h
+++ b/chrome/browser/prefs/preferences_manager.h
@@ -25,7 +25,8 @@
 // the requested preferences, notifying the client of all changes.
 class PreferencesManager : public prefs::mojom::PreferencesManager {
  public:
-  explicit PreferencesManager(Profile* profile);
+  PreferencesManager(prefs::mojom::PreferencesObserverPtr client,
+                     Profile* profile);
   ~PreferencesManager() override;
 
  private:
@@ -35,7 +36,6 @@
   void PreferenceChanged(const std::string& preference_name);
 
   // mojom::PreferencesManager:
-  void AddObserver(prefs::mojom::PreferencesObserverPtr client) override;
   void SetPreferences(
       std::unique_ptr<base::DictionaryValue> preferences) override;
   void Subscribe(const std::vector<std::string>& preferences) override;
diff --git a/chrome/browser/prefs/preferences_manager_unittest.cc b/chrome/browser/prefs/preferences_manager_unittest.cc
index f722949..73302cc 100644
--- a/chrome/browser/prefs/preferences_manager_unittest.cc
+++ b/chrome/browser/prefs/preferences_manager_unittest.cc
@@ -162,9 +162,8 @@
   ASSERT_NE(nullptr, profile_->GetPrefs());
 
   observer_.reset(new TestPreferencesObserver(mojo::MakeRequest(&proxy_)));
-  manager_ = base::MakeUnique<PreferencesManager>(profile_);
+  manager_ = base::MakeUnique<PreferencesManager>(std::move(proxy_), profile_);
   ASSERT_TRUE(manager_->preferences_change_registrar_->IsEmpty());
-  manager_->AddObserver(std::move(proxy_));
 }
 
 void PreferencesManagerTest::TearDown() {
diff --git a/chrome/browser/prefs/preferences_manifest.json b/chrome/browser/prefs/preferences_manifest.json
index 37b790ad..0ce32ca 100644
--- a/chrome/browser/prefs/preferences_manifest.json
+++ b/chrome/browser/prefs/preferences_manifest.json
@@ -4,7 +4,7 @@
   "interface_provider_specs": {
     "service_manager:connector": {
       "provides": {
-        "preferences_manager": [ "prefs::mojom::PreferencesManager" ]
+        "preferences_manager": [ "prefs::mojom::PreferencesFactory" ]
       },
       "requires": {
       }
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/panel.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/panel.js
index acdf95a..ac9318b 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/panel.js
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/panel.js
@@ -705,6 +705,11 @@
     return;
   }
 
+  // Events don't propagate correctly because blur places focus on body.
+  if (Panel.mode_ == Panel.Mode.FULLSCREEN_TUTORIAL &&
+      !Panel.tutorial_.onKeyDown(event))
+    return;
+
   if (!Panel.activeMenu_)
     return;
 
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/tutorial.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/tutorial.js
index b72d3b2c..b829712 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/tutorial.js
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/tutorial.js
@@ -25,6 +25,7 @@
   this.page = sessionStorage['tutorial_page_pos'] !== undefined ?
       sessionStorage['tutorial_page_pos'] : 0;
 };
+
 /**
  * @param {Node} container
  * @private
@@ -117,6 +118,26 @@
 ];
 
 Tutorial.prototype = {
+  /**
+   * Handles key down events.
+   * @param {Event} evt
+   * @return {boolean}
+   */
+  onKeyDown: function(evt) {
+    if (document.activeElement &&
+        (document.activeElement.id == 'tutorial_previous' ||
+        document.activeElement.id == 'tutorial_next'))
+      return true;
+
+    if (evt.key == 'Enter')
+      this.nextPage();
+    else if (evt.key == 'Backspace')
+      this.previousPage();
+    else
+      return true;
+    return false;
+  },
+
   /** Open the last viewed page in the tutorial. */
   lastViewedPage: function() {
     this.page = sessionStorage['tutorial_page_pos'] !== undefined ?
diff --git a/chrome/browser/resources/chromeos/chromevox/strings/chromevox_strings.grd b/chrome/browser/resources/chromeos/chromevox/strings/chromevox_strings.grd
index 24b0a496..d306c82 100644
--- a/chrome/browser/resources/chromeos/chromevox/strings/chromevox_strings.grd
+++ b/chrome/browser/resources/chromeos/chromevox/strings/chromevox_strings.grd
@@ -2530,8 +2530,8 @@
       <message desc="Introductory text for the 'ChromeVox Next' tutorial" name="IDS_CHROMEVOX_TUTORIAL_WELCOME_TEXT">
         Are you using ChromeVox Next spoken feedback for the first time? This quick tutorial explains the essentials for getting started with ChromeVox Next.
       </message>
-      <message desc="Text that tells users to press the enter key to move to the next page in the tutorial" name="IDS_CHROMEVOX_TUTORIAL_ENTER_TO_ADVANCE">
-        To advance, press Enter.
+      <message desc="Text that tells users to press the enter key to move to the next page or backspace to move to the previous page in the tutorial" name="IDS_CHROMEVOX_TUTORIAL_ENTER_TO_ADVANCE">
+        To advance, press enter; to go back, press backspace.
       </message>
       <message desc="Heading that talks about turning ChromeVox on, off, and stopping it from speaking" name="IDS_CHROMEVOX_TUTORIAL_ON_OFF_HEADING">
         On, Off, and Stop
diff --git a/chrome/browser/resources/chromeos/quick_unlock/pin_keyboard.html b/chrome/browser/resources/chromeos/quick_unlock/pin_keyboard.html
index 64f6453..4b7642e7 100644
--- a/chrome/browser/resources/chromeos/quick_unlock/pin_keyboard.html
+++ b/chrome/browser/resources/chromeos/quick_unlock/pin_keyboard.html
@@ -32,6 +32,10 @@
 <dom-module id="pin-keyboard">
   <template>
     <style>
+      :host {
+        outline: none;
+      }
+
       #root {
         direction: ltr;
         display: flex;
diff --git a/chrome/browser/task_manager/providers/browser_process_task.cc b/chrome/browser/task_manager/providers/browser_process_task.cc
index cc6f606..d12a0e1 100644
--- a/chrome/browser/task_manager/providers/browser_process_task.cc
+++ b/chrome/browser/task_manager/providers/browser_process_task.cc
@@ -4,13 +4,9 @@
 
 #include "chrome/browser/task_manager/providers/browser_process_task.h"
 
-#include "base/command_line.h"
 #include "chrome/browser/task_manager/task_manager_observer.h"
-#include "chrome/common/chrome_switches.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/grit/theme_resources.h"
-#include "content/public/common/content_switches.h"
-#include "net/proxy/proxy_resolver_v8.h"
 #include "third_party/sqlite/sqlite3.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
@@ -32,13 +28,6 @@
   return g_default_icon;
 }
 
-bool ReportsV8Stats() {
-  const base::CommandLine* command_line =
-      base::CommandLine::ForCurrentProcess();
-  return !command_line->HasSwitch(switches::kWinHttpProxyResolver) &&
-      !command_line->HasSwitch(switches::kSingleProcess);
-}
-
 }  // namespace
 
 BrowserProcessTask::BrowserProcessTask()
@@ -46,10 +35,7 @@
            "Browser Process",
            GetDefaultIcon(),
            base::GetCurrentProcessHandle()),
-       allocated_v8_memory_(-1),
-       used_v8_memory_(-1),
-       used_sqlite_memory_(-1),
-       reports_v8_stats_(ReportsV8Stats()) {
+       used_sqlite_memory_(-1) {
 }
 
 BrowserProcessTask::~BrowserProcessTask() {
@@ -68,13 +54,6 @@
                                  int64_t refresh_flags) {
   Task::Refresh(update_interval, refresh_flags);
 
-  if (reports_v8_stats_ && (refresh_flags & REFRESH_TYPE_V8_MEMORY) != 0) {
-    allocated_v8_memory_ =
-        static_cast<int64_t>(net::ProxyResolverV8::GetTotalHeapSize());
-    used_v8_memory_ =
-        static_cast<int64_t>(net::ProxyResolverV8::GetUsedHeapSize());
-  }
-
   if ((refresh_flags & REFRESH_TYPE_SQLITE_MEMORY) != 0)
     used_sqlite_memory_ = static_cast<int64_t>(sqlite3_memory_used());
 }
@@ -91,12 +70,4 @@
   return used_sqlite_memory_;
 }
 
-int64_t BrowserProcessTask::GetV8MemoryAllocated() const {
-  return allocated_v8_memory_;
-}
-
-int64_t BrowserProcessTask::GetV8MemoryUsed() const {
-  return used_v8_memory_;
-}
-
 }  // namespace task_manager
diff --git a/chrome/browser/task_manager/providers/browser_process_task.h b/chrome/browser/task_manager/providers/browser_process_task.h
index 0d0653f..53ef16c7 100644
--- a/chrome/browser/task_manager/providers/browser_process_task.h
+++ b/chrome/browser/task_manager/providers/browser_process_task.h
@@ -26,14 +26,9 @@
   Type GetType() const override;
   int GetChildProcessUniqueID() const override;
   int64_t GetSqliteMemoryUsed() const override;
-  int64_t GetV8MemoryAllocated() const override;
-  int64_t GetV8MemoryUsed() const override;
 
  private:
-  int64_t allocated_v8_memory_;
-  int64_t used_v8_memory_;
   int64_t used_sqlite_memory_;
-  bool reports_v8_stats_;
 
   DISALLOW_COPY_AND_ASSIGN(BrowserProcessTask);
 };
diff --git a/chrome/browser/task_manager/sampling/task_group.cc b/chrome/browser/task_manager/sampling/task_group.cc
index a7a0d11..d7fab26 100644
--- a/chrome/browser/task_manager/sampling/task_group.cc
+++ b/chrome/browser/task_manager/sampling/task_group.cc
@@ -26,11 +26,12 @@
 const int kBackgroundRefreshTypesMask =
     REFRESH_TYPE_CPU | REFRESH_TYPE_MEMORY | REFRESH_TYPE_IDLE_WAKEUPS |
 #if defined(OS_WIN)
-    REFRESH_TYPE_START_TIME | REFRESH_TYPE_CPU_TIME |
+        REFRESH_TYPE_START_TIME | REFRESH_TYPE_CPU_TIME |
 #endif  // defined(OS_WIN)
 #if defined(OS_LINUX)
-    REFRESH_TYPE_FD_COUNT |
+        REFRESH_TYPE_FD_COUNT |
 #endif  // defined(OS_LINUX)
+        REFRESH_TYPE_NACL ||
     REFRESH_TYPE_PRIORITY;
 
 #if defined(OS_WIN)
@@ -176,7 +177,8 @@
   }
 #endif  // defined(OS_WIN)
 
-  // 4- Refresh the NACL debug stub port (if enabled).
+// 4- Refresh the NACL debug stub port (if enabled). This calls out to
+//    NaClBrowser on the browser's IO thread, completing asynchronously.
 #if !defined(DISABLE_NACL)
   if (TaskManagerObserver::IsResourceRefreshEnabled(REFRESH_TYPE_NACL,
                                                     refresh_flags) &&
@@ -255,14 +257,25 @@
 #endif  // defined(OS_WIN)
 }
 
-void TaskGroup::RefreshNaClDebugStubPort(int child_process_unique_id) {
 #if !defined(DISABLE_NACL)
+void TaskGroup::RefreshNaClDebugStubPort(int child_process_unique_id) {
   nacl::NaClBrowser* nacl_browser = nacl::NaClBrowser::GetInstance();
-  nacl_debug_stub_port_ =
-      nacl_browser->GetProcessGdbDebugStubPort(child_process_unique_id);
-#endif  // !defined(DISABLE_NACL)
+  content::BrowserThread::PostTaskAndReplyWithResult(
+      content::BrowserThread::IO, FROM_HERE,
+      base::Bind(&nacl::NaClBrowser::GetProcessGdbDebugStubPort,
+                 base::Unretained(nacl_browser), child_process_unique_id),
+      base::Bind(&TaskGroup::OnRefreshNaClDebugStubPortDone,
+                 weak_ptr_factory_.GetWeakPtr()));
 }
 
+void TaskGroup::OnRefreshNaClDebugStubPortDone(int nacl_debug_stub_port) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  nacl_debug_stub_port_ = nacl_debug_stub_port;
+  OnBackgroundRefreshTypeFinished(REFRESH_TYPE_NACL);
+}
+#endif  // !defined(DISABLE_NACL)
+
 void TaskGroup::OnCpuRefreshDone(double cpu_usage) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
diff --git a/chrome/browser/task_manager/sampling/task_group.h b/chrome/browser/task_manager/sampling/task_group.h
index 288c54f..7768367 100644
--- a/chrome/browser/task_manager/sampling/task_group.h
+++ b/chrome/browser/task_manager/sampling/task_group.h
@@ -107,8 +107,11 @@
 
   void RefreshWindowsHandles();
 
+#if !defined(DISABLE_NACL)
   // |child_process_unique_id| see Task::GetChildProcessUniqueID().
   void RefreshNaClDebugStubPort(int child_process_unique_id);
+  void OnRefreshNaClDebugStubPortDone(int port);
+#endif
 
   void OnCpuRefreshDone(double cpu_usage);
 
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 154b5cff..d535c11 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -3467,6 +3467,8 @@
   if (toolkit_views && (!is_mac || mac_views_browser)) {
     sources += [
       "views/find_bar_host_unittest_util_views.cc",
+      "views/payments/test_chrome_payment_request_delegate.cc",
+      "views/payments/test_chrome_payment_request_delegate.h",
       "views/toolbar/browser_action_test_util_views.cc",
     ]
     if (!is_mac) {
diff --git a/chrome/browser/ui/cocoa/extensions/browser_actions_container_view.h b/chrome/browser/ui/cocoa/extensions/browser_actions_container_view.h
index b26cfb3..2890c9a 100644
--- a/chrome/browser/ui/cocoa/extensions/browser_actions_container_view.h
+++ b/chrome/browser/ui/cocoa/extensions/browser_actions_container_view.h
@@ -49,12 +49,6 @@
   BROWSER_ACTIONS_INVALID_KEY_ACTION = 3,
 };
 
-class BrowserActionsContainerViewSizeDelegate {
- public:
-  virtual CGFloat GetMaxAllowedWidth() = 0;
-  virtual ~BrowserActionsContainerViewSizeDelegate() {}
-};
-
 // The view that encompasses the Browser Action buttons in the toolbar and
 // provides mechanisms for resizing.
 @interface BrowserActionsContainerView : NSView<NSAnimationDelegate> {
@@ -62,13 +56,8 @@
   // The frame encompasing the grippy used for resizing the container.
   NSRect grippyRect_;
 
-  // Used to cache the original position within the container that initiated the
-  // drag.
-  NSPoint initialDragPoint_;
-
-  // The maximum width the container could want; i.e., the width required to
-  // display all the icons.
-  CGFloat maxDesiredWidth_;
+  // Remember where in the grippy the drag began.
+  CGFloat dragOffset_;
 
   // Whether the container is currently being resized by the user.
   BOOL userIsResizing_;
@@ -83,15 +72,6 @@
   // app menu.
   BOOL isOverflow_;
 
-  // Whether the user is allowed to drag the grippy to the left. NO if all
-  // extensions are shown or the location bar has hit its minimum width (handled
-  // within toolbar_controller.mm).
-  BOOL canDragLeft_;
-
-  // Whether the user is allowed to drag the grippy to the right. NO if all
-  // extensions are hidden.
-  BOOL canDragRight_;
-
   // When the left grippy is pinned, resizing the window has no effect on its
   // position. This prevents it from overlapping with other elements as well
   // as letting the container expand when the window is going from super small
@@ -101,10 +81,6 @@
   // The nine-grid of the highlight to paint, if any.
   std::unique_ptr<ui::NinePartImageIds> highlight_;
 
-  // The size delegate, if any.
-  // Weak; delegate is responsible for adding/removing itself.
-  BrowserActionsContainerViewSizeDelegate* sizeDelegate_;
-
   base::scoped_nsobject<NSViewAnimation> resizeAnimation_;
 }
 
@@ -130,12 +106,10 @@
 // Stops any animation in progress.
 - (void)stopAnimation;
 
-@property(nonatomic) BOOL canDragLeft;
-@property(nonatomic) BOOL canDragRight;
+@property(nonatomic) CGFloat minWidth;
+@property(nonatomic) CGFloat maxWidth;
 @property(nonatomic) BOOL grippyPinned;
-@property(nonatomic) CGFloat maxDesiredWidth;
 @property(readonly, nonatomic) BOOL userIsResizing;
-@property(nonatomic) BrowserActionsContainerViewSizeDelegate* delegate;
 
 @end
 
diff --git a/chrome/browser/ui/cocoa/extensions/browser_actions_container_view.mm b/chrome/browser/ui/cocoa/extensions/browser_actions_container_view.mm
index 3bf1e04..251d337 100644
--- a/chrome/browser/ui/cocoa/extensions/browser_actions_container_view.mm
+++ b/chrome/browser/ui/cocoa/extensions/browser_actions_container_view.mm
@@ -32,26 +32,20 @@
 namespace {
 const CGFloat kAnimationDuration = 0.2;
 const CGFloat kGrippyWidth = 3.0;
-const CGFloat kMinimumContainerWidth = 3.0;
 }  // namespace
 
 @interface BrowserActionsContainerView(Private)
 // Returns the cursor that should be shown when hovering over the grippy based
 // on |canDragLeft_| and |canDragRight_|.
 - (NSCursor*)appropriateCursorForGrippy;
-
-// Returns the maximum allowed size for the container.
-- (CGFloat)maxAllowedWidth;
 @end
 
 @implementation BrowserActionsContainerView
 
-@synthesize canDragLeft = canDragLeft_;
-@synthesize canDragRight = canDragRight_;
+@synthesize minWidth = minWidth_;
+@synthesize maxWidth = maxWidth_;
 @synthesize grippyPinned = grippyPinned_;
-@synthesize maxDesiredWidth = maxDesiredWidth_;
 @synthesize userIsResizing = userIsResizing_;
-@synthesize delegate = delegate_;
 
 #pragma mark -
 #pragma mark Overridden Class Functions
@@ -62,8 +56,6 @@
     if (cocoa_l10n_util::ShouldDoExperimentalRTLLayout())
       grippyRect_.origin.x = NSWidth(frameRect) - NSWidth(grippyRect_);
 
-    canDragLeft_ = YES;
-    canDragRight_ = YES;
     resizable_ = YES;
 
     resizeAnimation_.reset([[NSViewAnimation alloc] init]);
@@ -179,12 +171,15 @@
 }
 
 - (void)mouseDown:(NSEvent*)theEvent {
-  initialDragPoint_ = [self convertPoint:[theEvent locationInWindow]
-                                fromView:nil];
-  if (!resizable_ ||
-      !NSMouseInRect(initialDragPoint_, grippyRect_, [self isFlipped]))
+  NSPoint location =
+      [self convertPoint:[theEvent locationInWindow] fromView:nil];
+  if (!resizable_ || !NSMouseInRect(location, grippyRect_, [self isFlipped]))
     return;
 
+  dragOffset_ = location.x - (cocoa_l10n_util::ShouldDoExperimentalRTLLayout()
+                                  ? NSWidth(self.frame)
+                                  : 0);
+
   userIsResizing_ = YES;
 
   [[self appropriateCursorForGrippy] push];
@@ -215,37 +210,14 @@
   if (!userIsResizing_)
     return;
 
-  NSPoint location = [self convertPoint:[theEvent locationInWindow]
-                               fromView:nil];
-  NSRect containerFrame = [self frame];
-  CGFloat dX = [theEvent deltaX];
-  CGFloat withDelta = location.x - dX;
-  BOOL isRTL = cocoa_l10n_util::ShouldDoExperimentalRTLLayout();
+  const CGFloat translation =
+      [self convertPoint:[theEvent locationInWindow] fromView:nil].x -
+      dragOffset_;
+  const CGFloat targetWidth = (cocoa_l10n_util::ShouldDoExperimentalRTLLayout()
+                                   ? translation
+                                   : NSWidth(self.frame) - translation);
 
-  CGFloat maxAllowedWidth = [self maxAllowedWidth];
-
-  const CGFloat maxWidth = std::min(maxAllowedWidth, maxDesiredWidth_);
-  CGFloat newWidth = NSWidth(containerFrame) + (isRTL ? dX : -dX);
-  newWidth = std::min(std::max(newWidth, kMinimumContainerWidth), maxWidth);
-
-  BOOL canGrow = NSWidth(containerFrame) < maxWidth;
-  BOOL canShrink = NSWidth(containerFrame) > kMinimumContainerWidth;
-
-  canDragLeft_ =
-      withDelta <= initialDragPoint_.x && (isRTL ? canShrink : canGrow);
-  canDragRight_ =
-      (withDelta >= initialDragPoint_.x) && (isRTL ? canGrow : canShrink);
-  if ((dX < 0.0 && !canDragLeft_) || (dX > 0.0 && !canDragRight_) ||
-      fabs(dX) < FLT_EPSILON)
-    return;
-
-  grippyPinned_ = newWidth >= maxAllowedWidth;
-  if (!isRTL)
-    containerFrame.origin.x += dX;
-  containerFrame.size.width = newWidth;
-
-  [self setFrame:containerFrame];
-  [self setNeedsDisplay:YES];
+  [self resizeToWidth:targetWidth animate:NO];
 
   [[NSNotificationCenter defaultCenter]
       postNotificationName:kBrowserActionGrippyDraggingNotification
@@ -282,21 +254,14 @@
 #pragma mark Public Methods
 
 - (void)resizeToWidth:(CGFloat)width animate:(BOOL)animate {
-  width = std::max(width, kMinimumContainerWidth);
+  width = std::min(std::max(width, minWidth_), maxWidth_);
+
   NSRect newFrame = [self frame];
+  if (!cocoa_l10n_util::ShouldDoExperimentalRTLLayout())
+    newFrame.origin.x += NSWidth(newFrame) - width;
+  newFrame.size.width = width;
 
-  CGFloat maxAllowedWidth = [self maxAllowedWidth];
-  width = std::min(maxAllowedWidth, width);
-
-  if (cocoa_l10n_util::ShouldDoExperimentalRTLLayout()) {
-    newFrame.size.width = width;
-  } else {
-    CGFloat dX = NSWidth(newFrame) - width;
-    newFrame.size.width = width;
-    newFrame.origin.x += dX;
-  }
-
-  grippyPinned_ = width == maxAllowedWidth;
+  grippyPinned_ = width == maxWidth_;
 
   [self stopAnimation];
 
@@ -343,21 +308,20 @@
 // Returns the cursor to display over the grippy hover region depending on the
 // current drag state.
 - (NSCursor*)appropriateCursorForGrippy {
-  NSCursor* retVal;
-  if (!resizable_ || (!canDragLeft_ && !canDragRight_)) {
-    retVal = [NSCursor arrowCursor];
-  } else if (!canDragLeft_) {
-    retVal = [NSCursor resizeRightCursor];
-  } else if (!canDragRight_) {
-    retVal = [NSCursor resizeLeftCursor];
-  } else {
-    retVal = [NSCursor resizeLeftRightCursor];
-  }
-  return retVal;
-}
+  if (resizable_) {
+    const CGFloat width = NSWidth(self.frame);
+    const BOOL isRTL = cocoa_l10n_util::ShouldDoExperimentalRTLLayout();
+    const BOOL canDragLeft = width != (isRTL ? minWidth_ : maxWidth_);
+    const BOOL canDragRight = width != (isRTL ? maxWidth_ : minWidth_);
 
-- (CGFloat)maxAllowedWidth {
-  return delegate_ ? delegate_->GetMaxAllowedWidth() : CGFLOAT_MAX;
+    if (canDragLeft && canDragRight)
+      return [NSCursor resizeLeftRightCursor];
+    if (canDragLeft)
+      return [NSCursor resizeLeftCursor];
+    if (canDragRight)
+      return [NSCursor resizeRightCursor];
+  }
+  return [NSCursor arrowCursor];
 }
 
 @end
diff --git a/chrome/browser/ui/cocoa/extensions/browser_actions_container_view_unittest.mm b/chrome/browser/ui/cocoa/extensions/browser_actions_container_view_unittest.mm
index dca3226..7f26cab 100644
--- a/chrome/browser/ui/cocoa/extensions/browser_actions_container_view_unittest.mm
+++ b/chrome/browser/ui/cocoa/extensions/browser_actions_container_view_unittest.mm
@@ -15,18 +15,6 @@
 const CGFloat kMinimumContainerWidth = 3.0;
 const CGFloat kMaxAllowedWidthForTest = 50.0;
 
-class BrowserActionsContainerTestDelegate
-    : public BrowserActionsContainerViewSizeDelegate {
- public:
-  BrowserActionsContainerTestDelegate() {}
-  ~BrowserActionsContainerTestDelegate() override {}
-
-  CGFloat GetMaxAllowedWidth() override { return kMaxAllowedWidthForTest; }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(BrowserActionsContainerTestDelegate);
-};
-
 class BrowserActionsContainerViewTest : public CocoaTest {
  public:
   void SetUp() override {
@@ -39,13 +27,14 @@
 };
 
 TEST_F(BrowserActionsContainerViewTest, BasicTests) {
-  EXPECT_TRUE([view_ canDragLeft]);
-  EXPECT_TRUE([view_ canDragRight]);
   EXPECT_TRUE([view_ isHidden]);
 }
 
 TEST_F(BrowserActionsContainerViewTest, SetWidthTests) {
-  // Try setting below the minimum width (10 pixels).
+  [view_ setMinWidth:kMinimumContainerWidth];
+  [view_ setMaxWidth:kMaxAllowedWidthForTest];
+
+  // Try setting below the minimum width.
   [view_ resizeToWidth:kMinimumContainerWidth - 1 animate:NO];
   EXPECT_EQ(kMinimumContainerWidth, NSWidth([view_ frame])) << "Frame width is "
       << "less than the minimum allowed.";
@@ -73,11 +62,8 @@
   EXPECT_EQ(35.0, NSWidth([view_ frame]));
   EXPECT_EQ(35.0, NSWidth([view_ animationEndFrame]));
 
-  BrowserActionsContainerTestDelegate delegate;
-  [view_ setDelegate:&delegate];
   [view_ resizeToWidth:kMaxAllowedWidthForTest + 10.0 animate:NO];
   EXPECT_EQ(kMaxAllowedWidthForTest, NSWidth([view_ frame]));
-  [view_ setDelegate:nil];
 }
 
 }  // namespace
diff --git a/chrome/browser/ui/cocoa/extensions/browser_actions_controller.h b/chrome/browser/ui/cocoa/extensions/browser_actions_controller.h
index 26802e1b..1c8ebe7 100644
--- a/chrome/browser/ui/cocoa/extensions/browser_actions_controller.h
+++ b/chrome/browser/ui/cocoa/extensions/browser_actions_controller.h
@@ -60,6 +60,7 @@
   NSInteger focusedViewIndex_;
 }
 
+@property(nonatomic) CGFloat maxWidth;
 @property(readonly, nonatomic) BrowserActionsContainerView* containerView;
 @property(readonly, nonatomic) Browser* browser;
 @property(readonly, nonatomic) BOOL isOverflow;
diff --git a/chrome/browser/ui/cocoa/extensions/browser_actions_controller.mm b/chrome/browser/ui/cocoa/extensions/browser_actions_controller.mm
index 60d3c42..17cadc0 100644
--- a/chrome/browser/ui/cocoa/extensions/browser_actions_controller.mm
+++ b/chrome/browser/ui/cocoa/extensions/browser_actions_controller.mm
@@ -135,9 +135,6 @@
 // Handles clicks for BrowserActionButtons.
 - (BOOL)browserActionClicked:(BrowserActionButton*)button;
 
-// Updates the container's grippy cursor based on the number of hidden buttons.
-- (void)updateGrippyCursors;
-
 // Returns the associated ToolbarController.
 - (ToolbarController*)toolbarController;
 
@@ -249,6 +246,7 @@
 
 @implementation BrowserActionsController
 
+@synthesize maxWidth = maxWidth_;
 @synthesize containerView = containerView_;
 @synthesize browser = browser_;
 @synthesize isOverflow = isOverflow_;
@@ -275,6 +273,7 @@
                               mainBar));
 
     containerView_ = container;
+    [containerView_ setMinWidth:toolbarActionsBar_->GetMinimumWidth()];
     [containerView_ setPostsFrameChangedNotifications:YES];
     [[NSNotificationCenter defaultCenter]
         addObserver:self
@@ -314,7 +313,6 @@
 
     buttons_.reset([[NSMutableArray alloc] init]);
     toolbarActionsBar_->CreateActions();
-    [self updateGrippyCursors];
     [container setIsOverflow:isOverflow_];
 
     focusedViewIndex_ = -1;
@@ -405,6 +403,17 @@
   return [self preferredSize];
 }
 
+- (void)updateMaxWidth {
+  const CGFloat ownMaxWidth = toolbarActionsBar_->GetMaximumWidth();
+  containerView_.maxWidth =
+      (maxWidth_ ? std::min(maxWidth_, ownMaxWidth) : ownMaxWidth);
+}
+
+- (void)setMaxWidth:(CGFloat)maxWidth {
+  maxWidth_ = maxWidth;
+  [self updateMaxWidth];
+}
+
 - (void)addViewForAction:(ToolbarActionViewController*)action
                withIndex:(NSUInteger)index {
   NSRect buttonFrame = NSMakeRect(NSMaxX([containerView_ bounds]),
@@ -420,13 +429,12 @@
   [newButton setAction:@selector(browserActionClicked:)];
   [buttons_ insertObject:newButton atIndex:index];
 
+  [self updateMaxWidth];
   [[NSNotificationCenter defaultCenter]
       addObserver:self
          selector:@selector(actionButtonDragging:)
              name:kBrowserActionButtonDraggingNotification
            object:newButton];
-
-  [containerView_ setMaxDesiredWidth:toolbarActionsBar_->GetMaximumWidth()];
 }
 
 - (void)redraw {
@@ -505,9 +513,8 @@
   [button removeFromSuperview];
   [buttons_ removeObject:button];
 
+  [self updateMaxWidth];
   [button onRemoved];
-
-  [containerView_ setMaxDesiredWidth:toolbarActionsBar_->GetMaximumWidth()];
 }
 
 - (void)removeAllViews {
@@ -537,7 +544,7 @@
                       object:self];
   }
   [self redraw];
-  [self updateGrippyCursors];
+  [[containerView_ window] invalidateCursorRectsForView:containerView_];
 }
 
 - (BOOL)updateContainerVisibility {
@@ -622,27 +629,8 @@
 }
 
 - (void)containerDragFinished:(NSNotification*)notification {
-  for (BrowserActionButton* button in buttons_.get()) {
-    NSRect buttonFrame = [button frame];
-    if (NSContainsRect([containerView_ bounds], buttonFrame))
-      continue;
-
-    CGFloat intersectionWidth =
-        NSWidth(NSIntersectionRect([containerView_ bounds], buttonFrame));
-    // Hide the button if it's not "mostly" visible. "Mostly" here equates to
-    // having three or fewer pixels hidden.
-    if (([containerView_ grippyPinned] && intersectionWidth > 0) ||
-        (intersectionWidth <= NSWidth(buttonFrame) - 3.0)) {
-      [button setAlphaValue:0.0];
-      [button removeFromSuperview];
-    }
-  }
-
-  toolbarActionsBar_->OnResizeComplete(
-      toolbarActionsBar_->IconCountToWidth([self visibleButtonCount]));
-
-  [self updateGrippyCursors];
-  [self resizeContainerToWidth:toolbarActionsBar_->GetPreferredSize().width()];
+  toolbarActionsBar_->OnResizeComplete(NSWidth(containerView_.bounds));
+  [[containerView_ window] invalidateCursorRectsForView:containerView_];
 }
 
 - (void)containerAnimationEnded:(NSNotification*)notification {
@@ -786,20 +774,6 @@
   return [button viewController]->ExecuteAction(true);
 }
 
-- (void)updateGrippyCursors {
-  BOOL canClose = [self visibleButtonCount] > 0;
-  BOOL canOpen = toolbarActionsBar_->GetIconCount() != [buttons_ count];
-  [containerView_
-      setCanDragLeft:cocoa_l10n_util::ShouldDoExperimentalRTLLayout()
-                         ? canClose
-                         : canOpen];
-  [containerView_
-      setCanDragRight:cocoa_l10n_util::ShouldDoExperimentalRTLLayout()
-                          ? canOpen
-                          : canClose];
-  [[containerView_ window] invalidateCursorRectsForView:containerView_];
-}
-
 - (ToolbarController*)toolbarController {
   return [[BrowserWindowController browserWindowControllerForWindow:
              browser_->window()->GetNativeWindow()] toolbarController];
diff --git a/chrome/browser/ui/cocoa/toolbar/toolbar_controller.h b/chrome/browser/ui/cocoa/toolbar/toolbar_controller.h
index cf0c6a0..62b049a 100644
--- a/chrome/browser/ui/cocoa/toolbar/toolbar_controller.h
+++ b/chrome/browser/ui/cocoa/toolbar/toolbar_controller.h
@@ -21,7 +21,6 @@
 @class BackForwardMenuController;
 class Browser;
 @class BrowserActionsContainerView;
-class BrowserActionsContainerViewSizeDelegate;
 @class BrowserActionsController;
 class CommandUpdater;
 class LocationBarViewMac;
@@ -71,8 +70,6 @@
   base::scoped_nsobject<BackForwardMenuController> backMenuController_;
   base::scoped_nsobject<BackForwardMenuController> forwardMenuController_;
   base::scoped_nsobject<BrowserActionsController> browserActionsController_;
-  std::unique_ptr<BrowserActionsContainerViewSizeDelegate>
-      browserActionsContainerDelegate_;
 
   // Lazily-instantiated menu controller.
   base::scoped_nsobject<AppMenuController> appMenuController_;
diff --git a/chrome/browser/ui/cocoa/toolbar/toolbar_controller.mm b/chrome/browser/ui/cocoa/toolbar/toolbar_controller.mm
index 9206e9e..4b3458fa 100644
--- a/chrome/browser/ui/cocoa/toolbar/toolbar_controller.mm
+++ b/chrome/browser/ui/cocoa/toolbar/toolbar_controller.mm
@@ -103,42 +103,6 @@
 // The minimum width of the location bar in pixels.
 const CGFloat kMinimumLocationBarWidth = 100.0;
 
-class BrowserActionsContainerDelegate :
-    public BrowserActionsContainerViewSizeDelegate {
- public:
-  BrowserActionsContainerDelegate(
-      AutocompleteTextField* location_bar,
-      BrowserActionsContainerView* browser_actions_container_view);
-  ~BrowserActionsContainerDelegate() override;
-
- private:
-  // BrowserActionsContainerSizeDelegate:
-  CGFloat GetMaxAllowedWidth() override;
-
-  AutocompleteTextField* location_bar_;
-  BrowserActionsContainerView* browser_actions_container_;
-
-  DISALLOW_COPY_AND_ASSIGN(BrowserActionsContainerDelegate);
-};
-
-BrowserActionsContainerDelegate::BrowserActionsContainerDelegate(
-    AutocompleteTextField* location_bar,
-    BrowserActionsContainerView* browser_actions_container_view)
-    : location_bar_(location_bar),
-      browser_actions_container_(browser_actions_container_view) {
-  [browser_actions_container_ setDelegate:this];
-}
-
-BrowserActionsContainerDelegate::~BrowserActionsContainerDelegate() {
-  [browser_actions_container_ setDelegate:nil];
-}
-
-CGFloat BrowserActionsContainerDelegate::GetMaxAllowedWidth() {
-  CGFloat location_bar_flex =
-      NSWidth([location_bar_ frame]) - kMinimumLocationBarWidth;
-  return NSWidth([browser_actions_container_ frame]) + location_bar_flex;
-}
-
 }  // namespace
 
 @interface ToolbarController()
@@ -528,7 +492,6 @@
 
   // Destroy owned objects that hold a weak Browser*.
   locationBarView_.reset();
-  browserActionsContainerDelegate_.reset();
   browser_ = nullptr;
 }
 
@@ -786,9 +749,6 @@
 
 - (void)createBrowserActionButtons {
   if (!browserActionsController_.get()) {
-    browserActionsContainerDelegate_.reset(
-        new BrowserActionsContainerDelegate(locationBar_,
-                                            browserActionsContainerView_));
     browserActionsController_.reset([[BrowserActionsController alloc]
             initWithBrowser:browser_
               containerView:browserActionsContainerView_
@@ -814,8 +774,7 @@
                name:NSWindowDidBecomeKeyNotification
              object:[[self view] window]];
   }
-  if (![browserActionsContainerView_ isHidden])
-    [self pinLocationBarBeforeBrowserActionsContainerAndAnimate:NO];
+  [self pinLocationBarBeforeBrowserActionsContainerAndAnimate:NO];
 }
 
 - (void)updateVisibility:(BOOL)visible withAnimation:(BOOL)animate {
@@ -875,10 +834,7 @@
     }
   }
 
-  if (delta != 0.0)
-    [self adjustLocationSizeBy:delta animate:animate];
-  else
-    [locationBar_ stopAnimation];
+  [self adjustLocationSizeBy:delta animate:animate];
 }
 
 - (void)maintainMinimumLocationBarWidth {
@@ -979,13 +935,23 @@
 }
 
 - (void)adjustLocationSizeBy:(CGFloat)dX animate:(BOOL)animate {
-  // Ensure that the location bar is in its proper place.
   NSRect locationFrame = [locationBar_ frame];
+
+  CGFloat location_bar_flex = NSWidth(locationFrame) - kMinimumLocationBarWidth;
+  [browserActionsController_
+      setMaxWidth:NSWidth(browserActionsContainerView_.frame) +
+                  location_bar_flex];
+
+  [locationBar_ stopAnimation];
+
+  if (dX == 0)
+    return;
+
+  // Ensure that the location bar is in its proper place.
   locationFrame.size.width += dX;
   if (cocoa_l10n_util::ShouldDoExperimentalRTLLayout())
     locationFrame.origin.x -= dX;
 
-  [locationBar_ stopAnimation];
   if (animate)
     [locationBar_ animateToFrame:locationFrame];
   else
diff --git a/chrome/browser/ui/views/payments/payment_request_dialog.cc b/chrome/browser/ui/views/payments/payment_request_dialog.cc
index 58af72fb..99a2871 100644
--- a/chrome/browser/ui/views/payments/payment_request_dialog.cc
+++ b/chrome/browser/ui/views/payments/payment_request_dialog.cc
@@ -21,8 +21,9 @@
 namespace chrome {
 
 void ShowPaymentRequestDialog(payments::PaymentRequest* request) {
-  constrained_window::ShowWebModalDialogViews(
-      new payments::PaymentRequestDialog(request), request->web_contents());
+  payments::PaymentRequestDialog::ShowWebModalPaymentDialog(
+      new payments::PaymentRequestDialog(request, /* no observer */ nullptr),
+      request);
 }
 
 }  // namespace chrome
@@ -48,8 +49,10 @@
 
 }  // namespace
 
-PaymentRequestDialog::PaymentRequestDialog(PaymentRequest* request)
-    : request_(request) {
+PaymentRequestDialog::PaymentRequestDialog(
+    PaymentRequest* request,
+    PaymentRequestDialog::ObserverForTest* observer)
+    : request_(request), observer_(observer) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   SetLayoutManager(new views::FillLayout());
 
@@ -109,10 +112,19 @@
   GetWidget()->Close();
 }
 
+// static
+void PaymentRequestDialog::ShowWebModalPaymentDialog(
+    PaymentRequestDialog* dialog,
+    PaymentRequest* request) {
+  constrained_window::ShowWebModalDialogViews(dialog, request->web_contents());
+}
+
 void PaymentRequestDialog::ShowInitialPaymentSheet() {
   view_stack_.Push(CreateViewAndInstallController<PaymentSheetViewController>(
                        &controller_map_, request_, this),
                    false);
+  if (observer_)
+    observer_->OnDialogOpened();
 }
 
 gfx::Size PaymentRequestDialog::GetPreferredSize() const {
diff --git a/chrome/browser/ui/views/payments/payment_request_dialog.h b/chrome/browser/ui/views/payments/payment_request_dialog.h
index d11f41312..e4f2ed16 100644
--- a/chrome/browser/ui/views/payments/payment_request_dialog.h
+++ b/chrome/browser/ui/views/payments/payment_request_dialog.h
@@ -28,7 +28,16 @@
 // the WebPayments flow and managing the transition between those states.
 class PaymentRequestDialog : public views::DialogDelegateView {
  public:
-  explicit PaymentRequestDialog(PaymentRequest* request);
+  class ObserverForTest {
+   public:
+    virtual void OnDialogOpened() = 0;
+  };
+
+  // Build a Dialog around the PaymentRequest object. |observer| is used to
+  // be notified of dialog events as they happen (but may be NULL) and should
+  // outlive this object.
+  PaymentRequestDialog(PaymentRequest* request,
+                       PaymentRequestDialog::ObserverForTest* observer);
   ~PaymentRequestDialog() override;
 
   // views::WidgetDelegate
@@ -44,6 +53,9 @@
   void ShowPaymentMethodSheet();
   void CloseDialog();
 
+  static void ShowWebModalPaymentDialog(PaymentRequestDialog* dialog,
+                                        PaymentRequest* request);
+
  private:
   void ShowInitialPaymentSheet();
 
@@ -57,6 +69,8 @@
   // always be valid even though there is no direct ownership relationship
   // between the two.
   PaymentRequest* request_;
+  // May be null.
+  ObserverForTest* observer_;
   ControllerMap controller_map_;
   ViewStack view_stack_;
 
diff --git a/chrome/browser/ui/views/payments/payment_request_interactive_uitest.cc b/chrome/browser/ui/views/payments/payment_request_interactive_uitest.cc
new file mode 100644
index 0000000..f4838628
--- /dev/null
+++ b/chrome/browser/ui/views/payments/payment_request_interactive_uitest.cc
@@ -0,0 +1,39 @@
+// 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 <vector>
+
+#include "chrome/browser/ui/views/payments/payment_request_interactive_uitest_base.h"
+#include "components/payments/payment_request.h"
+#include "components/payments/payment_request_web_contents_manager.h"
+
+namespace payments {
+
+class PaymentRequestWebContentsManagerTest
+    : public PaymentRequestInteractiveTestBase {
+ protected:
+  PaymentRequestWebContentsManagerTest()
+      : PaymentRequestInteractiveTestBase(
+            "/payment_request_multiple_requests.html") {}
+};
+
+// If the page creates multiple PaymentRequest objects, it should not crash.
+IN_PROC_BROWSER_TEST_F(PaymentRequestWebContentsManagerTest, MultipleRequests) {
+  const std::vector<PaymentRequest*> payment_requests =
+      GetPaymentRequests(GetActiveWebContents());
+  EXPECT_EQ(5U, payment_requests.size());
+}
+
+class PaymentRequestNoShippingTest : public PaymentRequestInteractiveTestBase {
+ protected:
+  PaymentRequestNoShippingTest()
+      : PaymentRequestInteractiveTestBase(
+            "/payment_request_no_shipping_test.html") {}
+};
+
+IN_PROC_BROWSER_TEST_F(PaymentRequestNoShippingTest, OpenPaymentRequestSheet) {
+  InvokePaymentRequestUI();
+}
+
+}  // namespace payments
diff --git a/chrome/browser/ui/views/payments/payment_request_interactive_uitest_base.cc b/chrome/browser/ui/views/payments/payment_request_interactive_uitest_base.cc
new file mode 100644
index 0000000..b1e7f27
--- /dev/null
+++ b/chrome/browser/ui/views/payments/payment_request_interactive_uitest_base.cc
@@ -0,0 +1,133 @@
+// 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 "chrome/browser/ui/views/payments/payment_request_interactive_uitest_base.h"
+
+#include <vector>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/memory/ptr_util.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/views/payments/test_chrome_payment_request_delegate.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "components/payments/payment_request.h"
+#include "components/payments/payment_request_web_contents_manager.h"
+#include "components/web_modal/web_contents_modal_dialog_manager.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/common/content_switches.h"
+#include "content/public/test/browser_test_utils.h"
+#include "services/service_manager/public/cpp/interface_registry.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace payments {
+
+PaymentRequestInteractiveTestBase::PaymentRequestInteractiveTestBase(
+    const std::string& test_file_path)
+    : test_file_path_(test_file_path) {}
+PaymentRequestInteractiveTestBase::~PaymentRequestInteractiveTestBase() {}
+
+void PaymentRequestInteractiveTestBase::SetUpCommandLine(
+    base::CommandLine* command_line) {
+  InProcessBrowserTest::SetUpCommandLine(command_line);
+  command_line->AppendSwitch(switches::kEnableExperimentalWebPlatformFeatures);
+}
+
+void PaymentRequestInteractiveTestBase::SetUpOnMainThread() {
+  https_server_ = base::MakeUnique<net::EmbeddedTestServer>(
+      net::EmbeddedTestServer::TYPE_HTTPS);
+  ASSERT_TRUE(https_server_->InitializeAndListen());
+  https_server_->ServeFilesFromSourceDirectory("chrome/test/data/payments");
+  https_server_->StartAcceptingConnections();
+
+  GURL url = https_server()->GetURL(test_file_path_);
+  ui_test_utils::NavigateToURL(browser(), url);
+
+  // Starting now, PaymentRequest Mojo messages sent by the renderer will
+  // create PaymentRequest objects via this test's CreatePaymentRequestForTest,
+  // allowing the test to inject itself as a dialog observer.
+  content::WebContents* web_contents = GetActiveWebContents();
+  service_manager::InterfaceRegistry* registry =
+      web_contents->GetMainFrame()->GetInterfaceRegistry();
+  registry->RemoveInterface(payments::mojom::PaymentRequest::Name_);
+  registry->AddInterface(base::Bind(
+      &PaymentRequestInteractiveTestBase::CreatePaymentRequestForTest,
+      base::Unretained(this), web_contents));
+}
+
+void PaymentRequestInteractiveTestBase::OnDialogOpened() {
+  if (event_observer_)
+    event_observer_->Observe(DialogEvent::DIALOG_OPENED);
+}
+
+void PaymentRequestInteractiveTestBase::InvokePaymentRequestUI() {
+  event_observer_.reset(new DialogEventObserver(DialogEvent::DIALOG_OPENED));
+
+  content::WebContents* web_contents = GetActiveWebContents();
+  const std::string click_buy_button_js =
+      "(function() { document.getElementById('buy').click(); })();";
+  ASSERT_TRUE(content::ExecuteScript(web_contents, click_buy_button_js));
+
+  event_observer_->Wait();
+
+  // The web-modal dialog should be open.
+  web_modal::WebContentsModalDialogManager* web_contents_modal_dialog_manager =
+      web_modal::WebContentsModalDialogManager::FromWebContents(web_contents);
+  EXPECT_TRUE(web_contents_modal_dialog_manager->IsDialogActive());
+}
+
+content::WebContents*
+PaymentRequestInteractiveTestBase::GetActiveWebContents() {
+  return browser()->tab_strip_model()->GetActiveWebContents();
+}
+
+const std::vector<PaymentRequest*>
+PaymentRequestInteractiveTestBase::GetPaymentRequests(
+    content::WebContents* web_contents) {
+  PaymentRequestWebContentsManager* manager =
+      PaymentRequestWebContentsManager::GetOrCreateForWebContents(web_contents);
+  if (!manager)
+    return std::vector<PaymentRequest*>();
+
+  std::vector<PaymentRequest*> payment_requests_ptrs;
+  for (const auto& p : manager->payment_requests_)
+    payment_requests_ptrs.push_back(p.first);
+  return payment_requests_ptrs;
+}
+
+void PaymentRequestInteractiveTestBase::CreatePaymentRequestForTest(
+    content::WebContents* web_contents,
+    mojo::InterfaceRequest<payments::mojom::PaymentRequest> request) {
+  DCHECK(web_contents);
+  PaymentRequestWebContentsManager::GetOrCreateForWebContents(web_contents)
+      ->CreatePaymentRequest(web_contents,
+                             base::MakeUnique<TestChromePaymentRequestDelegate>(
+                                 web_contents, this /* observer */),
+                             std::move(request));
+}
+
+PaymentRequestInteractiveTestBase::DialogEventObserver::DialogEventObserver(
+    PaymentRequestInteractiveTestBase::DialogEvent event)
+    : event_(event), seen_(false) {}
+PaymentRequestInteractiveTestBase::DialogEventObserver::~DialogEventObserver() {
+}
+
+void PaymentRequestInteractiveTestBase::DialogEventObserver::Wait() {
+  if (seen_)
+    return;
+
+  DCHECK(!run_loop_.running());
+  run_loop_.Run();
+}
+
+void PaymentRequestInteractiveTestBase::DialogEventObserver::Observe(
+    PaymentRequestInteractiveTestBase::DialogEvent event) {
+  seen_ = true;
+  if (event == event_ && run_loop_.running())
+    run_loop_.Quit();
+}
+
+}  // namespace payments
diff --git a/chrome/browser/ui/views/payments/payment_request_interactive_uitest_base.h b/chrome/browser/ui/views/payments/payment_request_interactive_uitest_base.h
new file mode 100644
index 0000000..0e2fe7bf
--- /dev/null
+++ b/chrome/browser/ui/views/payments/payment_request_interactive_uitest_base.h
@@ -0,0 +1,106 @@
+// 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 CHROME_BROWSER_UI_VIEWS_PAYMENTS_PAYMENT_REQUEST_INTERACTIVE_UITEST_BASE_H_
+#define CHROME_BROWSER_UI_VIEWS_PAYMENTS_PAYMENT_REQUEST_INTERACTIVE_UITEST_BASE_H_
+
+#include <vector>
+
+#include "base/command_line.h"
+#include "base/macros.h"
+#include "base/run_loop.h"
+#include "chrome/browser/ui/views/payments/payment_request_dialog.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "components/payments/payment_request.mojom.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+
+namespace content {
+class WebContents;
+}  // namespace content
+
+namespace payments {
+
+class PaymentRequest;
+
+// Base class for any interactive PaymentRequest test that will need to open
+// the UI and interact with it.
+class PaymentRequestInteractiveTestBase
+    : public InProcessBrowserTest,
+      public PaymentRequestDialog::ObserverForTest {
+ protected:
+  // Test will open a browser window to |test_file_path| (relative to
+  // chrome/test/data/payments).
+  explicit PaymentRequestInteractiveTestBase(const std::string& test_file_path);
+  ~PaymentRequestInteractiveTestBase() override;
+
+  void SetUpCommandLine(base::CommandLine* command_line) override;
+  void SetUpOnMainThread() override;
+
+  // PaymentRequestDialog::ObserverForTest
+  void OnDialogOpened() override;
+
+  // Will call JavaScript to invoke the PaymentRequest dialog and verify that
+  // it's open.
+  void InvokePaymentRequestUI();
+
+  // Convenience method to get a list of PaymentRequest associated with
+  // |web_contents|.
+  const std::vector<PaymentRequest*> GetPaymentRequests(
+      content::WebContents* web_contents);
+
+  content::WebContents* GetActiveWebContents();
+
+  void CreatePaymentRequestForTest(
+      content::WebContents* web_contents,
+      mojo::InterfaceRequest<payments::mojom::PaymentRequest> request);
+
+  net::EmbeddedTestServer* https_server() { return https_server_.get(); }
+
+ private:
+  // Various events that can be waited on by the DialogEventObserver.
+  enum DialogEvent {
+    DIALOG_OPENED,
+  };
+
+  // DialogEventObserver is used to wait on specific events that may have
+  // occured before the call to Wait(), or after, in which case a RunLoop is
+  // used.
+  //
+  // Usage:
+  // observer_.reset(new DialogEventObserver([DialogEvent]));
+  //
+  // Do stuff, which (a)synchronously calls observer_->Observe([DialogEvent]).
+  //
+  // observer_->Wait();  <- Will either return right away if event was observed,
+  //                     <- or use a RunLoop's Run/Quit to wait for the event.
+  class DialogEventObserver {
+   public:
+    explicit DialogEventObserver(DialogEvent event);
+    ~DialogEventObserver();
+
+    // Either returns right away if the event was observed between this object's
+    // construction and this call to Wait(), or use a RunLoop to wait for it.
+    void Wait();
+
+    // Observes the event (quits the RunLoop if it was running).
+    void Observe(DialogEvent event);
+
+   private:
+    DialogEvent event_;
+    bool seen_;
+    base::RunLoop run_loop_;
+
+    DISALLOW_COPY_AND_ASSIGN(DialogEventObserver);
+  };
+
+  const std::string test_file_path_;
+  std::unique_ptr<net::EmbeddedTestServer> https_server_;
+  std::unique_ptr<DialogEventObserver> event_observer_;
+
+  DISALLOW_COPY_AND_ASSIGN(PaymentRequestInteractiveTestBase);
+};
+
+}  // namespace payments
+
+#endif  // CHROME_BROWSER_UI_VIEWS_PAYMENTS_PAYMENT_REQUEST_INTERACTIVE_UITEST_BASE_H_
diff --git a/chrome/browser/ui/views/payments/test_chrome_payment_request_delegate.cc b/chrome/browser/ui/views/payments/test_chrome_payment_request_delegate.cc
new file mode 100644
index 0000000..09c6877
--- /dev/null
+++ b/chrome/browser/ui/views/payments/test_chrome_payment_request_delegate.cc
@@ -0,0 +1,22 @@
+// 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 "chrome/browser/ui/views/payments/test_chrome_payment_request_delegate.h"
+
+#include "content/public/browser/web_contents.h"
+
+namespace payments {
+
+TestChromePaymentRequestDelegate::TestChromePaymentRequestDelegate(
+    content::WebContents* web_contents,
+    PaymentRequestDialog::ObserverForTest* observer)
+    : ChromePaymentRequestDelegate(web_contents), observer_(observer) {}
+
+void TestChromePaymentRequestDelegate::ShowPaymentRequestDialog(
+    PaymentRequest* request) {
+  PaymentRequestDialog::ShowWebModalPaymentDialog(
+      new PaymentRequestDialog(request, observer_), request);
+}
+
+}  // namespace payments
diff --git a/chrome/browser/ui/views/payments/test_chrome_payment_request_delegate.h b/chrome/browser/ui/views/payments/test_chrome_payment_request_delegate.h
new file mode 100644
index 0000000..adccc37
--- /dev/null
+++ b/chrome/browser/ui/views/payments/test_chrome_payment_request_delegate.h
@@ -0,0 +1,37 @@
+// 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 CHROME_BROWSER_UI_VIEWS_PAYMENTS_TEST_CHROME_PAYMENT_REQUEST_DELEGATE_H_
+#define CHROME_BROWSER_UI_VIEWS_PAYMENTS_TEST_CHROME_PAYMENT_REQUEST_DELEGATE_H_
+
+#include "base/macros.h"
+#include "chrome/browser/payments/chrome_payment_request_delegate.h"
+#include "chrome/browser/ui/views/payments/payment_request_dialog.h"
+
+namespace content {
+class WebContents;
+}
+
+namespace payments {
+
+class PaymentRequest;
+
+// Implementation of the Payment Request delegate used in tests.
+class TestChromePaymentRequestDelegate : public ChromePaymentRequestDelegate {
+ public:
+  TestChromePaymentRequestDelegate(
+      content::WebContents* web_contents,
+      PaymentRequestDialog::ObserverForTest* observer);
+
+  void ShowPaymentRequestDialog(PaymentRequest* request) override;
+
+ private:
+  PaymentRequestDialog::ObserverForTest* observer_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestChromePaymentRequestDelegate);
+};
+
+}  // namespace payments
+
+#endif  // CHROME_BROWSER_UI_VIEWS_PAYMENTS_TEST_CHROME_PAYMENT_REQUEST_DELEGATE_H_
diff --git a/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.cc b/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.cc
index fb2ed5a2..6f5f7d2 100644
--- a/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.cc
@@ -480,7 +480,7 @@
 }
 
 void CoreOobeHandler::UpdateClientAreaSize() {
-  const gfx::Size& size =
+  const gfx::Size size =
       display::Screen::GetScreen()->GetPrimaryDisplay().size();
   SetClientAreaSize(size.width(), size.height());
 }
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index bd701a7..897e3c38 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -568,6 +568,15 @@
           "base/interactive_test_utils_views.cc",
         ]
       }
+      if (is_win || is_linux) {
+        # TODO(crbug.com/679127): Enable these tests on "mac_views_browser" once
+        # it is supported.
+        sources += [
+          "../browser/ui/views/payments/payment_request_interactive_uitest.cc",
+          "../browser/ui/views/payments/payment_request_interactive_uitest_base.cc",
+          "../browser/ui/views/payments/payment_request_interactive_uitest_base.h",
+        ]
+      }
       if (is_linux) {
         if (!is_chromeos) {
           # Desktop linux.
@@ -2001,10 +2010,8 @@
     # TODO(crbug.com/679127): Enable these tests on "mac_views_browser" once it
     # is supported.
     if (is_linux || is_win) {
-      sources += [
-        "../browser/payments/payment_request_web_contents_manager_browsertest.cc",
-        "../browser/payments/site_per_process_payments_browsertest.cc",
-      ]
+      sources +=
+          [ "../browser/payments/site_per_process_payments_browsertest.cc" ]
     }
 
     if (!enable_one_click_signin) {
diff --git a/components/autofill/core/browser/webdata/autocomplete_sync_bridge.cc b/components/autofill/core/browser/webdata/autocomplete_sync_bridge.cc
index 12702868..e569609 100644
--- a/components/autofill/core/browser/webdata/autocomplete_sync_bridge.cc
+++ b/components/autofill/core/browser/webdata/autocomplete_sync_bridge.cc
@@ -293,6 +293,8 @@
   DCHECK(web_data_backend_);
 
   scoped_observer_.Add(web_data_backend_);
+
+  LoadMetadata();
 }
 
 AutocompleteSyncBridge::~AutocompleteSyncBridge() {
@@ -390,6 +392,55 @@
   callback.Run(std::move(batch));
 }
 
+void AutocompleteSyncBridge::ActOnLocalChanges(
+    const AutofillChangeList& changes) {
+  if (!change_processor()->IsTrackingMetadata()) {
+    return;
+  }
+
+  auto metadata_change_list = base::MakeUnique<AutofillMetadataChangeList>(
+      GetAutofillTable(), syncer::AUTOFILL);
+  for (const auto& change : changes) {
+    const std::string storage_key = GetStorageKeyFromModel(change.key());
+    switch (change.type()) {
+      case AutofillChange::ADD:
+      case AutofillChange::UPDATE: {
+        base::Time date_created, date_last_used;
+        bool success = GetAutofillTable()->GetAutofillTimestamps(
+            change.key().name(), change.key().value(), &date_created,
+            &date_last_used);
+        if (!success) {
+          change_processor()->ReportError(
+              FROM_HERE, "Failed reading autofill entry from WebDatabase.");
+          return;
+        }
+
+        const AutofillEntry entry(change.key(), date_created, date_last_used);
+        change_processor()->Put(storage_key, CreateEntityData(entry),
+                                metadata_change_list.get());
+        break;
+      }
+      case AutofillChange::REMOVE: {
+        change_processor()->Delete(storage_key, metadata_change_list.get());
+        break;
+      }
+    }
+  }
+
+  if (Optional<ModelError> error = metadata_change_list->TakeError())
+    change_processor()->ReportError(error.value());
+}
+
+void AutocompleteSyncBridge::LoadMetadata() {
+  auto batch = base::MakeUnique<syncer::MetadataBatch>();
+  if (!GetAutofillTable()->GetAllSyncMetadata(syncer::AUTOFILL, batch.get())) {
+    change_processor()->ReportError(
+        FROM_HERE, "Failed reading autofill metadata from WebDatabase.");
+    return;
+  }
+  change_processor()->ModelReadyToSync(std::move(batch));
+}
+
 std::string AutocompleteSyncBridge::GetClientTag(
     const EntityData& entity_data) {
   DCHECK(entity_data.specifics.has_autofill());
@@ -411,6 +462,7 @@
 void AutocompleteSyncBridge::AutofillEntriesChanged(
     const AutofillChangeList& changes) {
   DCHECK(thread_checker_.CalledOnValidThread());
+  ActOnLocalChanges(changes);
 }
 
 AutofillTable* AutocompleteSyncBridge::GetAutofillTable() const {
diff --git a/components/autofill/core/browser/webdata/autocomplete_sync_bridge.h b/components/autofill/core/browser/webdata/autocomplete_sync_bridge.h
index 9629858..cd350be 100644
--- a/components/autofill/core/browser/webdata/autocomplete_sync_bridge.h
+++ b/components/autofill/core/browser/webdata/autocomplete_sync_bridge.h
@@ -42,7 +42,7 @@
   static AutocompleteSyncBridge* FromWebDataService(
       AutofillWebDataService* web_data_service);
 
-  // syncer::ModelTypeService implementation.
+  // syncer::ModelTypeSyncBridge implementation.
   std::unique_ptr<syncer::MetadataChangeList> CreateMetadataChangeList()
       override;
   base::Optional<syncer::ModelError> MergeSyncData(
@@ -70,11 +70,13 @@
   // Returns the table associated with the |web_data_backend_|.
   AutofillTable* GetAutofillTable() const;
 
-  std::string GetStorageKeyFromAutofillEntry(
-      const autofill::AutofillEntry& entry);
+  // Respond to local autofill entries changing by notifying sync of the
+  // changes.
+  void ActOnLocalChanges(const AutofillChangeList& changes);
 
-  static std::string FormatStorageKey(const std::string& name,
-                                      const std::string& value);
+  // Synchronously load sync metadata from the autofill table and pass it to the
+  // processor so that it can start tracking changes.
+  void LoadMetadata();
 
   base::ThreadChecker thread_checker_;
 
diff --git a/components/autofill/core/browser/webdata/autocomplete_sync_bridge_unittest.cc b/components/autofill/core/browser/webdata/autocomplete_sync_bridge_unittest.cc
index 515b8748..b12d0ef 100644
--- a/components/autofill/core/browser/webdata/autocomplete_sync_bridge_unittest.cc
+++ b/components/autofill/core/browser/webdata/autocomplete_sync_bridge_unittest.cc
@@ -16,18 +16,22 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/thread_task_runner_handle.h"
+#include "base/time/time.h"
+#include "components/autofill/core/browser/webdata/autofill_entry.h"
 #include "components/autofill/core/browser/webdata/autofill_table.h"
 #include "components/autofill/core/browser/webdata/autofill_webdata_backend.h"
-#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
+#include "components/autofill/core/browser/webdata/autofill_webdata_backend_impl.h"
 #include "components/sync/model/data_batch.h"
-#include "components/sync/model/fake_model_type_change_processor.h"
 #include "components/sync/model/metadata_batch.h"
 #include "components/sync/model/model_error.h"
+#include "components/sync/model/recording_model_type_change_processor.h"
 #include "components/webdata/common/web_database.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+using base::UTF8ToUTF16;
 using base::ScopedTempDir;
 using base::Time;
+using base::TimeDelta;
 using sync_pb::AutofillSpecifics;
 using sync_pb::EntitySpecifics;
 using syncer::DataBatch;
@@ -79,16 +83,9 @@
   EXPECT_TRUE(expected.empty());
 }
 
-std::unique_ptr<ModelTypeChangeProcessor> CreateModelTypeChangeProcessor(
-    ModelType type,
-    ModelTypeSyncBridge* bridge) {
-  return base::MakeUnique<FakeModelTypeChangeProcessor>();
-}
-
-AutofillEntry CreateAutofillEntry(
-    const sync_pb::AutofillSpecifics& autofill_specifics) {
-  AutofillKey key(base::UTF8ToUTF16(autofill_specifics.name()),
-                  base::UTF8ToUTF16(autofill_specifics.value()));
+AutofillEntry CreateAutofillEntry(const AutofillSpecifics& autofill_specifics) {
+  AutofillKey key(UTF8ToUTF16(autofill_specifics.name()),
+                  UTF8ToUTF16(autofill_specifics.value()));
   Time date_created, date_last_used;
   const google::protobuf::RepeatedField<int64_t>& timestamps =
       autofill_specifics.usage_timestamp();
@@ -99,7 +96,6 @@
   return AutofillEntry(key, date_created, date_last_used);
 }
 
-// Creates an EntityData/EntityDataPtr around a copy of the given specifics.
 EntityDataPtr SpecificsToEntity(const AutofillSpecifics& specifics) {
   EntityData data;
   data.client_tag_hash = "ignored";
@@ -135,15 +131,19 @@
       db_.Init(temp_dir_.GetPath().AppendASCII("SyncTestWebDatabase"));
       backend_.SetWebDatabase(&db_);
 
+      sync_pb::ModelTypeState model_type_state;
+      model_type_state.set_initial_sync_done(true);
+      table_.UpdateModelTypeState(syncer::AUTOFILL, model_type_state);
+
       bridge_.reset(new AutocompleteSyncBridge(
-          &backend_, base::Bind(&CreateModelTypeChangeProcessor)));
+          &backend_,
+          base::Bind(
+              &AutocompleteSyncBridgeTest::CreateModelTypeChangeProcessor,
+              base::Unretained(this))));
     }
   }
   ~AutocompleteSyncBridgeTest() override {}
 
- protected:
-  AutocompleteSyncBridge* bridge() { return bridge_.get(); }
-
   void SaveSpecificsToTable(
       const std::vector<AutofillSpecifics>& specifics_list) {
     std::vector<AutofillEntry> new_entries;
@@ -217,13 +217,49 @@
     bridge()->GetAllData(base::Bind(&VerifyDataBatch, ExpectedMap(expected)));
   }
 
+  void VerifyProcessorRecordedPut(const AutofillSpecifics& specifics,
+                                  int position = 0) {
+    const std::string storage_key = GetStorageKey(specifics);
+    auto recorded_specifics_iterator =
+        processor()->put_multimap().find(storage_key);
+
+    EXPECT_NE(processor()->put_multimap().end(), recorded_specifics_iterator);
+    while (position > 0) {
+      recorded_specifics_iterator++;
+      EXPECT_NE(processor()->put_multimap().end(), recorded_specifics_iterator);
+      position--;
+    }
+
+    AutofillSpecifics recorded_specifics =
+        recorded_specifics_iterator->second->specifics.autofill();
+    VerifyEqual(recorded_specifics, specifics);
+  }
+
+  AutocompleteSyncBridge* bridge() { return bridge_.get(); }
+
+  syncer::RecordingModelTypeChangeProcessor* processor() { return processor_; }
+
+  AutofillTable* table() { return &table_; }
+
  private:
+  std::unique_ptr<syncer::ModelTypeChangeProcessor>
+  CreateModelTypeChangeProcessor(syncer::ModelType type,
+                                 syncer::ModelTypeSyncBridge* bridge) {
+    auto processor =
+        base::MakeUnique<syncer::RecordingModelTypeChangeProcessor>();
+    processor_ = processor.get();
+    return std::move(processor);
+  }
+
   ScopedTempDir temp_dir_;
   base::MessageLoop message_loop_;
   FakeAutofillBackend backend_;
   AutofillTable table_;
   WebDatabase db_;
   std::unique_ptr<AutocompleteSyncBridge> bridge_;
+  // A non-owning pointer to the processor given to the bridge. Will be null
+  // before being given to the bridge, to make ownership easier.
+  syncer::RecordingModelTypeChangeProcessor* processor_ = nullptr;
 
   DISALLOW_COPY_AND_ASSIGN(AutocompleteSyncBridgeTest);
 };
@@ -426,4 +462,63 @@
   // making db calls and verify the errors are propagated up.
 }
 
+TEST_F(AutocompleteSyncBridgeTest, LocalEntriesAdded) {
+  const AutofillSpecifics added_specifics1 = CreateSpecifics(1, {2, 3});
+  const AutofillSpecifics added_specifics2 = CreateSpecifics(2, {2, 3});
+
+  const AutofillEntry added_entry1 = CreateAutofillEntry(added_specifics1);
+  const AutofillEntry added_entry2 = CreateAutofillEntry(added_specifics2);
+
+  table()->UpdateAutofillEntries({added_entry1, added_entry2});
+
+  bridge()->AutofillEntriesChanged(
+      {AutofillChange(AutofillChange::ADD, added_entry1.key()),
+       AutofillChange(AutofillChange::ADD, added_entry2.key())});
+
+  EXPECT_EQ(2u, processor()->put_multimap().size());
+
+  VerifyProcessorRecordedPut(added_specifics1);
+  VerifyProcessorRecordedPut(added_specifics2);
+}
+
+TEST_F(AutocompleteSyncBridgeTest, LocalEntryAddedThenUpdated) {
+  const AutofillSpecifics added_specifics = CreateSpecifics(1, {2, 3});
+  const AutofillEntry added_entry = CreateAutofillEntry(added_specifics);
+  table()->UpdateAutofillEntries({added_entry});
+
+  bridge()->AutofillEntriesChanged(
+      {AutofillChange(AutofillChange::ADD, added_entry.key())});
+
+  EXPECT_EQ(1u, processor()->put_multimap().size());
+
+  VerifyProcessorRecordedPut(added_specifics);
+
+  const AutofillSpecifics updated_specifics = CreateSpecifics(1, {2, 4});
+  const AutofillEntry updated_entry = CreateAutofillEntry(updated_specifics);
+  table()->UpdateAutofillEntries({updated_entry});
+
+  bridge()->AutofillEntriesChanged(
+      {AutofillChange(AutofillChange::UPDATE, updated_entry.key())});
+
+  VerifyProcessorRecordedPut(updated_specifics, 1);
+}
+
+TEST_F(AutocompleteSyncBridgeTest, LocalEntryDeleted) {
+  const AutofillSpecifics deleted_specifics = CreateSpecifics(1, {2, 3});
+  const AutofillEntry deleted_entry = CreateAutofillEntry(deleted_specifics);
+  const std::string storage_key = GetStorageKey(deleted_specifics);
+
+  bridge()->AutofillEntriesChanged(
+      {AutofillChange(AutofillChange::REMOVE, deleted_entry.key())});
+
+  EXPECT_EQ(1u, processor()->delete_set().size());
+  EXPECT_NE(processor()->delete_set().end(),
+            processor()->delete_set().find(storage_key));
+}
+
+TEST_F(AutocompleteSyncBridgeTest, LoadMetadataCalled) {
+  EXPECT_NE(processor()->metadata(), nullptr);
+  EXPECT_TRUE(processor()->metadata()->GetModelTypeState().initial_sync_done());
+}
+
 }  // namespace autofill
diff --git a/components/browser_sync/profile_sync_service.cc b/components/browser_sync/profile_sync_service.cc
index bccbad7..adb1b1ed 100644
--- a/components/browser_sync/profile_sync_service.cc
+++ b/components/browser_sync/profile_sync_service.cc
@@ -1446,6 +1446,7 @@
 void ProfileSyncService::OnConfigureStart() {
   DCHECK(thread_checker_.CalledOnValidThread());
   sync_configure_start_time_ = base::Time::Now();
+  engine_->StartConfiguration();
   NotifyObservers();
 }
 
diff --git a/components/cryptauth/BUILD.gn b/components/cryptauth/BUILD.gn
index 6093685..e8e14798 100644
--- a/components/cryptauth/BUILD.gn
+++ b/components/cryptauth/BUILD.gn
@@ -132,6 +132,7 @@
     ":cryptauth",
     ":test_support",
     "//base/test:test_support",
+    "//components/cryptauth/ble:unit_tests",
     "//components/gcm_driver:test_support",
     "//components/prefs:test_support",
     "//google_apis:test_support",
diff --git a/components/cryptauth/ble/bluetooth_low_energy_weave_client_connection_unittest.cc b/components/cryptauth/ble/bluetooth_low_energy_weave_client_connection_unittest.cc
index c8b69df..e0dc88d1 100644
--- a/components/cryptauth/ble/bluetooth_low_energy_weave_client_connection_unittest.cc
+++ b/components/cryptauth/ble/bluetooth_low_energy_weave_client_connection_unittest.cc
@@ -40,6 +40,8 @@
 namespace cryptauth {
 namespace {
 
+const std::string kTestFeature = "testFeature";
+
 class MockBluetoothThrottler : public BluetoothThrottler {
  public:
   MockBluetoothThrottler() {}
@@ -175,10 +177,11 @@
   void SetMaxPacketSize(uint16_t size) override { max_packet_size_ = size; }
 
   std::vector<Packet> EncodeDataMessage(std::string message) override {
-    if (message == kSmallMessage && max_packet_size_ == kDefaultMaxPacketSize) {
+    if (message == (kTestFeature + "," + kSmallMessage)
+        && max_packet_size_ == kDefaultMaxPacketSize) {
       return kSmallPackets;
-    } else if (message == kLargeMessage &&
-               max_packet_size_ == kLargeMaxPacketSize) {
+    } else if (message == (kTestFeature + "," + kLargeMessage)
+          && max_packet_size_ == kLargeMaxPacketSize) {
       return kLargePackets;
     } else {
       NOTREACHED();
@@ -350,7 +353,6 @@
         notify_session_alias_(NULL),
         bluetooth_throttler_(new NiceMock<MockBluetoothThrottler>),
         task_runner_(new base::TestSimpleTaskRunner),
-        last_completed_wire_message_(""),
         generator_factory_(
             new MockBluetoothLowEnergyWeavePacketGeneratorFactory()),
         receiver_factory_(
@@ -599,7 +601,6 @@
   std::unique_ptr<MockBluetoothThrottler> bluetooth_throttler_;
   scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
   base::MessageLoop message_loop_;
-  WireMessage last_completed_wire_message_;
   bool last_wire_message_success_;
   std::shared_ptr<MockBluetoothLowEnergyWeavePacketGeneratorFactory>
       generator_factory_;
@@ -806,7 +807,8 @@
                 SaveArg<1>(&write_remote_characteristic_success_callback_),
                 SaveArg<2>(&write_remote_characteristic_error_callback_)));
 
-  connection->SendMessage(base::MakeUnique<FakeWireMessage>(kSmallMessage));
+  connection->SendMessage(
+      base::MakeUnique<FakeWireMessage>(kSmallMessage, kTestFeature));
 
   EXPECT_EQ(last_value_written_on_tx_characteristic_, kSmallPackets0);
 
@@ -832,7 +834,8 @@
                 SaveArg<1>(&write_remote_characteristic_success_callback_),
                 SaveArg<2>(&write_remote_characteristic_error_callback_)));
 
-  connection->SendMessage(base::MakeUnique<FakeWireMessage>(kLargeMessage));
+  connection->SendMessage(
+      base::MakeUnique<FakeWireMessage>(kLargeMessage, kTestFeature));
 
   EXPECT_EQ(last_value_written_on_tx_characteristic_, kLargePackets0);
   std::vector<uint8_t> bytes_received(
@@ -873,7 +876,8 @@
                 SaveArg<1>(&write_remote_characteristic_success_callback_),
                 SaveArg<2>(&write_remote_characteristic_error_callback_)));
 
-  connection->SendMessage(base::MakeUnique<FakeWireMessage>(kSmallMessage));
+  connection->SendMessage(
+      base::MakeUnique<FakeWireMessage>(kSmallMessage, kTestFeature));
 
   for (int i = 0; i < kMaxNumberOfTries; i++) {
     EXPECT_EQ(last_value_written_on_tx_characteristic_, kSmallPackets0);
@@ -949,7 +953,8 @@
                 SaveArg<1>(&write_remote_characteristic_success_callback_),
                 SaveArg<2>(&write_remote_characteristic_error_callback_)));
 
-  connection->SendMessage(base::MakeUnique<FakeWireMessage>(kLargeMessage));
+  connection->SendMessage(
+      base::MakeUnique<FakeWireMessage>(kLargeMessage, kTestFeature));
 
   connection->GattCharacteristicValueChanged(
       adapter_.get(), rx_characteristic_.get(), kErroneousPacket);
diff --git a/components/cryptauth/ble/fake_wire_message.cc b/components/cryptauth/ble/fake_wire_message.cc
index 31ea442..8853299 100644
--- a/components/cryptauth/ble/fake_wire_message.cc
+++ b/components/cryptauth/ble/fake_wire_message.cc
@@ -12,18 +12,12 @@
 
 namespace cryptauth {
 
-FakeWireMessage::FakeWireMessage(const std::string& payload)
-    : WireMessage(payload) {}
-
-std::unique_ptr<FakeWireMessage> FakeWireMessage::Deserialize(
-    const std::string& serialized_message,
-    bool* is_incomplete_message) {
-  *is_incomplete_message = false;
-  return std::unique_ptr<FakeWireMessage>(
-      new FakeWireMessage(serialized_message));
-}
+FakeWireMessage::FakeWireMessage(
+    const std::string& payload, const std::string& feature)
+    : WireMessage(payload, feature) {}
 
 std::string FakeWireMessage::Serialize() const {
-  return std::string(payload());
+  return feature() + "," + payload();
 }
+
 }
diff --git a/components/cryptauth/ble/fake_wire_message.h b/components/cryptauth/ble/fake_wire_message.h
index 85cb82b..aa179e0 100644
--- a/components/cryptauth/ble/fake_wire_message.h
+++ b/components/cryptauth/ble/fake_wire_message.h
@@ -15,17 +15,15 @@
 
 class FakeWireMessage : public WireMessage {
  public:
-  FakeWireMessage(const std::string& payload);
+  FakeWireMessage(const std::string& payload, const std::string& feature);
 
-  static std::unique_ptr<FakeWireMessage> Deserialize(
-      const std::string& serialized_message,
-      bool* is_incomplete_message);
-
+  // WireMessage:
   std::string Serialize() const override;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(FakeWireMessage);
 };
-}
+
+}  // namespace cryptauth
 
 #endif  // COMPONENTS_CRYPTAUTH_WIRE_MESSAGE_H
diff --git a/components/cryptauth/connection_unittest.cc b/components/cryptauth/connection_unittest.cc
index 82e09c2..4d66fc4 100644
--- a/components/cryptauth/connection_unittest.cc
+++ b/components/cryptauth/connection_unittest.cc
@@ -78,7 +78,7 @@
 // Unlike WireMessage, offers a public constructor.
 class TestWireMessage : public WireMessage {
  public:
-  TestWireMessage() : WireMessage(std::string()) {}
+  TestWireMessage() : WireMessage("payload", "feature") {}
   ~TestWireMessage() override {}
 
  private:
diff --git a/components/cryptauth/fake_connection.cc b/components/cryptauth/fake_connection.cc
index 650f62e..c5008fce 100644
--- a/components/cryptauth/fake_connection.cc
+++ b/components/cryptauth/fake_connection.cc
@@ -11,6 +11,10 @@
 
 namespace cryptauth {
 
+namespace {
+const char kFakeFeatureName[] = "fakeFeature";
+}  // namespace
+
 FakeConnection::FakeConnection(const cryptauth::RemoteDevice& remote_device)
     : Connection(remote_device) {
   Connect();
@@ -50,7 +54,8 @@
 std::unique_ptr<WireMessage> FakeConnection::DeserializeWireMessage(
     bool* is_incomplete_message) {
   *is_incomplete_message = false;
-  return base::MakeUnique<WireMessage>(pending_payload_);
+  return base::MakeUnique<WireMessage>(
+      pending_payload_, std::string(kFakeFeatureName));
 }
 
 }  // namespace cryptauth
diff --git a/components/cryptauth/wire_message.cc b/components/cryptauth/wire_message.cc
index 7b26d7d..b91b943 100644
--- a/components/cryptauth/wire_message.cc
+++ b/components/cryptauth/wire_message.cc
@@ -33,7 +33,14 @@
 const int kMessageFormatVersionThree = 3;
 
 const char kPayloadKey[] = "payload";
-const char kPermitIdKey[] = "permit_id";
+const char kFeatureKey[] = "feature";
+
+// The default feature value. This is the default for backward compatibility
+// reasons; previously, the protocol did not transmit the feature in the
+// message, but because EasyUnlock was the only feature used, it didn't matter.
+// So, if a message is received without a feature, it is assumed to be
+// EasyUnlock by default.
+const char kDefaultFeature[] = "easy_unlock";
 
 // Parses the |serialized_message|'s header. Returns |true| iff the message has
 // a valid header, is complete, and is well-formed according to the header. Sets
@@ -83,29 +90,24 @@
     const std::string& serialized_message,
     bool* is_incomplete_message) {
   if (!ParseHeader(serialized_message, is_incomplete_message))
-    return std::unique_ptr<WireMessage>();
+    return nullptr;
 
   std::unique_ptr<base::Value> body_value =
       base::JSONReader::Read(serialized_message.substr(kHeaderLength));
   if (!body_value || !body_value->IsType(base::Value::Type::DICTIONARY)) {
     PA_LOG(WARNING) << "Error: Unable to parse message as JSON.";
-    return std::unique_ptr<WireMessage>();
+    return nullptr;
   }
 
   base::DictionaryValue* body;
   bool success = body_value->GetAsDictionary(&body);
   DCHECK(success);
 
-  // The permit ID is optional. In the Easy Unlock protocol, only the first
-  // message includes this field.
-  std::string permit_id;
-  body->GetString(kPermitIdKey, &permit_id);
-
   std::string payload_base64;
   if (!body->GetString(kPayloadKey, &payload_base64) ||
       payload_base64.empty()) {
     PA_LOG(WARNING) << "Error: Missing payload.";
-    return std::unique_ptr<WireMessage>();
+    return nullptr;
   }
 
   std::string payload;
@@ -113,10 +115,15 @@
                              base::Base64UrlDecodePolicy::REQUIRE_PADDING,
                              &payload)) {
     PA_LOG(WARNING) << "Error: Invalid base64 encoding for payload.";
-    return std::unique_ptr<WireMessage>();
+    return nullptr;
   }
 
-  return base::WrapUnique(new WireMessage(payload, permit_id));
+  std::string feature;
+  if (!body->GetString(kFeatureKey, &feature) || feature.empty()) {
+    feature = std::string(kDefaultFeature);
+  }
+
+  return base::WrapUnique(new WireMessage(payload, feature));
 }
 
 std::string WireMessage::Serialize() const {
@@ -127,13 +134,12 @@
 
   // Create JSON body containing permit id and payload.
   base::DictionaryValue body;
-  if (!permit_id_.empty())
-    body.SetString(kPermitIdKey, permit_id_);
 
   std::string base64_payload;
   base::Base64UrlEncode(payload_, base::Base64UrlEncodePolicy::INCLUDE_PADDING,
                         &base64_payload);
   body.SetString(kPayloadKey, base64_payload);
+  body.SetString(kFeatureKey, feature_);
 
   std::string json_body;
   if (!base::JSONWriter::Write(body, &json_body)) {
@@ -161,11 +167,7 @@
   return header_string + json_body;
 }
 
-WireMessage::WireMessage(const std::string& payload)
-    : WireMessage(payload, std::string()) {}
-
-WireMessage::WireMessage(const std::string& payload,
-                         const std::string& permit_id)
-    : payload_(payload), permit_id_(permit_id) {}
+WireMessage::WireMessage(const std::string& payload, const std::string& feature)
+    : payload_(payload), feature_(feature) {}
 
 }  // namespace cryptauth
diff --git a/components/cryptauth/wire_message.h b/components/cryptauth/wire_message.h
index b691462..cbb34054 100644
--- a/components/cryptauth/wire_message.h
+++ b/components/cryptauth/wire_message.h
@@ -14,18 +14,15 @@
 
 class WireMessage {
  public:
-  // Creates a WireMessage containing |payload|.
-  explicit WireMessage(const std::string& payload);
-
-  // Creates a WireMessage containing |payload| and |permit_id| in the metadata.
-  WireMessage(const std::string& payload, const std::string& permit_id);
-
+  // Creates a WireMessage containing |payload| for feature |feature|.
+  explicit WireMessage(const std::string& payload, const std::string& feature);
   virtual ~WireMessage();
 
-  // Returns the deserialized message from |serialized_message|, or NULL if the
-  // message is malformed. Sets |is_incomplete_message| to true if the message
-  // does not have enough data to parse the header, or if the message length
-  // encoded in the message header exceeds the size of the |serialized_message|.
+  // Returns the deserialized message from |serialized_message|, or nullptr if
+  // the message is malformed. Sets |is_incomplete_message| to true if the
+  // message does not have enough data to parse the header, or if the message
+  // length encoded in the message header exceeds the size of the
+  // |serialized_message|.
   static std::unique_ptr<WireMessage> Deserialize(
       const std::string& serialized_message,
       bool* is_incomplete_message);
@@ -34,18 +31,15 @@
   virtual std::string Serialize() const;
 
   const std::string& payload() const { return payload_; }
-  const std::string& permit_id() const { return permit_id_; }
+  const std::string& feature() const { return feature_; }
 
  private:
   // The message payload.
   const std::string payload_;
 
-  // Identifier of the permit being used. A permit contains the credentials used
-  // to authenticate a device. For example, when sending a WireMessage to the
-  // remote device the |permit_id_| indexes a permit possibly containing the
-  // public key
-  // of the local device or a symmetric key shared between the devices.
-  const std::string permit_id_;
+  // The feature which sends or intends to receive this message (e.g.,
+  // EasyUnlock).
+  const std::string feature_;
 
   DISALLOW_COPY_AND_ASSIGN(WireMessage);
 };
diff --git a/components/cryptauth/wire_message_unittest.cc b/components/cryptauth/wire_message_unittest.cc
index 84dc625..7c7caca3 100644
--- a/components/cryptauth/wire_message_unittest.cc
+++ b/components/cryptauth/wire_message_unittest.cc
@@ -11,7 +11,16 @@
 
 namespace cryptauth {
 
-TEST(ProximityAuthWireMessage, Deserialize_EmptyMessage) {
+class CryptAuthWireMessageTest : public testing::Test {
+ protected:
+  CryptAuthWireMessageTest() {}
+  ~CryptAuthWireMessageTest() override {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(CryptAuthWireMessageTest);
+};
+
+TEST(CryptAuthWireMessageTest, Deserialize_EmptyMessage) {
   bool is_incomplete;
   std::unique_ptr<WireMessage> message =
       WireMessage::Deserialize(std::string(), &is_incomplete);
@@ -19,7 +28,7 @@
   EXPECT_FALSE(message);
 }
 
-TEST(ProximityAuthWireMessage, Deserialize_IncompleteHeader) {
+TEST(CryptAuthWireMessageTest, Deserialize_IncompleteHeader) {
   bool is_incomplete;
   std::unique_ptr<WireMessage> message =
       WireMessage::Deserialize("\3", &is_incomplete);
@@ -27,7 +36,7 @@
   EXPECT_FALSE(message);
 }
 
-TEST(ProximityAuthWireMessage, Deserialize_UnexpectedMessageFormatVersion) {
+TEST(CryptAuthWireMessageTest, Deserialize_UnexpectedMessageFormatVersion) {
   bool is_incomplete;
   // Version 2 is below the minimum supported version.
   std::unique_ptr<WireMessage> message =
@@ -36,7 +45,7 @@
   EXPECT_FALSE(message);
 }
 
-TEST(ProximityAuthWireMessage, Deserialize_BodyOfSizeZero) {
+TEST(CryptAuthWireMessageTest, Deserialize_BodyOfSizeZero) {
   bool is_incomplete;
   std::unique_ptr<WireMessage> message =
       WireMessage::Deserialize(std::string("\3\0\0", 3), &is_incomplete);
@@ -44,7 +53,7 @@
   EXPECT_FALSE(message);
 }
 
-TEST(ProximityAuthWireMessage, Deserialize_IncompleteBody) {
+TEST(CryptAuthWireMessageTest, Deserialize_IncompleteBody) {
   bool is_incomplete;
   std::unique_ptr<WireMessage> message =
       WireMessage::Deserialize(std::string("\3\0\5", 3), &is_incomplete);
@@ -52,7 +61,7 @@
   EXPECT_FALSE(message);
 }
 
-TEST(ProximityAuthWireMessage, Deserialize_BodyLongerThanSpecifiedInHeader) {
+TEST(CryptAuthWireMessageTest, Deserialize_BodyLongerThanSpecifiedInHeader) {
   bool is_incomplete;
   std::unique_ptr<WireMessage> message = WireMessage::Deserialize(
       std::string("\3\0\5", 3) + "123456", &is_incomplete);
@@ -60,7 +69,7 @@
   EXPECT_FALSE(message);
 }
 
-TEST(ProximityAuthWireMessage, Deserialize_BodyIsNotValidJSON) {
+TEST(CryptAuthWireMessageTest, Deserialize_BodyIsNotValidJSON) {
   bool is_incomplete;
   std::unique_ptr<WireMessage> message = WireMessage::Deserialize(
       std::string("\3\0\5", 3) + "12345", &is_incomplete);
@@ -68,122 +77,101 @@
   EXPECT_FALSE(message);
 }
 
-TEST(ProximityAuthWireMessage, Deserialize_BodyIsNotADictionary) {
+TEST(CryptAuthWireMessageTest, Deserialize_BodyIsNotADictionary) {
+  bool is_incomplete;
+  std::string header("\3\0\x15", 3);
+  std::string bytes =
+      header + "[{\"payload\": \"YQ==\"}]";
+  std::unique_ptr<WireMessage> message =
+      WireMessage::Deserialize(bytes, &is_incomplete);
+  EXPECT_FALSE(is_incomplete);
+  EXPECT_FALSE(message);
+}
+
+TEST(CryptAuthWireMessageTest, Deserialize_BodyLacksPayload) {
+  bool is_incomplete;
+  std::string header("\3\0\x02", 3);
+  std::string bytes = header + "{}";
+  std::unique_ptr<WireMessage> message =
+      WireMessage::Deserialize(bytes, &is_incomplete);
+  EXPECT_FALSE(is_incomplete);
+  EXPECT_FALSE(message);
+}
+
+TEST(CryptAuthWireMessageTest, Deserialize_BodyHasEmptyPayload) {
   bool is_incomplete;
   std::string header("\3\0\x29", 3);
+  std::string bytes = header
+      + "{\"payload\": \"\", \"feature\": \"testFeature\"}";
+  std::unique_ptr<WireMessage> message =
+      WireMessage::Deserialize(bytes, &is_incomplete);
+  EXPECT_FALSE(is_incomplete);
+  EXPECT_FALSE(message);
+}
+
+TEST(CryptAuthWireMessageTest, Deserialize_PayloadIsNotBase64Encoded) {
+  bool is_incomplete;
+  std::string header("\3\0\x30", 3);
   std::string bytes =
-      header + "[{\"permit_id\": \"Hi!\", \"payload\": \"YQ==\"}]";
+      header + "{\"payload\": \"garbage\", \"feature\": \"testFeature\"}";
   std::unique_ptr<WireMessage> message =
       WireMessage::Deserialize(bytes, &is_incomplete);
   EXPECT_FALSE(is_incomplete);
   EXPECT_FALSE(message);
 }
 
-// The permit ID is optional.
-TEST(ProximityAuthWireMessage, Deserialize_BodyLacksPermitId) {
+TEST(CryptAuthWireMessageTest, Deserialize_ValidMessage) {
   bool is_incomplete;
-  std::string header("\3\0\x13", 3);
-  std::string bytes = header + "{\"payload\": \"YQ==\"}";
-  std::unique_ptr<WireMessage> message =
-      WireMessage::Deserialize(bytes, &is_incomplete);
-  EXPECT_FALSE(is_incomplete);
-  EXPECT_TRUE(message);
-  EXPECT_EQ(std::string(), message->permit_id());
-  EXPECT_EQ("a", message->payload());
-}
-
-TEST(ProximityAuthWireMessage, Deserialize_BodyLacksPayload) {
-  bool is_incomplete;
-  std::string header("\3\0\x14", 3);
-  std::string bytes = header + "{\"permit_id\": \"Hi!\"}";
-  std::unique_ptr<WireMessage> message =
-      WireMessage::Deserialize(bytes, &is_incomplete);
-  EXPECT_FALSE(is_incomplete);
-  EXPECT_FALSE(message);
-}
-
-// The permit ID is optional.
-TEST(ProximityAuthWireMessage, Deserialize_BodyHasEmptyPermitId) {
-  bool is_incomplete;
-  std::string header("\3\0\x24", 3);
-  std::string bytes = header + "{\"permit_id\": \"\", \"payload\": \"YQ==\"}";
-  std::unique_ptr<WireMessage> message =
-      WireMessage::Deserialize(bytes, &is_incomplete);
-  EXPECT_FALSE(is_incomplete);
-  EXPECT_TRUE(message);
-  EXPECT_EQ(std::string(), message->permit_id());
-  EXPECT_EQ("a", message->payload());
-}
-
-TEST(ProximityAuthWireMessage, Deserialize_BodyHasEmptyPayload) {
-  bool is_incomplete;
-  std::string header("\3\0\x23", 3);
-  std::string bytes = header + "{\"permit_id\": \"Hi!\", \"payload\": \"\"}";
-  std::unique_ptr<WireMessage> message =
-      WireMessage::Deserialize(bytes, &is_incomplete);
-  EXPECT_FALSE(is_incomplete);
-  EXPECT_FALSE(message);
-}
-
-TEST(ProximityAuthWireMessage, Deserialize_PayloadIsNotBase64Encoded) {
-  bool is_incomplete;
-  std::string header("\3\0\x2A", 3);
+  std::string header("\3\0\x2d", 3);
   std::string bytes =
-      header + "{\"permit_id\": \"Hi!\", \"payload\": \"garbage\"}";
-  std::unique_ptr<WireMessage> message =
-      WireMessage::Deserialize(bytes, &is_incomplete);
-  EXPECT_FALSE(is_incomplete);
-  EXPECT_FALSE(message);
-}
-
-TEST(ProximityAuthWireMessage, Deserialize_ValidMessage) {
-  bool is_incomplete;
-  std::string header("\3\0\x27", 3);
-  std::string bytes =
-      header + "{\"permit_id\": \"Hi!\", \"payload\": \"YQ==\"}";
+      header + "{\"payload\": \"YQ==\", \"feature\": \"testFeature\"}";
   std::unique_ptr<WireMessage> message =
       WireMessage::Deserialize(bytes, &is_incomplete);
   EXPECT_FALSE(is_incomplete);
   ASSERT_TRUE(message);
-  EXPECT_EQ("Hi!", message->permit_id());
   EXPECT_EQ("a", message->payload());
+  EXPECT_EQ("testFeature", message->feature());
 }
 
-TEST(ProximityAuthWireMessage, Deserialize_ValidMessageWithBase64UrlEncoding) {
+TEST(CryptAuthWireMessageTest, Deserialize_ValidMessageWithBase64UrlEncoding) {
   bool is_incomplete;
-  std::string header("\3\0\x27", 3);
+  std::string header("\3\0\x2d", 3);
   std::string bytes =
-      header + "{\"permit_id\": \"Hi!\", \"payload\": \"_-Y=\"}";
+      header + "{\"payload\": \"_-Y=\", \"feature\": \"testFeature\"}";
   std::unique_ptr<WireMessage> message =
       WireMessage::Deserialize(bytes, &is_incomplete);
   EXPECT_FALSE(is_incomplete);
   ASSERT_TRUE(message);
-  EXPECT_EQ("Hi!", message->permit_id());
   EXPECT_EQ("\xFF\xE6", message->payload());
+  EXPECT_EQ("testFeature", message->feature());
 }
 
-TEST(ProximityAuthWireMessage, Deserialize_ValidMessageWithExtraUnknownFields) {
+TEST(CryptAuthWireMessageTest, Deserialize_ValidMessageWithExtraUnknownFields) {
   bool is_incomplete;
-  std::string header("\3\0\x46", 3);
+  std::string header("\3\0\x4c", 3);
   std::string bytes = header +
                       "{"
-                      "  \"permit_id\": \"Hi!\","
                       "  \"payload\": \"YQ==\","
+                      "  \"feature\": \"testFeature\","
                       "  \"unexpected\": \"surprise!\""
                       "}";
   std::unique_ptr<WireMessage> message =
       WireMessage::Deserialize(bytes, &is_incomplete);
   EXPECT_FALSE(is_incomplete);
   ASSERT_TRUE(message);
-  EXPECT_EQ("Hi!", message->permit_id());
   EXPECT_EQ("a", message->payload());
+  EXPECT_EQ("testFeature", message->feature());
 }
 
-TEST(ProximityAuthWireMessage, Deserialize_SizeEquals0x01FF) {
+TEST(CryptAuthWireMessageTest, Deserialize_SizeEquals0x01FF) {
   // Create a message with a body of 0x01FF bytes to test the size contained in
   // the header is parsed correctly.
   std::string header("\3\x01\xff", 3);
-  char json_template[] = "{\"payload\":\"YQ==\", \"filler\":\"$1\"}";
+  char json_template[] = "{"
+                         "  \"payload\":\"YQ==\","
+                         "  \"feature\": \"testFeature\","
+                         "  \"filler\":\"$1\""
+                         "}";
   // Add 3 to the size to take into account the "$1" and NUL terminator ("\0")
   // characters in |json_template|.
   uint16_t filler_size = 0x01ff - sizeof(json_template) + 3;
@@ -199,37 +187,25 @@
   EXPECT_FALSE(is_incomplete);
   ASSERT_TRUE(message);
   EXPECT_EQ("a", message->payload());
+  EXPECT_EQ("testFeature", message->feature());
 }
 
-TEST(ProximityAuthWireMessage, Serialize_WithPermitId) {
-  WireMessage message1("example payload", "example id");
-  std::string bytes = message1.Serialize();
-  ASSERT_FALSE(bytes.empty());
-
+TEST(CryptAuthWireMessageTest, Serialize_WithoutFeature) {
   bool is_incomplete;
-  std::unique_ptr<WireMessage> message2 =
+  std::string header("\3\0\x13", 3);
+  std::string bytes = header + "{\"payload\": \"YQ==\"}";
+  std::unique_ptr<WireMessage> message =
       WireMessage::Deserialize(bytes, &is_incomplete);
   EXPECT_FALSE(is_incomplete);
-  ASSERT_TRUE(message2);
-  EXPECT_EQ("example id", message2->permit_id());
-  EXPECT_EQ("example payload", message2->payload());
+  EXPECT_TRUE(message);
+  EXPECT_EQ("a", message->payload());
+
+  // If unspecified, the default feature is "easy_unlock" for backwards
+  // compatibility.
+  EXPECT_EQ("easy_unlock", message->feature());
 }
 
-TEST(ProximityAuthWireMessage, Serialize_WithoutPermitId) {
-  WireMessage message1("example payload");
-  std::string bytes = message1.Serialize();
-  ASSERT_FALSE(bytes.empty());
-
-  bool is_incomplete;
-  std::unique_ptr<WireMessage> message2 =
-      WireMessage::Deserialize(bytes, &is_incomplete);
-  EXPECT_FALSE(is_incomplete);
-  ASSERT_TRUE(message2);
-  EXPECT_EQ(std::string(), message2->permit_id());
-  EXPECT_EQ("example payload", message2->payload());
-}
-
-TEST(ProximityAuthWireMessage, Serialize_FailsWithoutPayload) {
+TEST(CryptAuthWireMessageTest, Serialize_FailsWithoutPayload) {
   WireMessage message1(std::string(), "example id");
   std::string bytes = message1.Serialize();
   EXPECT_TRUE(bytes.empty());
diff --git a/components/password_manager/content/browser/credential_manager_impl.cc b/components/password_manager/content/browser/credential_manager_impl.cc
index 3f7a88e7..7c01bea 100644
--- a/components/password_manager/content/browser/credential_manager_impl.cc
+++ b/components/password_manager/content/browser/credential_manager_impl.cc
@@ -16,6 +16,7 @@
 #include "components/password_manager/content/browser/content_password_manager_driver_factory.h"
 #include "components/password_manager/core/browser/affiliated_match_helper.h"
 #include "components/password_manager/core/browser/credential_manager_logger.h"
+#include "components/password_manager/core/browser/form_fetcher_impl.h"
 #include "components/password_manager/core/browser/form_saver.h"
 #include "components/password_manager/core/browser/password_manager_client.h"
 #include "components/password_manager/core/browser/password_manager_metrics_util.h"
@@ -76,9 +77,14 @@
   std::unique_ptr<autofill::PasswordForm> form(
       CreatePasswordFormFromCredentialInfo(credential, origin));
 
+  std::unique_ptr<autofill::PasswordForm> observed_form =
+      CreateObservedPasswordFormFromOrigin(origin);
+  // Create a custom form fetcher with suppressed HTTP->HTTPS migration.
+  auto form_fetcher = base::MakeUnique<FormFetcherImpl>(
+      PasswordStore::FormDigest(*observed_form), client_, false);
   form_manager_ = base::MakeUnique<CredentialManagerPasswordFormManager>(
-      client_, GetDriver(), *CreateObservedPasswordFormFromOrigin(origin),
-      std::move(form), this, nullptr, nullptr);
+      client_, GetDriver(), *observed_form, std::move(form), this, nullptr,
+      std::move(form_fetcher));
 }
 
 void CredentialManagerImpl::OnProvisionalSaveComplete() {
diff --git a/components/password_manager/content/browser/credential_manager_impl_unittest.cc b/components/password_manager/content/browser/credential_manager_impl_unittest.cc
index 887fb91..103f830 100644
--- a/components/password_manager/content/browser/credential_manager_impl_unittest.cc
+++ b/components/password_manager/content/browser/credential_manager_impl_unittest.cc
@@ -35,6 +35,8 @@
 #include "content/public/test/test_renderer_host.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+#include "url/url_constants.h"
 
 using content::BrowserContext;
 using content::WebContents;
@@ -197,6 +199,12 @@
   *out_info = info;
 }
 
+GURL HttpURLFromHttps(const GURL& https_url) {
+  GURL::Replacements rep;
+  rep.SetSchemeStr(url::kHttpScheme);
+  return https_url.ReplaceComponents(rep);
+}
+
 }  // namespace
 
 class CredentialManagerImplTest : public content::RenderViewHostTestHarness {
@@ -1393,15 +1401,23 @@
   // in.
   store_->AddLogin(affiliated_form1_);
 
-  auto mock_helper = base::WrapUnique(new MockAffiliatedMatchHelper);
-  store_->SetAffiliatedMatchHelper(std::move(mock_helper));
+  store_->SetAffiliatedMatchHelper(
+      base::MakeUnique<MockAffiliatedMatchHelper>());
+
+  std::vector<std::string> affiliated_realms;
+  PasswordStore::FormDigest digest =
+      cm_service_impl_->GetSynthesizedFormForOrigin();
+  // First expect affiliations for the HTTPS domain.
+  static_cast<MockAffiliatedMatchHelper*>(store_->affiliated_match_helper())
+      ->ExpectCallToGetAffiliatedAndroidRealms(digest, affiliated_realms);
+
+  digest.origin = HttpURLFromHttps(digest.origin);
+  digest.signon_realm = digest.origin.spec();
+  // The second call happens for HTTP as the migration is triggered.
+  static_cast<MockAffiliatedMatchHelper*>(store_->affiliated_match_helper())
+      ->ExpectCallToGetAffiliatedAndroidRealms(digest, affiliated_realms);
 
   std::vector<GURL> federations;
-  std::vector<std::string> affiliated_realms;
-  static_cast<MockAffiliatedMatchHelper*>(store_->affiliated_match_helper())
-      ->ExpectCallToGetAffiliatedAndroidRealms(
-          cm_service_impl_->GetSynthesizedFormForOrigin(), affiliated_realms);
-
   ExpectZeroClickSignInFailure(true, true, federations);
 }
 
@@ -1446,6 +1462,20 @@
                                CredentialType::CREDENTIAL_TYPE_FEDERATED);
 }
 
+TEST_F(CredentialManagerImplTest, ZeroClickAfterMigratingHttpCredential) {
+  // There is an http credential saved. It should be migrated and used for auto
+  // sign-in.
+  form_.origin = HttpURLFromHttps(form_.origin);
+  form_.signon_realm = form_.origin.GetOrigin().spec();
+  // That is the default value for old credentials.
+  form_.skip_zero_click = true;
+  store_->AddLogin(form_);
+
+  std::vector<GURL> federations;
+  ExpectZeroClickSignInSuccess(true, true, federations,
+                               CredentialType::CREDENTIAL_TYPE_PASSWORD);
+}
+
 TEST_F(CredentialManagerImplTest, GetSynthesizedFormForOrigin) {
   PasswordStore::FormDigest synthesized =
       cm_service_impl_->GetSynthesizedFormForOrigin();
diff --git a/components/password_manager/core/browser/credential_manager_password_form_manager.cc b/components/password_manager/core/browser/credential_manager_password_form_manager.cc
index 38224508..0677a17f 100644
--- a/components/password_manager/core/browser/credential_manager_password_form_manager.cc
+++ b/components/password_manager/core/browser/credential_manager_password_form_manager.cc
@@ -26,7 +26,7 @@
     std::unique_ptr<autofill::PasswordForm> saved_form,
     CredentialManagerPasswordFormManagerDelegate* delegate,
     std::unique_ptr<FormSaver> form_saver,
-    FormFetcher* form_fetcher)
+    std::unique_ptr<FormFetcher> form_fetcher)
     : PasswordFormManager(driver->GetPasswordManager(),
                           client,
                           driver,
@@ -34,11 +34,15 @@
                           (form_saver ? std::move(form_saver)
                                       : base::MakeUnique<FormSaverImpl>(
                                             client->GetPasswordStore())),
-                          form_fetcher),
+                          form_fetcher.get()),
       delegate_(delegate),
       saved_form_(std::move(saved_form)),
+      form_fetcher_(std::move(form_fetcher)),
       weak_factory_(this) {
   DCHECK(saved_form_);
+  // This condition is only false on iOS.
+  if (form_fetcher_)
+    form_fetcher_->Fetch();
 }
 
 CredentialManagerPasswordFormManager::~CredentialManagerPasswordFormManager() {
diff --git a/components/password_manager/core/browser/credential_manager_password_form_manager.h b/components/password_manager/core/browser/credential_manager_password_form_manager.h
index 6ac5a18..d41f8079 100644
--- a/components/password_manager/core/browser/credential_manager_password_form_manager.h
+++ b/components/password_manager/core/browser/credential_manager_password_form_manager.h
@@ -45,19 +45,24 @@
       std::unique_ptr<autofill::PasswordForm> saved_form,
       CredentialManagerPasswordFormManagerDelegate* delegate,
       std::unique_ptr<FormSaver> form_saver,
-      FormFetcher* form_fetcher);
+      std::unique_ptr<FormFetcher> form_fetcher);
   ~CredentialManagerPasswordFormManager() override;
 
   void ProcessMatches(
       const std::vector<const autofill::PasswordForm*>& non_federated,
       size_t filtered_count) override;
 
+#if defined(UNIT_TEST)
+  FormFetcher* form_fetcher() const { return form_fetcher_.get(); }
+#endif  // defined(UNIT_TEST)
+
  private:
   // Calls OnProvisionalSaveComplete on |delegate_|.
   void NotifyDelegate();
 
   CredentialManagerPasswordFormManagerDelegate* delegate_;
   std::unique_ptr<autofill::PasswordForm> saved_form_;
+  std::unique_ptr<FormFetcher> form_fetcher_;
 
   base::WeakPtrFactory<CredentialManagerPasswordFormManager> weak_factory_;
 
diff --git a/components/password_manager/core/browser/credential_manager_password_form_manager_unittest.cc b/components/password_manager/core/browser/credential_manager_password_form_manager_unittest.cc
index b25176a7..88caa117 100644
--- a/components/password_manager/core/browser/credential_manager_password_form_manager_unittest.cc
+++ b/components/password_manager/core/browser/credential_manager_password_form_manager_unittest.cc
@@ -50,29 +50,28 @@
 TEST_F(CredentialManagerPasswordFormManagerTest, AbortEarly) {
   PasswordForm observed_form;
   MockDelegate delegate;
-  auto form_fetcher = base::MakeUnique<FakeFormFetcher>();
-  form_fetcher->Fetch();
-  CredentialManagerPasswordFormManager form_manager(
+  auto form_manager = base::MakeUnique<CredentialManagerPasswordFormManager>(
       &client_, driver_.AsWeakPtr(), observed_form,
       base::MakeUnique<PasswordForm>(observed_form), &delegate,
-      base::MakeUnique<StubFormSaver>(), form_fetcher.get());
+      base::MakeUnique<StubFormSaver>(), base::MakeUnique<FakeFormFetcher>());
 
-  auto deleter = [&form_fetcher]() { form_fetcher.reset(); };
+  auto deleter = [&form_manager]() { form_manager.reset(); };
 
   // Simulate that the PasswordStore responded to the FormFetcher. As a result,
   // |form_manager| should call the delegate's OnProvisionalSaveComplete, which
   // in turn should delete |form_fetcher|.
   EXPECT_CALL(delegate, OnProvisionalSaveComplete()).WillOnce(Invoke(deleter));
-  form_fetcher->SetNonFederated(std::vector<const PasswordForm*>(), 0u);
-  // Check that |form_fetcher| was not deleted yet; doing so would have caused
+  static_cast<FakeFormFetcher*>(form_manager->form_fetcher())
+      ->SetNonFederated(std::vector<const PasswordForm*>(), 0u);
+  // Check that |form_manager| was not deleted yet; doing so would have caused
   // use after free during SetNonFederated.
-  EXPECT_TRUE(form_fetcher);
+  EXPECT_TRUE(form_manager);
 
   base::RunLoop().RunUntilIdle();
 
   // Ultimately, |form_fetcher| should have been deleted. It just should happen
   // after it finishes executing.
-  EXPECT_FALSE(form_fetcher);
+  EXPECT_FALSE(form_manager);
 }
 
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/credential_manager_pending_request_task.cc b/components/password_manager/core/browser/credential_manager_pending_request_task.cc
index 8508bda2..a3a3747 100644
--- a/components/password_manager/core/browser/credential_manager_pending_request_task.cc
+++ b/components/password_manager/core/browser/credential_manager_pending_request_task.cc
@@ -122,6 +122,22 @@
 
 void CredentialManagerPendingRequestTask::OnGetPasswordStoreResults(
     std::vector<std::unique_ptr<autofill::PasswordForm>> results) {
+  if (results.empty()) {
+    // Try to migrate the HTTP passwords and process them later.
+    http_migrator_ = base::MakeUnique<HttpPasswordMigrator>(
+        origin_, delegate_->client()->GetPasswordStore(), this);
+    return;
+  }
+  ProcessForms(std::move(results));
+}
+
+void CredentialManagerPendingRequestTask::ProcessMigratedForms(
+    std::vector<std::unique_ptr<autofill::PasswordForm>> forms) {
+  ProcessForms(std::move(forms));
+}
+
+void CredentialManagerPendingRequestTask::ProcessForms(
+    std::vector<std::unique_ptr<autofill::PasswordForm>> results) {
   using metrics_util::LogCredentialManagerGetResult;
   metrics_util::CredentialManagerGetMediation mediation_status =
       zero_click_only_ ? metrics_util::CREDENTIAL_MANAGER_GET_UNMEDIATED
diff --git a/components/password_manager/core/browser/credential_manager_pending_request_task.h b/components/password_manager/core/browser/credential_manager_pending_request_task.h
index b29994a9..289a820e 100644
--- a/components/password_manager/core/browser/credential_manager_pending_request_task.h
+++ b/components/password_manager/core/browser/credential_manager_pending_request_task.h
@@ -5,12 +5,14 @@
 #ifndef COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_CREDENTIAL_MANAGER_PENDING_REQUEST_TASK_H_
 #define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_CREDENTIAL_MANAGER_PENDING_REQUEST_TASK_H_
 
+#include <memory>
 #include <set>
 #include <string>
 #include <vector>
 
 #include "base/callback_forward.h"
 #include "base/macros.h"
+#include "components/password_manager/core/browser/http_password_migrator.h"
 #include "components/password_manager/core/browser/password_store.h"
 #include "components/password_manager/core/browser/password_store_consumer.h"
 #include "url/gurl.h"
@@ -51,7 +53,9 @@
 };
 
 // Retrieves credentials from the PasswordStore.
-class CredentialManagerPendingRequestTask : public PasswordStoreConsumer {
+class CredentialManagerPendingRequestTask
+    : public PasswordStoreConsumer,
+      public HttpPasswordMigrator::Consumer {
  public:
   CredentialManagerPendingRequestTask(
       CredentialManagerPendingRequestTaskDelegate* delegate,
@@ -64,11 +68,18 @@
   SendCredentialCallback send_callback() const { return send_callback_; }
   const GURL& origin() const { return origin_; }
 
-  // PasswordStoreConsumer implementation.
+  // PasswordStoreConsumer:
   void OnGetPasswordStoreResults(
       std::vector<std::unique_ptr<autofill::PasswordForm>> results) override;
 
  private:
+  // HttpPasswordMigrator::Consumer:
+  void ProcessMigratedForms(
+      std::vector<std::unique_ptr<autofill::PasswordForm>> forms) override;
+
+  void ProcessForms(
+      std::vector<std::unique_ptr<autofill::PasswordForm>> results);
+
   CredentialManagerPendingRequestTaskDelegate* delegate_;  // Weak;
   SendCredentialCallback send_callback_;
   const bool zero_click_only_;
@@ -76,6 +87,8 @@
   const bool include_passwords_;
   std::set<std::string> federations_;
 
+  std::unique_ptr<HttpPasswordMigrator> http_migrator_;
+
   DISALLOW_COPY_AND_ASSIGN(CredentialManagerPendingRequestTask);
 };
 
diff --git a/components/password_manager/core/browser/form_fetcher_impl.cc b/components/password_manager/core/browser/form_fetcher_impl.cc
index 72b71b71..e4f8ed6 100644
--- a/components/password_manager/core/browser/form_fetcher_impl.cc
+++ b/components/password_manager/core/browser/form_fetcher_impl.cc
@@ -59,12 +59,15 @@
 }  // namespace
 
 FormFetcherImpl::FormFetcherImpl(PasswordStore::FormDigest form_digest,
-                                 const PasswordManagerClient* client)
-    : form_digest_(std::move(form_digest)), client_(client) {}
+                                 const PasswordManagerClient* client,
+                                 bool should_migrate_http_passwords)
+    : form_digest_(std::move(form_digest)),
+      client_(client),
+      should_migrate_http_passwords_(should_migrate_http_passwords) {}
 
 FormFetcherImpl::~FormFetcherImpl() = default;
 
-void FormFetcherImpl::AddConsumer(Consumer* consumer) {
+void FormFetcherImpl::AddConsumer(FormFetcher::Consumer* consumer) {
   DCHECK(consumer);
   consumers_.insert(consumer);
   if (state_ == State::NOT_WAITING)
@@ -105,21 +108,14 @@
     logger->LogNumber(Logger::STRING_NUMBER_RESULTS, results.size());
   }
 
-  federated_ = SplitFederatedMatches(&results);
-  non_federated_ = std::move(results);
+  if (should_migrate_http_passwords_ && results.empty() &&
+      form_digest_.origin.SchemeIs(url::kHttpsScheme)) {
+    http_migrator_ = base::MakeUnique<HttpPasswordMigrator>(
+        form_digest_.origin, client_->GetPasswordStore(), this);
+    return;
+  }
 
-  const size_t original_count = non_federated_.size();
-
-  non_federated_ =
-      client_->GetStoreResultFilter()->FilterResults(std::move(non_federated_));
-
-  filtered_count_ = original_count - non_federated_.size();
-
-  weak_non_federated_ = MakeWeakCopies(non_federated_);
-  weak_federated_ = MakeWeakCopies(federated_);
-
-  for (Consumer* consumer : consumers_)
-    consumer->ProcessMatches(weak_non_federated_, filtered_count_);
+  ProcessPasswordStoreResults(std::move(results));
 }
 
 void FormFetcherImpl::OnGetSiteStatistics(
@@ -129,6 +125,11 @@
   interactions_stats_ = std::move(stats);
 }
 
+void FormFetcherImpl::ProcessMigratedForms(
+    std::vector<std::unique_ptr<autofill::PasswordForm>> forms) {
+  ProcessPasswordStoreResults(std::move(forms));
+}
+
 void FormFetcherImpl::Fetch() {
   std::unique_ptr<BrowserSavePasswordProgressLogger> logger;
   if (password_manager_util::IsLoggingActive(client_)) {
@@ -164,4 +165,23 @@
 #endif
 }
 
+void FormFetcherImpl::ProcessPasswordStoreResults(
+    std::vector<std::unique_ptr<autofill::PasswordForm>> results) {
+  federated_ = SplitFederatedMatches(&results);
+  non_federated_ = std::move(results);
+
+  const size_t original_count = non_federated_.size();
+
+  non_federated_ =
+      client_->GetStoreResultFilter()->FilterResults(std::move(non_federated_));
+
+  filtered_count_ = original_count - non_federated_.size();
+
+  weak_non_federated_ = MakeWeakCopies(non_federated_);
+  weak_federated_ = MakeWeakCopies(federated_);
+
+  for (FormFetcher::Consumer* consumer : consumers_)
+    consumer->ProcessMatches(weak_non_federated_, filtered_count_);
+}
+
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/form_fetcher_impl.h b/components/password_manager/core/browser/form_fetcher_impl.h
index b786f945..0a7b2a5 100644
--- a/components/password_manager/core/browser/form_fetcher_impl.h
+++ b/components/password_manager/core/browser/form_fetcher_impl.h
@@ -11,6 +11,7 @@
 
 #include "base/macros.h"
 #include "components/password_manager/core/browser/form_fetcher.h"
+#include "components/password_manager/core/browser/http_password_migrator.h"
 #include "components/password_manager/core/browser/password_store.h"
 #include "components/password_manager/core/browser/password_store_consumer.h"
 
@@ -20,17 +21,20 @@
 
 // Production implementation of FormFetcher. Fetches credentials associated
 // with a particular origin.
-class FormFetcherImpl : public FormFetcher, public PasswordStoreConsumer {
+class FormFetcherImpl : public FormFetcher,
+                        public PasswordStoreConsumer,
+                        public HttpPasswordMigrator::Consumer {
  public:
   // |form_digest| describes what credentials need to be retrieved and
   // |client| serves the PasswordStore, the logging information etc.
   FormFetcherImpl(PasswordStore::FormDigest form_digest,
-                  const PasswordManagerClient* client);
+                  const PasswordManagerClient* client,
+                  bool should_migrate_http_passwords);
 
   ~FormFetcherImpl() override;
 
   // FormFetcher:
-  void AddConsumer(Consumer* consumer) override;
+  void AddConsumer(FormFetcher::Consumer* consumer) override;
   State GetState() const override;
   const std::vector<InteractionsStats>& GetInteractionsStats() const override;
   const std::vector<const autofill::PasswordForm*>& GetFederatedMatches()
@@ -42,7 +46,15 @@
       std::vector<std::unique_ptr<autofill::PasswordForm>> results) override;
   void OnGetSiteStatistics(std::vector<InteractionsStats> stats) override;
 
+  // HttpPasswordMigrator::Consumer:
+  void ProcessMigratedForms(
+      std::vector<std::unique_ptr<autofill::PasswordForm>> forms) override;
+
  private:
+  // Processes password form results and forwards them to the |consumers_|.
+  void ProcessPasswordStoreResults(
+      std::vector<std::unique_ptr<autofill::PasswordForm>> results);
+
   // PasswordStore results will be fetched for this description.
   const PasswordStore::FormDigest form_digest_;
 
@@ -62,7 +74,7 @@
   std::vector<const autofill::PasswordForm*> weak_federated_;
 
   // Consumers of the fetcher, all are assumed to outlive |this|.
-  std::set<Consumer*> consumers_;
+  std::set<FormFetcher::Consumer*> consumers_;
 
   // Client used to obtain a CredentialFilter.
   const PasswordManagerClient* const client_;
@@ -78,6 +90,12 @@
   // password store returning results in the meantime.
   bool need_to_refetch_ = false;
 
+  // Indicates whether HTTP passwords should be migrated to HTTPS.
+  const bool should_migrate_http_passwords_;
+
+  // Does the actual migration.
+  std::unique_ptr<HttpPasswordMigrator> http_migrator_;
+
   DISALLOW_COPY_AND_ASSIGN(FormFetcherImpl);
 };
 
diff --git a/components/password_manager/core/browser/form_fetcher_impl_unittest.cc b/components/password_manager/core/browser/form_fetcher_impl_unittest.cc
index 269abc9..9ab832f 100644
--- a/components/password_manager/core/browser/form_fetcher_impl_unittest.cc
+++ b/components/password_manager/core/browser/form_fetcher_impl_unittest.cc
@@ -27,6 +27,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
 #include "url/origin.h"
+#include "url/url_constants.h"
 
 using autofill::PasswordForm;
 using base::ASCIIToUTF16;
@@ -113,6 +114,17 @@
   return form;
 }
 
+// Creates a dummy non-federated HTTP form with some basic arbitrary values.
+PasswordForm CreateHTTPNonFederated() {
+  PasswordForm form;
+  form.origin = GURL("http://example.in");
+  form.signon_realm = form.origin.spec();
+  form.action = GURL("http://login.example.org");
+  form.username_value = ASCIIToUTF16("user");
+  form.password_value = ASCIIToUTF16("password");
+  return form;
+}
+
 // Creates a dummy federated form with some basic arbitrary values.
 PasswordForm CreateFederated() {
   PasswordForm form = CreateNonFederated();
@@ -131,6 +143,38 @@
   return form;
 }
 
+// Small helper that wraps passed in forms in unique ptrs.
+std::vector<std::unique_ptr<PasswordForm>> make_results(
+    const std::vector<PasswordForm>& forms) {
+  std::vector<std::unique_ptr<PasswordForm>> results;
+  results.reserve(forms.size());
+  for (const auto& form : forms)
+    results.push_back(base::MakeUnique<PasswordForm>(form));
+  return results;
+}
+
+class MockFormFetcherImpl : public FormFetcherImpl {
+ public:
+  // Inherit constructors.
+  using FormFetcherImpl::FormFetcherImpl;
+
+  // Google Mock is currently unable to mock |ProcessMigratedForms| due to the
+  // presence of move-only types. In order to ensure it is called, a dummy is
+  // added which can be passed to |EXPECT_CALL|.
+  void ProcessMigratedForms(
+      std::vector<std::unique_ptr<autofill::PasswordForm>> results) override {
+    FormFetcherImpl::ProcessMigratedForms(std::move(results));
+    ProcessMigratedFormsDummy();
+  }
+
+  MOCK_METHOD0(ProcessMigratedFormsDummy, void());
+};
+
+ACTION(InvokeMigratorGetResults) {
+  static_cast<HttpPasswordMigrator*>(arg0)->OnGetPasswordStoreResults(
+      std::vector<std::unique_ptr<PasswordForm>>());
+}
+
 }  // namespace
 
 class FormFetcherImplTest : public testing::Test {
@@ -142,7 +186,8 @@
     mock_store_ = new MockPasswordStore();
     client_.set_store(mock_store_.get());
 
-    form_fetcher_ = base::MakeUnique<FormFetcherImpl>(form_digest_, &client_);
+    form_fetcher_ = base::MakeUnique<FormFetcherImpl>(
+        form_digest_, &client_, /* should_migrate_http_passwords */ false);
   }
 
   ~FormFetcherImplTest() override { mock_store_->ShutdownOnUIThread(); }
@@ -362,4 +407,65 @@
 }
 #endif
 
+// Test that ensures HTTP passwords are not migrated on HTTP sites.
+TEST_F(FormFetcherImplTest, DoNotTryToMigrateHTTPPasswordsOnHTTPSites) {
+  GURL::Replacements http_rep;
+  http_rep.SetSchemeStr(url::kHttpScheme);
+  const GURL http_origin = form_digest_.origin.ReplaceComponents(http_rep);
+  const PasswordStore::FormDigest http_form_digest(
+      PasswordForm::SCHEME_HTML, http_origin.GetOrigin().spec(), http_origin);
+
+  // A new form fetcher is created to be able to set the form digest and
+  // migration flag.
+  const auto http_form_fetcher = base::MakeUnique<MockFormFetcherImpl>(
+      http_form_digest, &client_, /* should_migrate_http_passwords */ true);
+
+  std::vector<PasswordForm> empty_forms;
+  const PasswordForm http_form = CreateHTTPNonFederated();
+
+  // Tests that there is no attempt to migrate credentials on HTTP origins.
+  // FormFetcherImplTest::Fetch() can't be used here due to different
+  // expectations. The repeated calls to MockFormFetcherImpl::Fetch() are
+  // necessary to set the correct state.
+  EXPECT_CALL(*mock_store_, GetLogins(_, _));
+  http_form_fetcher->Fetch();
+  EXPECT_CALL(*mock_store_, GetLogins(_, _)).Times(0);
+  http_form_fetcher->OnGetPasswordStoreResults(make_results(empty_forms));
+
+  EXPECT_CALL(*mock_store_, GetLogins(_, _));
+  http_form_fetcher->Fetch();
+  EXPECT_CALL(*mock_store_, GetLogins(_, _)).Times(0);
+  http_form_fetcher->OnGetPasswordStoreResults(make_results({http_form}));
+}
+
+// Test that ensures HTTP passwords are only migrated on HTTPS sites when no
+// HTTPS credentials are available.
+TEST_F(FormFetcherImplTest, TryToMigrateHTTPPasswordsOnHTTPSSites) {
+  GURL::Replacements https_rep;
+  https_rep.SetSchemeStr(url::kHttpsScheme);
+  const GURL https_origin = form_digest_.origin.ReplaceComponents(https_rep);
+  const PasswordStore::FormDigest https_form_digest(
+      PasswordForm::SCHEME_HTML, https_origin.GetOrigin().spec(), https_origin);
+
+  // A new form fetcher is created to be able to set the form digest and
+  // migration flag.
+  const auto https_form_fetcher = base::MakeUnique<MockFormFetcherImpl>(
+      https_form_digest, &client_, /* should_migrate_http_passwords */ true);
+
+  std::vector<PasswordForm> empty_forms;
+  const PasswordForm https_form = CreateNonFederated();
+
+  // Tests that there is only an attempt to migrate credentials on HTTPS origins
+  // when no other credentials are available.
+  // FormFetcherImplTest::Fetch() can't be used here due to different
+  // expectations. The repeated calls to MockFormFetcherImpl::Fetch() are
+  // necessary to set the correct state.
+  EXPECT_CALL(*mock_store_, GetLogins(_, _));
+  https_form_fetcher->Fetch();
+  EXPECT_CALL(*mock_store_, GetLogins(_, _))
+      .WillOnce(testing::WithArg<1>(InvokeMigratorGetResults()));
+  EXPECT_CALL(*https_form_fetcher, ProcessMigratedFormsDummy());
+  https_form_fetcher->OnGetPasswordStoreResults(make_results(empty_forms));
+}
+
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/password_form_manager.cc b/components/password_manager/core/browser/password_form_manager.cc
index 51e3f1e..a8ef741 100644
--- a/components/password_manager/core/browser/password_form_manager.cc
+++ b/components/password_manager/core/browser/password_form_manager.cc
@@ -228,10 +228,12 @@
       submit_result_(kSubmitResultNotSubmitted),
       form_type_(kFormTypeUnspecified),
       form_saver_(std::move(form_saver)),
-      form_fetcher_impl_(
-          form_fetcher ? nullptr : base::MakeUnique<FormFetcherImpl>(
-                                       PasswordStore::FormDigest(observed_form),
-                                       client)),
+      form_fetcher_impl_(form_fetcher
+                             ? nullptr
+                             : base::MakeUnique<FormFetcherImpl>(
+                                   PasswordStore::FormDigest(observed_form),
+                                   client,
+                                   /* should_migrate_http_passwords */ true)),
       form_fetcher_(form_fetcher ? form_fetcher : form_fetcher_impl_.get()) {
   if (form_fetcher_impl_)
     form_fetcher_impl_->Fetch();
diff --git a/components/payments/payment_request_web_contents_manager.cc b/components/payments/payment_request_web_contents_manager.cc
index bb358f9..ca89372 100644
--- a/components/payments/payment_request_web_contents_manager.cc
+++ b/components/payments/payment_request_web_contents_manager.cc
@@ -20,7 +20,7 @@
 PaymentRequestWebContentsManager::GetOrCreateForWebContents(
     content::WebContents* web_contents) {
   DCHECK(web_contents);
-  // CreateForWebContents does nothing if the delegate instance already exists.
+  // CreateForWebContents does nothing if the manager instance already exists.
   PaymentRequestWebContentsManager::CreateForWebContents(web_contents);
   return PaymentRequestWebContentsManager::FromWebContents(web_contents);
 }
diff --git a/components/payments/payment_request_web_contents_manager.h b/components/payments/payment_request_web_contents_manager.h
index 503107b61..42e26f4 100644
--- a/components/payments/payment_request_web_contents_manager.h
+++ b/components/payments/payment_request_web_contents_manager.h
@@ -46,7 +46,7 @@
  private:
   explicit PaymentRequestWebContentsManager(content::WebContents* web_contents);
   friend class content::WebContentsUserData<PaymentRequestWebContentsManager>;
-  friend class PaymentRequestWebContentsManagerBrowserTest;
+  friend class PaymentRequestInteractiveTestBase;
 
   // Owns all the PaymentRequest for this WebContents. Since the
   // PaymentRequestWebContentsManager's lifetime is tied to the WebContents,
@@ -58,4 +58,4 @@
 
 }  // namespace payments
 
-#endif  // COMPONENTS_PAYMENTS_PAYMENT_REQUEST_IMPL_H_
+#endif  // COMPONENTS_PAYMENTS_PAYMENT_REQUEST_WEB_CONTENTS_MANAGER_H_
diff --git a/components/proximity_auth/BUILD.gn b/components/proximity_auth/BUILD.gn
index a8a1f66..9e19dc5 100644
--- a/components/proximity_auth/BUILD.gn
+++ b/components/proximity_auth/BUILD.gn
@@ -6,6 +6,7 @@
 
 static_library("proximity_auth") {
   sources = [
+    "authenticator.cc",
     "authenticator.h",
     "bluetooth_connection.cc",
     "bluetooth_connection.h",
diff --git a/components/proximity_auth/authenticator.cc b/components/proximity_auth/authenticator.cc
new file mode 100644
index 0000000..92ca25a
--- /dev/null
+++ b/components/proximity_auth/authenticator.cc
@@ -0,0 +1,12 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/proximity_auth/authenticator.h"
+
+namespace proximity_auth {
+
+// static
+const char Authenticator::kAuthenticationFeature[] = "auth";
+
+}  // namespace proximity_auth
diff --git a/components/proximity_auth/authenticator.h b/components/proximity_auth/authenticator.h
index 3882a76..2c56fcc 100644
--- a/components/proximity_auth/authenticator.h
+++ b/components/proximity_auth/authenticator.h
@@ -27,6 +27,10 @@
     FAILURE,
   };
 
+  // Feature to be used in |WireMessage|s sent during the authentication
+  // handshake.
+  static const char kAuthenticationFeature[];
+
   virtual ~Authenticator() {}
 
   // Initiates the authentication attempt, invoking |callback| with the result.
diff --git a/components/proximity_auth/ble/bluetooth_low_energy_connection_unittest.cc b/components/proximity_auth/ble/bluetooth_low_energy_connection_unittest.cc
index 4266d8e..2c529ff 100644
--- a/components/proximity_auth/ble/bluetooth_low_energy_connection_unittest.cc
+++ b/components/proximity_auth/ble/bluetooth_low_energy_connection_unittest.cc
@@ -52,6 +52,8 @@
 const char kToPeripheralCharID[] = "to peripheral char id";
 const char kFromPeripheralCharID[] = "from peripheral char id";
 
+const char kTestFeature[] = "testFeature";
+
 const device::BluetoothRemoteGattCharacteristic::Properties
     kCharacteristicProperties =
         device::BluetoothRemoteGattCharacteristic::PROPERTY_BROADCAST |
@@ -598,19 +600,25 @@
   int message_size = 100;
   std::string message(message_size, 'A');
   message[0] = 'B';
-  connection->SendMessage(
-      base::MakeUnique<cryptauth::FakeWireMessage>(message));
+
+  std::unique_ptr<cryptauth::FakeWireMessage> wire_message =
+      base::MakeUnique<cryptauth::FakeWireMessage>(message,
+                                                   std::string(kTestFeature));
+  std::string serialized_message = wire_message->Serialize();
+
+  connection->SendMessage(std::move(wire_message));
 
   // Expecting that |kSendSignal| + |message_size| + |message| was written.
   EXPECT_EQ(last_value_written_on_to_peripheral_char_,
-            CreateFirstCharacteristicValue(message, message.size()));
+            CreateFirstCharacteristicValue(serialized_message,
+                                           serialized_message.size()));
   EXPECT_CALL(*connection, OnDidSendMessage(_, _));
 
   RunWriteCharacteristicSuccessCallback();
 }
 
 TEST_F(ProximityAuthBluetoothLowEnergyConnectionTest,
-       SendMessage_LagerThanCharacteristicSize) {
+       SendMessage_LargerThanCharacteristicSize) {
   std::unique_ptr<MockBluetoothLowEnergyConnection> connection(
       CreateConnection());
   InitializeConnection(connection.get());
@@ -627,15 +635,21 @@
   int message_size = 600;
   std::string message(message_size, 'A');
   message[0] = 'B';
-  connection->SendMessage(
-      base::MakeUnique<cryptauth::FakeWireMessage>(message));
 
-  // Expecting that |kSendSignal| + |message_size| was written in the first 8
-  // bytes.
+  std::unique_ptr<cryptauth::FakeWireMessage> wire_message =
+      base::MakeUnique<cryptauth::FakeWireMessage>(message,
+                                                   std::string(kTestFeature));
+  std::string serialized_message = wire_message->Serialize();
+
+  // Send the message.
+  connection->SendMessage(std::move(wire_message));
+
+  // Expecting that |kSendSignal| + |serialized_message| was written in the
+  // first 8 bytes.
   std::vector<uint8_t> prefix(
       last_value_written_on_to_peripheral_char_.begin(),
       last_value_written_on_to_peripheral_char_.begin() + 8);
-  EXPECT_EQ(prefix, CreateSendSignalWithSize(message_size));
+  EXPECT_EQ(prefix, CreateSendSignalWithSize(serialized_message.size()));
   std::vector<uint8_t> bytes_received(
       last_value_written_on_to_peripheral_char_.begin() + 8,
       last_value_written_on_to_peripheral_char_.end());
@@ -654,7 +668,8 @@
                         last_value_written_on_to_peripheral_char_.end());
 
   // Expecting that the message was written.
-  std::vector<uint8_t> expected_value(message.begin(), message.end());
+  std::vector<uint8_t> expected_value(serialized_message.begin(),
+                                      serialized_message.end());
   EXPECT_EQ(expected_value.size(), bytes_received.size());
   EXPECT_EQ(expected_value, bytes_received);
 
diff --git a/components/proximity_auth/bluetooth_connection_unittest.cc b/components/proximity_auth/bluetooth_connection_unittest.cc
index e318c21..dd57691 100644
--- a/components/proximity_auth/bluetooth_connection_unittest.cc
+++ b/components/proximity_auth/bluetooth_connection_unittest.cc
@@ -80,7 +80,7 @@
 
 class TestWireMessage : public cryptauth::WireMessage {
  public:
-  TestWireMessage() : cryptauth::WireMessage("permit id", "payload") {}
+  TestWireMessage() : cryptauth::WireMessage("payload", "feature") {}
   ~TestWireMessage() override {}
 
   std::string Serialize() const override { return kSerializedMessage; }
diff --git a/components/proximity_auth/device_to_device_authenticator.cc b/components/proximity_auth/device_to_device_authenticator.cc
index cc9ccdf6..751e277f 100644
--- a/components/proximity_auth/device_to_device_authenticator.cc
+++ b/components/proximity_auth/device_to_device_authenticator.cc
@@ -12,6 +12,7 @@
 #include "components/cryptauth/connection.h"
 #include "components/cryptauth/secure_message_delegate.h"
 #include "components/cryptauth/wire_message.h"
+#include "components/proximity_auth/authenticator.h"
 #include "components/proximity_auth/device_to_device_initiator_operations.h"
 #include "components/proximity_auth/device_to_device_secure_context.h"
 #include "components/proximity_auth/logging/logging.h"
@@ -26,10 +27,6 @@
 // authentication will fail.
 const int kResponderAuthTimeoutSeconds = 5;
 
-// The prefix of the permit id sent to the remote device. The permit id
-// is used by the remote device to find the credentials of the local device.
-const char kPermitIdPrefix[] = "permit://google.com/easyunlock/v1/";
-
 }  // namespace
 
 DeviceToDeviceAuthenticator::DeviceToDeviceAuthenticator(
@@ -113,9 +110,8 @@
   // Send the [Hello] message to the remote device.
   state_ = State::SENT_HELLO;
   hello_message_ = message;
-  std::string permit_id = kPermitIdPrefix + account_id_;
-  connection_->SendMessage(
-      base::MakeUnique<cryptauth::WireMessage>(hello_message_, permit_id));
+  connection_->SendMessage(base::MakeUnique<cryptauth::WireMessage>(
+      hello_message_, std::string(Authenticator::kAuthenticationFeature)));
 }
 
 void DeviceToDeviceAuthenticator::OnResponderAuthTimedOut() {
@@ -154,7 +150,8 @@
   }
 
   state_ = State::SENT_INITIATOR_AUTH;
-  connection_->SendMessage(base::MakeUnique<cryptauth::WireMessage>(message));
+  connection_->SendMessage(base::MakeUnique<cryptauth::WireMessage>(
+      message, std::string(Authenticator::kAuthenticationFeature)));
 }
 
 void DeviceToDeviceAuthenticator::Fail(const std::string& error_message) {
@@ -200,7 +197,8 @@
 void DeviceToDeviceAuthenticator::OnMessageReceived(
     const cryptauth::Connection& connection,
     const cryptauth::WireMessage& message) {
-  if (state_ == State::SENT_HELLO) {
+  if (state_ == State::SENT_HELLO &&
+      message.feature() == std::string(Authenticator::kAuthenticationFeature)) {
     PA_LOG(INFO) << "Received [Responder Auth] message, payload_size="
                  << message.payload().size();
     state_ = State::RECEIVED_RESPONDER_AUTH;
diff --git a/components/proximity_auth/device_to_device_authenticator_unittest.cc b/components/proximity_auth/device_to_device_authenticator_unittest.cc
index 510d266..b66d735 100644
--- a/components/proximity_auth/device_to_device_authenticator_unittest.cc
+++ b/components/proximity_auth/device_to_device_authenticator_unittest.cc
@@ -17,6 +17,7 @@
 #include "components/cryptauth/cryptauth_test_util.h"
 #include "components/cryptauth/fake_secure_message_delegate.h"
 #include "components/cryptauth/wire_message.h"
+#include "components/proximity_auth/authenticator.h"
 #include "components/proximity_auth/device_to_device_responder_operations.h"
 #include "components/proximity_auth/secure_context.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -181,8 +182,6 @@
         base::Unretained(this)));
 
     EXPECT_EQ(1u, connection_.message_buffer().size());
-    EXPECT_EQ(std::string("permit://google.com/easyunlock/v1/") + kAccountId,
-              connection_.message_buffer()[0]->permit_id());
     std::string hello_message = connection_.message_buffer()[0]->payload();
     connection_.ClearMessageBuffer();
 
@@ -214,7 +213,8 @@
         base::Bind(&SaveStringResult, &responder_auth_message));
     EXPECT_FALSE(responder_auth_message.empty());
 
-    cryptauth::WireMessage wire_message(responder_auth_message);
+    cryptauth::WireMessage wire_message(responder_auth_message,
+                                        Authenticator::kAuthenticationFeature);
     connection_.OnBytesReceived(wire_message.Serialize());
 
     return responder_auth_message;
@@ -281,7 +281,8 @@
 
   // If the responder could not validate the [Hello message], it essentially
   // sends random bytes back for privacy reasons.
-  cryptauth::WireMessage wire_message(base::RandBytesAsString(300u));
+  cryptauth::WireMessage wire_message(base::RandBytesAsString(300u),
+                                      Authenticator::kAuthenticationFeature);
   EXPECT_CALL(*this,
               OnAuthenticationResultProxy(Authenticator::Result::FAILURE));
   connection_.OnBytesReceived(wire_message.Serialize());
@@ -346,12 +347,13 @@
 
   // Test that the authenticator is properly cleaned up after authentication
   // completes.
-  cryptauth::WireMessage wire_message(base::RandBytesAsString(300u));
-  connection_.SendMessage(
-      base::MakeUnique<cryptauth::WireMessage>(base::RandBytesAsString(300u)));
+  cryptauth::WireMessage wire_message(base::RandBytesAsString(300u),
+                                      Authenticator::kAuthenticationFeature);
+  connection_.SendMessage(base::MakeUnique<cryptauth::WireMessage>(
+      base::RandBytesAsString(300u), Authenticator::kAuthenticationFeature));
   connection_.OnBytesReceived(wire_message.Serialize());
-  connection_.SendMessage(
-      base::MakeUnique<cryptauth::WireMessage>(base::RandBytesAsString(300u)));
+  connection_.SendMessage(base::MakeUnique<cryptauth::WireMessage>(
+      base::RandBytesAsString(300u), Authenticator::kAuthenticationFeature));
   connection_.OnBytesReceived(wire_message.Serialize());
 }
 
diff --git a/components/proximity_auth/messenger_impl.cc b/components/proximity_auth/messenger_impl.cc
index 200539e9..1a512b6 100644
--- a/components/proximity_auth/messenger_impl.cc
+++ b/components/proximity_auth/messenger_impl.cc
@@ -50,6 +50,8 @@
 const char kScreenLocked[] = "Screen Locked";
 const int kIOSPollingIntervalSeconds = 5;
 
+const char kEasyUnlockFeatureName[] = "easy_unlock";
+
 // Serializes the |value| to a JSON string and returns the result.
 std::string SerializeValueToJson(const base::Value& value) {
   std::string json;
@@ -179,8 +181,8 @@
 }
 
 void MessengerImpl::OnMessageEncoded(const std::string& encoded_message) {
-  connection_->SendMessage(
-      base::MakeUnique<cryptauth::WireMessage>(encoded_message));
+  connection_->SendMessage(base::MakeUnique<cryptauth::WireMessage>(
+      encoded_message, std::string(kEasyUnlockFeatureName)));
 }
 
 void MessengerImpl::OnMessageDecoded(const std::string& decoded_message) {
diff --git a/components/proximity_auth/messenger_impl_unittest.cc b/components/proximity_auth/messenger_impl_unittest.cc
index 2a66e8f..5ff61dc1 100644
--- a/components/proximity_auth/messenger_impl_unittest.cc
+++ b/components/proximity_auth/messenger_impl_unittest.cc
@@ -112,13 +112,13 @@
   cryptauth::WireMessage* message =
       messenger.GetFakeConnection()->current_message();
   ASSERT_TRUE(message);
-  EXPECT_EQ(std::string(), message->permit_id());
   EXPECT_EQ(
       "{"
       "\"name\":\"easy_unlock\","
       "\"type\":\"event\""
       "}, but encoded",
       message->payload());
+  EXPECT_EQ("easy_unlock", message->feature());
 }
 
 TEST(ProximityAuthMessengerImplTest, DispatchUnlockEvent_SendMessageFails) {
@@ -155,7 +155,6 @@
   cryptauth::WireMessage* message =
       messenger.GetFakeConnection()->current_message();
   ASSERT_TRUE(message);
-  EXPECT_EQ(std::string(), message->permit_id());
   EXPECT_EQ(
       "{"
       "\"encrypted_data\":\"YSBtb3N0IGRpZmZpY3VsdCBjaGFsbGVuZ2U=\","
@@ -172,7 +171,6 @@
   cryptauth::WireMessage* message =
       messenger.GetFakeConnection()->current_message();
   ASSERT_TRUE(message);
-  EXPECT_EQ(std::string(), message->permit_id());
   EXPECT_EQ(
       "{"
       "\"encrypted_data\":\"_-Y=\","
@@ -274,7 +272,6 @@
   cryptauth::WireMessage* message =
       messenger.GetFakeConnection()->current_message();
   ASSERT_TRUE(message);
-  EXPECT_EQ(std::string(), message->permit_id());
   EXPECT_EQ("{\"type\":\"unlock_request\"}, but encoded", message->payload());
 }
 
diff --git a/components/sync/BUILD.gn b/components/sync/BUILD.gn
index f05878b0..2a552cd 100644
--- a/components/sync/BUILD.gn
+++ b/components/sync/BUILD.gn
@@ -760,6 +760,8 @@
     "model/mock_model_type_store.h",
     "model/model_type_store_test_util.cc",
     "model/model_type_store_test_util.h",
+    "model/recording_model_type_change_processor.cc",
+    "model/recording_model_type_change_processor.h",
     "model/stub_model_type_sync_bridge.cc",
     "model/stub_model_type_sync_bridge.h",
     "model/sync_change_processor_wrapper_for_test.cc",
diff --git a/components/sync/device_info/device_info_sync_bridge_unittest.cc b/components/sync/device_info/device_info_sync_bridge_unittest.cc
index 6f996f4..bac12413 100644
--- a/components/sync/device_info/device_info_sync_bridge_unittest.cc
+++ b/components/sync/device_info/device_info_sync_bridge_unittest.cc
@@ -21,6 +21,7 @@
 #include "components/sync/model/fake_model_type_change_processor.h"
 #include "components/sync/model/metadata_batch.h"
 #include "components/sync/model/model_type_store_test_util.h"
+#include "components/sync/model/recording_model_type_change_processor.h"
 #include "components/sync/protocol/model_type_state.pb.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -170,43 +171,6 @@
   return map;
 }
 
-// Instead of actually processing anything, simply accumulates all instructions
-// in members that can then be accessed. TODO(skym): If this ends up being
-// useful for other model type unittests it should be moved out to a shared
-// location.
-class RecordingModelTypeChangeProcessor : public FakeModelTypeChangeProcessor {
- public:
-  RecordingModelTypeChangeProcessor() {}
-  ~RecordingModelTypeChangeProcessor() override {}
-
-  void Put(const std::string& storage_key,
-           std::unique_ptr<EntityData> entity_data,
-           MetadataChangeList* metadata_changes) override {
-    put_multimap_.insert(std::make_pair(storage_key, std::move(entity_data)));
-  }
-
-  void Delete(const std::string& storage_key,
-              MetadataChangeList* metadata_changes) override {
-    delete_set_.insert(storage_key);
-  }
-
-  void ModelReadyToSync(std::unique_ptr<MetadataBatch> batch) override {
-    std::swap(metadata_, batch);
-  }
-
-  const std::multimap<std::string, std::unique_ptr<EntityData>>& put_multimap()
-      const {
-    return put_multimap_;
-  }
-  const std::set<std::string>& delete_set() const { return delete_set_; }
-  const MetadataBatch* metadata() const { return metadata_.get(); }
-
- private:
-  std::multimap<std::string, std::unique_ptr<EntityData>> put_multimap_;
-  std::set<std::string> delete_set_;
-  std::unique_ptr<MetadataBatch> metadata_;
-};
-
 }  // namespace
 
 class DeviceInfoSyncBridgeTest : public testing::Test,
diff --git a/components/sync/driver/data_type_controller.h b/components/sync/driver/data_type_controller.h
index aef685cd..29d2e22e 100644
--- a/components/sync/driver/data_type_controller.h
+++ b/components/sync/driver/data_type_controller.h
@@ -91,6 +91,12 @@
   // return false while USS datatypes should return true.
   virtual bool ShouldLoadModelBeforeConfigure() const = 0;
 
+  // Called right before LoadModels. This method allows controller to register
+  // the type with sync engine. Directory datatypes download initial data in
+  // parallel with LoadModels and thus should be ready to receive updates with
+  // initial data before LoadModels finishes.
+  virtual void BeforeLoadModels(ModelTypeConfigurer* configurer) = 0;
+
   // Begins asynchronous operation of loading the model to get it ready for
   // model association. Once the models are loaded the callback will be invoked
   // with the result. If the models are already loaded it is safe to call the
diff --git a/components/sync/driver/data_type_manager_impl.cc b/components/sync/driver/data_type_manager_impl.cc
index 071d4c42..afb73b0 100644
--- a/components/sync/driver/data_type_manager_impl.cc
+++ b/components/sync/driver/data_type_manager_impl.cc
@@ -642,6 +642,12 @@
   model_association_manager_.StartAssociationAsync(types_to_associate);
 }
 
+void DataTypeManagerImpl::OnSingleDataTypeWillStart(ModelType type) {
+  DCHECK(controllers_->find(type) != controllers_->end());
+  DataTypeController* dtc = controllers_->find(type)->second.get();
+  dtc->BeforeLoadModels(configurer_);
+}
+
 void DataTypeManagerImpl::OnSingleDataTypeWillStop(ModelType type,
                                                    const SyncError& error) {
   DataTypeController::TypeMap::const_iterator c_it = controllers_->find(type);
diff --git a/components/sync/driver/data_type_manager_impl.h b/components/sync/driver/data_type_manager_impl.h
index 2f64a457..cf28cdf 100644
--- a/components/sync/driver/data_type_manager_impl.h
+++ b/components/sync/driver/data_type_manager_impl.h
@@ -59,6 +59,7 @@
   State state() const override;
 
   // |ModelAssociationManagerDelegate| implementation.
+  void OnSingleDataTypeWillStart(ModelType type) override;
   void OnAllDataTypesReadyForConfigure() override;
   void OnSingleDataTypeAssociationDone(
       ModelType type,
diff --git a/components/sync/driver/data_type_manager_impl_unittest.cc b/components/sync/driver/data_type_manager_impl_unittest.cc
index af1bf7e..52ecd58 100644
--- a/components/sync/driver/data_type_manager_impl_unittest.cc
+++ b/components/sync/driver/data_type_manager_impl_unittest.cc
@@ -5,6 +5,7 @@
 #include "components/sync/driver/data_type_manager_impl.h"
 
 #include <memory>
+#include <utility>
 
 #include "base/memory/ptr_util.h"
 #include "base/message_loop/message_loop.h"
@@ -80,6 +81,15 @@
     last_params_ = std::move(params);
   }
 
+  void RegisterDirectoryDataType(ModelType type,
+                                 ModelSafeGroup group) override {
+    registered_directory_types_.Put(type);
+  }
+
+  void UnregisterDirectoryDataType(ModelType type) override {
+    registered_directory_types_.Remove(type);
+  }
+
   void ActivateDirectoryDataType(ModelType type,
                                  ModelSafeGroup group,
                                  ChangeProcessor* change_processor) override {
@@ -100,6 +110,10 @@
     // TODO(stanisc): crbug.com/515962: Add test coverage.
   }
 
+  const ModelTypeSet registered_directory_types() {
+    return registered_directory_types_;
+  }
+
   const ModelTypeSet activated_types() { return activated_types_; }
 
   int configure_call_count() const { return configure_call_count_; }
@@ -107,6 +121,7 @@
   const ConfigureParams& last_params() const { return last_params_; }
 
  private:
+  ModelTypeSet registered_directory_types_;
   ModelTypeSet activated_types_;
   int configure_call_count_ = 0;
   ConfigureParams last_params_;
@@ -342,6 +357,7 @@
 
   Configure(ModelTypeSet(BOOKMARKS));
   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
+  EXPECT_EQ(ModelTypeSet(BOOKMARKS), configurer_.registered_directory_types());
 
   FinishDownload(ModelTypeSet(), ModelTypeSet());
   FinishDownload(ModelTypeSet(BOOKMARKS), ModelTypeSet());
@@ -354,6 +370,7 @@
   dtm_->Stop();
   EXPECT_EQ(DataTypeManager::STOPPED, dtm_->state());
   EXPECT_TRUE(configurer_.activated_types().Empty());
+  EXPECT_TRUE(configurer_.registered_directory_types().Empty());
 }
 
 // Set up a DTM with a single controller, configure it, but stop it
@@ -369,9 +386,12 @@
 
     Configure(ModelTypeSet(BOOKMARKS));
     EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
+    EXPECT_EQ(ModelTypeSet(BOOKMARKS),
+              configurer_.registered_directory_types());
 
     dtm_->Stop();
     EXPECT_EQ(DataTypeManager::STOPPED, dtm_->state());
+    EXPECT_TRUE(configurer_.registered_directory_types().Empty());
   }
 
   last_configure_params().ready_task.Run(ModelTypeSet(BOOKMARKS),
@@ -393,13 +413,15 @@
 
     Configure(ModelTypeSet(BOOKMARKS));
     EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
-
+    EXPECT_EQ(ModelTypeSet(BOOKMARKS),
+              configurer_.registered_directory_types());
     FinishDownload(ModelTypeSet(), ModelTypeSet());
     FinishDownload(ModelTypeSet(BOOKMARKS), ModelTypeSet());
     EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
 
     dtm_->Stop();
     EXPECT_EQ(DataTypeManager::STOPPED, dtm_->state());
+    EXPECT_TRUE(configurer_.registered_directory_types().Empty());
     dtm_.reset();
   }
 
@@ -422,6 +444,8 @@
 
     Configure(ModelTypeSet(BOOKMARKS));
     EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
+    EXPECT_EQ(ModelTypeSet(BOOKMARKS),
+              configurer_.registered_directory_types());
 
     FinishDownload(ModelTypeSet(), ModelTypeSet());
     FinishDownload(ModelTypeSet(BOOKMARKS), ModelTypeSet());
@@ -430,6 +454,7 @@
 
     dtm_->Stop();
     EXPECT_EQ(DataTypeManager::STOPPED, dtm_->state());
+    EXPECT_TRUE(configurer_.registered_directory_types().Empty());
     dtm_.reset();
   }
 
@@ -497,6 +522,7 @@
   // Step 1.
   Configure(ModelTypeSet(BOOKMARKS));
   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
+  EXPECT_EQ(ModelTypeSet(BOOKMARKS), configurer_.registered_directory_types());
 
   // Step 2.
   FinishDownload(ModelTypeSet(), ModelTypeSet());
@@ -514,6 +540,8 @@
   // Step 4.
   Configure(ModelTypeSet(BOOKMARKS, PREFERENCES));
   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
+  EXPECT_EQ(ModelTypeSet(BOOKMARKS, PREFERENCES),
+            configurer_.registered_directory_types());
 
   // Step 5.
   FinishDownload(ModelTypeSet(), ModelTypeSet());
@@ -529,6 +557,7 @@
   dtm_->Stop();
   EXPECT_EQ(DataTypeManager::STOPPED, dtm_->state());
   EXPECT_TRUE(configurer_.activated_types().Empty());
+  EXPECT_TRUE(configurer_.registered_directory_types().Empty());
 }
 
 // Set up a DTM with two controllers.  Then:
@@ -550,6 +579,7 @@
   // Step 1.
   Configure(ModelTypeSet(BOOKMARKS));
   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
+  EXPECT_EQ(ModelTypeSet(BOOKMARKS), configurer_.registered_directory_types());
 
   // Step 2.
   FinishDownload(ModelTypeSet(), ModelTypeSet());
@@ -567,6 +597,8 @@
   // Step 4.
   Configure(ModelTypeSet(PREFERENCES));
   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
+  EXPECT_EQ(ModelTypeSet(PREFERENCES),
+            configurer_.registered_directory_types());
 
   // Step 5.
   FinishDownload(ModelTypeSet(), ModelTypeSet());
@@ -582,6 +614,7 @@
   dtm_->Stop();
   EXPECT_EQ(DataTypeManager::STOPPED, dtm_->state());
   EXPECT_TRUE(configurer_.activated_types().Empty());
+  EXPECT_TRUE(configurer_.registered_directory_types().Empty());
 }
 
 // Set up a DTM with two controllers.  Then:
@@ -603,6 +636,7 @@
   // Step 1.
   Configure(ModelTypeSet(BOOKMARKS));
   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
+  EXPECT_EQ(ModelTypeSet(BOOKMARKS), configurer_.registered_directory_types());
 
   // Step 2.
   FinishDownload(ModelTypeSet(), ModelTypeSet());
@@ -626,11 +660,14 @@
   GetController(PREFERENCES)->FinishStart(DataTypeController::OK);
   EXPECT_EQ(DataTypeManager::CONFIGURED, dtm_->state());
   EXPECT_EQ(2U, configurer_.activated_types().Size());
+  EXPECT_EQ(ModelTypeSet(BOOKMARKS, PREFERENCES),
+            configurer_.registered_directory_types());
 
   // Step 7.
   dtm_->Stop();
   EXPECT_EQ(DataTypeManager::STOPPED, dtm_->state());
   EXPECT_TRUE(configurer_.activated_types().Empty());
+  EXPECT_TRUE(configurer_.registered_directory_types().Empty());
 }
 
 // Set up a DTM with one controller.  Then configure, finish
@@ -647,6 +684,7 @@
 
   Configure(ModelTypeSet(BOOKMARKS));
   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
+  EXPECT_EQ(ModelTypeSet(BOOKMARKS), configurer_.registered_directory_types());
 
   FinishDownload(ModelTypeSet(), ModelTypeSet());
   FinishDownload(ModelTypeSet(BOOKMARKS), ModelTypeSet());
@@ -657,6 +695,7 @@
       DataTypeController::UNRECOVERABLE_ERROR);
   EXPECT_EQ(DataTypeManager::STOPPED, dtm_->state());
   EXPECT_TRUE(configurer_.activated_types().Empty());
+  EXPECT_TRUE(configurer_.registered_directory_types().Empty());
 }
 
 // Set up a DTM with two controllers.  Then:
@@ -680,6 +719,8 @@
   // Step 1.
   Configure(ModelTypeSet(BOOKMARKS, PREFERENCES));
   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
+  EXPECT_EQ(ModelTypeSet(BOOKMARKS, PREFERENCES),
+            configurer_.registered_directory_types());
 
   // Step 2.
   FinishDownload(ModelTypeSet(), ModelTypeSet());
@@ -694,6 +735,7 @@
   GetController(PREFERENCES)
       ->FinishStart(DataTypeController::UNRECOVERABLE_ERROR);
   EXPECT_EQ(DataTypeManager::STOPPED, dtm_->state());
+  EXPECT_TRUE(configurer_.registered_directory_types().Empty());
 }
 
 // Set up a DTM with two controllers.  Then:
@@ -722,6 +764,8 @@
   // Step 1.
   Configure(ModelTypeSet(BOOKMARKS, PREFERENCES));
   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
+  EXPECT_EQ(ModelTypeSet(BOOKMARKS, PREFERENCES),
+            configurer_.registered_directory_types());
 
   // Step 2.
   FinishDownload(ModelTypeSet(), ModelTypeSet());
@@ -742,11 +786,13 @@
   FinishDownload(ModelTypeSet(BOOKMARKS), ModelTypeSet());
   EXPECT_EQ(DataTypeManager::CONFIGURED, dtm_->state());
   EXPECT_EQ(1U, configurer_.activated_types().Size());
+  EXPECT_EQ(ModelTypeSet(BOOKMARKS), configurer_.registered_directory_types());
 
   // Step 6.
   dtm_->Stop();
   EXPECT_EQ(DataTypeManager::STOPPED, dtm_->state());
   EXPECT_TRUE(configurer_.activated_types().Empty());
+  EXPECT_TRUE(configurer_.registered_directory_types().Empty());
 }
 
 // Set up a DTM with two controllers.  Then:
@@ -767,6 +813,7 @@
   // Step 1.
   Configure(ModelTypeSet(BOOKMARKS));
   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
+  EXPECT_EQ(ModelTypeSet(BOOKMARKS), configurer_.registered_directory_types());
 
   // Step 2.
   Configure(ModelTypeSet(BOOKMARKS, PREFERENCES));
@@ -786,10 +833,13 @@
   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
   GetController(PREFERENCES)->FinishStart(DataTypeController::OK);
   EXPECT_EQ(DataTypeManager::CONFIGURED, dtm_->state());
+  EXPECT_EQ(ModelTypeSet(BOOKMARKS, PREFERENCES),
+            configurer_.registered_directory_types());
 
   // Step 6.
   dtm_->Stop();
   EXPECT_EQ(DataTypeManager::STOPPED, dtm_->state());
+  EXPECT_TRUE(configurer_.registered_directory_types().Empty());
 }
 
 // Set up a DTM with two controllers.  Then:
@@ -814,6 +864,7 @@
   Configure(ModelTypeSet(BOOKMARKS));
   FinishDownload(ModelTypeSet(), ModelTypeSet());
   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
+  EXPECT_EQ(ModelTypeSet(BOOKMARKS), configurer_.registered_directory_types());
 
   // Step 2.
   Configure(ModelTypeSet(BOOKMARKS, PREFERENCES));
@@ -833,10 +884,13 @@
   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
   GetController(PREFERENCES)->FinishStart(DataTypeController::OK);
   EXPECT_EQ(DataTypeManager::CONFIGURED, dtm_->state());
+  EXPECT_EQ(ModelTypeSet(BOOKMARKS, PREFERENCES),
+            configurer_.registered_directory_types());
 
   // Step 6.
   dtm_->Stop();
   EXPECT_EQ(DataTypeManager::STOPPED, dtm_->state());
+  EXPECT_TRUE(configurer_.registered_directory_types().Empty());
 }
 
 // Tests a Purge then Configure.  This is similar to the sequence of
diff --git a/components/sync/driver/directory_data_type_controller.cc b/components/sync/driver/directory_data_type_controller.cc
index 86fdd73..933a328 100644
--- a/components/sync/driver/directory_data_type_controller.cc
+++ b/components/sync/driver/directory_data_type_controller.cc
@@ -34,6 +34,31 @@
   return false;
 }
 
+void DirectoryDataTypeController::BeforeLoadModels(
+    ModelTypeConfigurer* configurer) {
+  configurer->RegisterDirectoryDataType(type(), model_safe_group_);
+}
+
+void DirectoryDataTypeController::RegisterWithBackend(
+    base::Callback<void(bool)> set_downloaded,
+    ModelTypeConfigurer* configurer) {}
+
+void DirectoryDataTypeController::ActivateDataType(
+    ModelTypeConfigurer* configurer) {
+  DCHECK(CalledOnValidThread());
+  // Tell the backend about the change processor for this type so it can
+  // begin routing changes to it.
+  configurer->ActivateDirectoryDataType(type(), model_safe_group_,
+                                        GetChangeProcessor());
+}
+
+void DirectoryDataTypeController::DeactivateDataType(
+    ModelTypeConfigurer* configurer) {
+  DCHECK(CalledOnValidThread());
+  configurer->DeactivateDirectoryDataType(type());
+  configurer->UnregisterDirectoryDataType(type());
+}
+
 void DirectoryDataTypeController::GetAllNodes(
     const AllNodesCallback& callback) {
   std::unique_ptr<base::ListValue> node_list = GetAllNodesForTypeFromDirectory(
@@ -57,25 +82,6 @@
   callback.Run(type(), counters);
 }
 
-void DirectoryDataTypeController::RegisterWithBackend(
-    base::Callback<void(bool)> set_downloaded,
-    ModelTypeConfigurer* configurer) {}
-
-void DirectoryDataTypeController::ActivateDataType(
-    ModelTypeConfigurer* configurer) {
-  DCHECK(CalledOnValidThread());
-  // Tell the backend about the change processor for this type so it can
-  // begin routing changes to it.
-  configurer->ActivateDirectoryDataType(type(), model_safe_group_,
-                                        GetChangeProcessor());
-}
-
-void DirectoryDataTypeController::DeactivateDataType(
-    ModelTypeConfigurer* configurer) {
-  DCHECK(CalledOnValidThread());
-  configurer->DeactivateDirectoryDataType(type());
-}
-
 // static
 std::unique_ptr<base::ListValue>
 DirectoryDataTypeController::GetAllNodesForTypeFromDirectory(
diff --git a/components/sync/driver/directory_data_type_controller.h b/components/sync/driver/directory_data_type_controller.h
index b4b2777..d05bddc5 100644
--- a/components/sync/driver/directory_data_type_controller.h
+++ b/components/sync/driver/directory_data_type_controller.h
@@ -23,12 +23,13 @@
 
   // DataTypeController implementation.
   bool ShouldLoadModelBeforeConfigure() const override;
-  void GetAllNodes(const AllNodesCallback& callback) override;
-  void GetStatusCounters(const StatusCountersCallback& callback) override;
 
-  // Directory based data types don't need to register with backend.
-  // ModelTypeRegistry will create all necessary objects in
-  // SetEnabledDirectoryTypes based on routing info.
+  // Directory types need to register with sync engine before LoadModels because
+  // downloading initial data happens in parallel with LoadModels.
+  void BeforeLoadModels(ModelTypeConfigurer* configurer) override;
+
+  // Directory based data types register with backend before LoadModels in
+  // BeforeLoadModels. No need to do anything in RegisterWithBackend.
   void RegisterWithBackend(base::Callback<void(bool)> set_downloaded,
                            ModelTypeConfigurer* configurer) override;
 
@@ -46,6 +47,9 @@
   // See ModelTypeConfigurer::DeactivateDataType for more details.
   void DeactivateDataType(ModelTypeConfigurer* configurer) override;
 
+  void GetAllNodes(const AllNodesCallback& callback) override;
+  void GetStatusCounters(const StatusCountersCallback& callback) override;
+
   // Returns a ListValue representing all nodes for a specified type by querying
   // the directory.
   static std::unique_ptr<base::ListValue> GetAllNodesForTypeFromDirectory(
diff --git a/components/sync/driver/glue/sync_backend_host_core.cc b/components/sync/driver/glue/sync_backend_host_core.cc
index b934544..0751ba2 100644
--- a/components/sync/driver/glue/sync_backend_host_core.cc
+++ b/components/sync/driver/glue/sync_backend_host_core.cc
@@ -141,6 +141,16 @@
 
   ModelTypeSet new_control_types =
       registrar_->ConfigureDataTypes(ControlTypes(), ModelTypeSet());
+
+  // Control types don't have DataTypeControllers, but they need to have
+  // update handlers registered in ModelTypeRegistry. Register them here.
+  ModelTypeConnector* model_type_connector =
+      sync_manager_->GetModelTypeConnector();
+  ModelTypeSet control_types = ControlTypes();
+  for (auto it = control_types.First(); it.Good(); it.Inc()) {
+    model_type_connector->RegisterDirectoryType(it.Get(), GROUP_PASSIVE);
+  }
+
   ModelSafeRoutingInfo routing_info;
   registrar_->GetModelSafeRoutingInfo(&routing_info);
   SDVLOG(1) << "Control Types " << ModelTypeSetToString(new_control_types)
@@ -152,7 +162,7 @@
   sync_manager_->PurgeDisabledTypes(types_to_purge, ModelTypeSet(),
                                     ModelTypeSet());
   sync_manager_->ConfigureSyncer(
-      reason, new_control_types, routing_info,
+      reason, new_control_types,
       base::Bind(&SyncBackendHostCore::DoInitialProcessControlTypes,
                  weak_ptr_factory_.GetWeakPtr()),
       base::Closure());
@@ -389,11 +399,13 @@
   }
 }
 
-void SyncBackendHostCore::DoStartSyncing(
-    const ModelSafeRoutingInfo& routing_info,
-    base::Time last_poll_time) {
+void SyncBackendHostCore::DoStartConfiguration() {
+  sync_manager_->StartConfiguration();
+}
+
+void SyncBackendHostCore::DoStartSyncing(base::Time last_poll_time) {
   DCHECK(thread_checker_.CalledOnValidThread());
-  sync_manager_->StartSyncingNormally(routing_info, last_poll_time);
+  sync_manager_->StartSyncingNormally(last_poll_time);
 }
 
 void SyncBackendHostCore::DoSetEncryptionPassphrase(
@@ -515,9 +527,6 @@
 
   registrar_->ConfigureDataTypes(params.enabled_types, params.disabled_types);
 
-  ModelSafeRoutingInfo routing_info;
-  registrar_->GetModelSafeRoutingInfo(&routing_info);
-
   base::Closure chained_ready_task(base::Bind(
       &SyncBackendHostCore::DoFinishConfigureDataTypes,
       weak_ptr_factory_.GetWeakPtr(), params.to_download, params.ready_task));
@@ -526,8 +535,7 @@
                  weak_ptr_factory_.GetWeakPtr(), params.retry_callback));
 
   sync_manager_->ConfigureSyncer(params.reason, params.to_download,
-                                 routing_info, chained_ready_task,
-                                 chained_retry_task);
+                                 chained_ready_task, chained_retry_task);
 }
 
 void SyncBackendHostCore::DoFinishConfigureDataTypes(
diff --git a/components/sync/driver/glue/sync_backend_host_core.h b/components/sync/driver/glue/sync_backend_host_core.h
index 787a1eb..c46814b 100644
--- a/components/sync/driver/glue/sync_backend_host_core.h
+++ b/components/sync/driver/glue/sync_backend_host_core.h
@@ -106,10 +106,14 @@
   // SyncEngine::UpdateCredentials.
   void DoUpdateCredentials(const SyncCredentials& credentials);
 
+  // Switches sync engine into configuration mode. In this mode only initial
+  // data for newly enabled types is downloaded from server. No local changes
+  // are committed to server.
+  void DoStartConfiguration();
+
   // Called to tell the syncapi to start syncing (generally after
   // initialization and authentication).
-  void DoStartSyncing(const ModelSafeRoutingInfo& routing_info,
-                      base::Time last_poll_time);
+  void DoStartSyncing(base::Time last_poll_time);
 
   // Called to set the passphrase for encryption.
   void DoSetEncryptionPassphrase(const std::string& passphrase,
diff --git a/components/sync/driver/glue/sync_backend_host_impl.cc b/components/sync/driver/glue/sync_backend_host_impl.cc
index ff1a70e..0106db4c 100644
--- a/components/sync/driver/glue/sync_backend_host_impl.cc
+++ b/components/sync/driver/glue/sync_backend_host_impl.cc
@@ -90,15 +90,17 @@
                             credentials));
 }
 
+void SyncBackendHostImpl::StartConfiguration() {
+  sync_task_runner_->PostTask(
+      FROM_HERE, base::Bind(&SyncBackendHostCore::DoStartConfiguration, core_));
+}
+
 void SyncBackendHostImpl::StartSyncingWithServer() {
   SDVLOG(1) << "SyncBackendHostImpl::StartSyncingWithServer called.";
 
-  ModelSafeRoutingInfo routing_info;
-  registrar_->GetModelSafeRoutingInfo(&routing_info);
-
   sync_task_runner_->PostTask(
       FROM_HERE, base::Bind(&SyncBackendHostCore::DoStartSyncing, core_,
-                            routing_info, sync_prefs_->GetLastPollTime()));
+                            sync_prefs_->GetLastPollTime()));
 }
 
 void SyncBackendHostImpl::SetEncryptionPassphrase(const std::string& passphrase,
@@ -211,6 +213,15 @@
                             base::Passed(&params)));
 }
 
+void SyncBackendHostImpl::RegisterDirectoryDataType(ModelType type,
+                                                    ModelSafeGroup group) {
+  model_type_connector_->RegisterDirectoryType(type, group);
+}
+
+void SyncBackendHostImpl::UnregisterDirectoryDataType(ModelType type) {
+  model_type_connector_->UnregisterDirectoryType(type);
+}
+
 void SyncBackendHostImpl::EnableEncryptEverything() {
   sync_task_runner_->PostTask(
       FROM_HERE,
@@ -234,11 +245,12 @@
   registrar_->RegisterNonBlockingType(type);
   if (activation_context->model_type_state.initial_sync_done())
     registrar_->AddRestoredNonBlockingType(type);
-  model_type_connector_->ConnectType(type, std::move(activation_context));
+  model_type_connector_->ConnectNonBlockingType(type,
+                                                std::move(activation_context));
 }
 
 void SyncBackendHostImpl::DeactivateNonBlockingDataType(ModelType type) {
-  model_type_connector_->DisconnectType(type);
+  model_type_connector_->DisconnectNonBlockingType(type);
 }
 
 UserShare* SyncBackendHostImpl::GetUserShare() const {
diff --git a/components/sync/driver/glue/sync_backend_host_impl.h b/components/sync/driver/glue/sync_backend_host_impl.h
index 4d06288..e7f93eb 100644
--- a/components/sync/driver/glue/sync_backend_host_impl.h
+++ b/components/sync/driver/glue/sync_backend_host_impl.h
@@ -60,6 +60,7 @@
   void Initialize(InitParams params) override;
   void TriggerRefresh(const ModelTypeSet& types) override;
   void UpdateCredentials(const SyncCredentials& credentials) override;
+  void StartConfiguration() override;
   void StartSyncingWithServer() override;
   void SetEncryptionPassphrase(const std::string& passphrase,
                                bool is_explicit) override;
@@ -68,6 +69,8 @@
   void StopSyncingForShutdown() override;
   void Shutdown(ShutdownReason reason) override;
   void ConfigureDataTypes(ConfigureParams params) override;
+  void RegisterDirectoryDataType(ModelType type, ModelSafeGroup group) override;
+  void UnregisterDirectoryDataType(ModelType type) override;
   void ActivateDirectoryDataType(ModelType type,
                                  ModelSafeGroup group,
                                  ChangeProcessor* change_processor) override;
diff --git a/components/sync/driver/glue/sync_backend_host_impl_unittest.cc b/components/sync/driver/glue/sync_backend_host_impl_unittest.cc
index 21d8d42..a96b4b2 100644
--- a/components/sync/driver/glue/sync_backend_host_impl_unittest.cc
+++ b/components/sync/driver/glue/sync_backend_host_impl_unittest.cc
@@ -323,7 +323,6 @@
   EXPECT_TRUE(fake_manager_->GetAndResetDownloadedTypes().HasAll(
       Difference(enabled_types_, ControlTypes())));
   EXPECT_EQ(enabled_types_, fake_manager_->InitialSyncEndedTypes());
-  EXPECT_EQ(enabled_types_, fake_manager_->GetAndResetEnabledTypes());
   EXPECT_TRUE(
       fake_manager_->GetTypesWithEmptyProgressMarkerToken(enabled_types_)
           .Empty());
@@ -353,7 +352,6 @@
       Intersection(fake_manager_->GetAndResetPurgedTypes(), enabled_types_)
           .Empty());
   EXPECT_EQ(enabled_types_, fake_manager_->InitialSyncEndedTypes());
-  EXPECT_EQ(enabled_types_, fake_manager_->GetAndResetEnabledTypes());
   EXPECT_TRUE(
       fake_manager_->GetTypesWithEmptyProgressMarkerToken(enabled_types_)
           .Empty());
@@ -389,7 +387,6 @@
           .Empty());
   EXPECT_EQ(partial_types, fake_manager_->GetAndResetDownloadedTypes());
   EXPECT_EQ(enabled_types_, fake_manager_->InitialSyncEndedTypes());
-  EXPECT_EQ(enabled_types_, fake_manager_->GetAndResetEnabledTypes());
   EXPECT_TRUE(
       fake_manager_->GetTypesWithEmptyProgressMarkerToken(enabled_types_)
           .Empty());
@@ -424,7 +421,6 @@
       Intersection(fake_manager_->GetAndResetPurgedTypes(), enabled_types_)
           .Empty());
   EXPECT_EQ(enabled_types_, fake_manager_->InitialSyncEndedTypes());
-  EXPECT_EQ(enabled_types_, fake_manager_->GetAndResetEnabledTypes());
   EXPECT_TRUE(
       fake_manager_->GetTypesWithEmptyProgressMarkerToken(enabled_types_)
           .Empty());
@@ -459,7 +455,6 @@
   EXPECT_EQ(disabled_types,
             Intersection(fake_manager_->GetAndResetPurgedTypes(), old_types));
   EXPECT_EQ(enabled_types_, fake_manager_->InitialSyncEndedTypes());
-  EXPECT_EQ(enabled_types_, fake_manager_->GetAndResetEnabledTypes());
   EXPECT_TRUE(
       fake_manager_->GetTypesWithEmptyProgressMarkerToken(enabled_types_)
           .Empty());
@@ -495,7 +490,6 @@
       Intersection(fake_manager_->GetAndResetPurgedTypes(), enabled_types_)
           .Empty());
   EXPECT_EQ(enabled_types_, fake_manager_->InitialSyncEndedTypes());
-  EXPECT_EQ(enabled_types_, fake_manager_->GetAndResetEnabledTypes());
   EXPECT_TRUE(
       fake_manager_->GetTypesWithEmptyProgressMarkerToken(enabled_types_)
           .Empty());
@@ -534,7 +528,6 @@
   EXPECT_EQ(disabled_types,
             Intersection(fake_manager_->GetAndResetPurgedTypes(), old_types));
   EXPECT_EQ(enabled_types_, fake_manager_->InitialSyncEndedTypes());
-  EXPECT_EQ(enabled_types_, fake_manager_->GetAndResetEnabledTypes());
   EXPECT_EQ(disabled_types,
             fake_manager_->GetTypesWithEmptyProgressMarkerToken(old_types));
 }
@@ -570,7 +563,6 @@
       Intersection(fake_manager_->GetAndResetPurgedTypes(), enabled_types_)
           .Empty());
   EXPECT_EQ(enabled_types_, fake_manager_->InitialSyncEndedTypes());
-  EXPECT_EQ(enabled_types_, fake_manager_->GetAndResetEnabledTypes());
   EXPECT_TRUE(
       fake_manager_->GetTypesWithEmptyProgressMarkerToken(enabled_types_)
           .Empty());
@@ -612,7 +604,6 @@
       Intersection(fake_manager_->GetAndResetPurgedTypes(), enabled_types_)
           .Empty());
   EXPECT_EQ(enabled_types_, fake_manager_->InitialSyncEndedTypes());
-  EXPECT_EQ(enabled_types_, fake_manager_->GetAndResetEnabledTypes());
   EXPECT_TRUE(
       fake_manager_->GetTypesWithEmptyProgressMarkerToken(enabled_types_)
           .Empty());
diff --git a/components/sync/driver/model_association_manager.cc b/components/sync/driver/model_association_manager.cc
index 382c4f1..e8dae8a 100644
--- a/components/sync/driver/model_association_manager.cc
+++ b/components/sync/driver/model_association_manager.cc
@@ -169,6 +169,7 @@
     if (dtc->state() == DataTypeController::NOT_RUNNING) {
       DCHECK(!loaded_types_.Has(dtc->type()));
       DCHECK(!associated_types_.Has(dtc->type()));
+      delegate_->OnSingleDataTypeWillStart(dtc->type());
       dtc->LoadModels(base::Bind(&ModelAssociationManager::ModelLoadCallback,
                                  weak_ptr_factory_.GetWeakPtr()));
     }
diff --git a/components/sync/driver/model_association_manager.h b/components/sync/driver/model_association_manager.h
index 2f8bd9d..c083d47 100644
--- a/components/sync/driver/model_association_manager.h
+++ b/components/sync/driver/model_association_manager.h
@@ -28,6 +28,10 @@
 // those operations are passed back via this interface.
 class ModelAssociationManagerDelegate {
  public:
+  // Called right before ModelAssociationManager calls LoadModels. Allows
+  // directory types to register with sync engine before download starts.
+  virtual void OnSingleDataTypeWillStart(ModelType type) = 0;
+
   // Called when all desired types are ready to be configured with
   // ModelTypeConfigurer. Data type is ready when its progress marker is
   // available to configurer. Directory data types are always ready, their
diff --git a/components/sync/driver/model_association_manager_unittest.cc b/components/sync/driver/model_association_manager_unittest.cc
index ebb576b5..251bb637 100644
--- a/components/sync/driver/model_association_manager_unittest.cc
+++ b/components/sync/driver/model_association_manager_unittest.cc
@@ -25,6 +25,7 @@
   MOCK_METHOD2(OnSingleDataTypeAssociationDone,
                void(ModelType type,
                     const DataTypeAssociationStats& association_stats));
+  MOCK_METHOD1(OnSingleDataTypeWillStart, void(ModelType type));
   MOCK_METHOD2(OnSingleDataTypeWillStop,
                void(ModelType, const SyncError& error));
   MOCK_METHOD1(OnModelAssociationDone,
@@ -64,6 +65,8 @@
   ModelAssociationManager model_association_manager(&controllers_, &delegate_);
   ModelTypeSet types(BOOKMARKS, APPS);
   DataTypeManager::ConfigureResult expected_result(DataTypeManager::OK, types);
+  EXPECT_CALL(delegate_, OnSingleDataTypeWillStart(BOOKMARKS));
+  EXPECT_CALL(delegate_, OnSingleDataTypeWillStart(APPS));
   EXPECT_CALL(delegate_, OnAllDataTypesReadyForConfigure());
   EXPECT_CALL(delegate_, OnModelAssociationDone(_))
       .WillOnce(VerifyResult(expected_result));
@@ -99,9 +102,9 @@
   ModelTypeSet types;
   types.Put(BOOKMARKS);
 
+  EXPECT_CALL(delegate_, OnSingleDataTypeWillStart(BOOKMARKS));
   DataTypeManager::ConfigureResult expected_result(DataTypeManager::ABORTED,
                                                    types);
-
   EXPECT_CALL(delegate_, OnModelAssociationDone(_))
       .WillOnce(VerifyResult(expected_result));
   EXPECT_CALL(delegate_, OnSingleDataTypeWillStop(BOOKMARKS, _));
@@ -122,6 +125,7 @@
   ModelAssociationManager model_association_manager(&controllers_, &delegate_);
   ModelTypeSet types;
   types.Put(BOOKMARKS);
+  EXPECT_CALL(delegate_, OnSingleDataTypeWillStart(BOOKMARKS));
   DataTypeManager::ConfigureResult expected_result(DataTypeManager::OK, types);
   EXPECT_CALL(delegate_, OnModelAssociationDone(_))
       .WillOnce(VerifyResult(expected_result));
@@ -145,6 +149,7 @@
   ModelAssociationManager model_association_manager(&controllers_, &delegate_);
   ModelTypeSet types;
   types.Put(BOOKMARKS);
+  EXPECT_CALL(delegate_, OnSingleDataTypeWillStart(BOOKMARKS));
   DataTypeManager::ConfigureResult expected_result(DataTypeManager::OK, types);
   EXPECT_CALL(delegate_, OnSingleDataTypeWillStop(BOOKMARKS, _));
   EXPECT_CALL(delegate_, OnModelAssociationDone(_))
@@ -167,6 +172,7 @@
   ModelAssociationManager model_association_manager(&controllers_, &delegate_);
   ModelTypeSet types;
   types.Put(BOOKMARKS);
+  EXPECT_CALL(delegate_, OnSingleDataTypeWillStart(BOOKMARKS));
   DataTypeManager::ConfigureResult expected_result(
       DataTypeManager::UNRECOVERABLE_ERROR, types);
   EXPECT_CALL(delegate_, OnSingleDataTypeWillStop(BOOKMARKS, _));
@@ -195,6 +201,8 @@
   DataTypeManager::ConfigureResult expected_result_partially_done(
       DataTypeManager::OK, types);
 
+  EXPECT_CALL(delegate_, OnSingleDataTypeWillStart(BOOKMARKS));
+  EXPECT_CALL(delegate_, OnSingleDataTypeWillStart(APPS));
   EXPECT_CALL(delegate_, OnModelAssociationDone(_))
       .WillOnce(VerifyResult(expected_result_partially_done));
 
@@ -262,6 +270,7 @@
   ModelTypeSet types;
   types.Put(BOOKMARKS);
   DataTypeManager::ConfigureResult expected_result(DataTypeManager::OK, types);
+  EXPECT_CALL(delegate_, OnSingleDataTypeWillStart(BOOKMARKS));
   EXPECT_CALL(delegate_, OnSingleDataTypeWillStop(BOOKMARKS, _));
   EXPECT_CALL(delegate_, OnModelAssociationDone(_))
       .WillOnce(VerifyResult(expected_result));
@@ -281,6 +290,7 @@
   ModelTypeSet types;
   types.Put(BOOKMARKS);
   DataTypeManager::ConfigureResult expected_result(DataTypeManager::OK, types);
+  EXPECT_CALL(delegate_, OnSingleDataTypeWillStart(BOOKMARKS));
   EXPECT_CALL(delegate_, OnModelAssociationDone(_))
       .WillOnce(VerifyResult(expected_result));
 
@@ -315,6 +325,8 @@
   DataTypeManager::ConfigureResult expected_result_partially_done(
       DataTypeManager::OK, types);
 
+  EXPECT_CALL(delegate_, OnSingleDataTypeWillStart(BOOKMARKS));
+  EXPECT_CALL(delegate_, OnSingleDataTypeWillStart(APPS));
   EXPECT_CALL(delegate_, OnModelAssociationDone(_))
       .WillOnce(VerifyResult(expected_result_partially_done));
 
@@ -350,6 +362,8 @@
   DataTypeManager::ConfigureResult expected_result(DataTypeManager::OK, types);
   // OnAllDataTypesReadyForConfigure shouldn't be called, APPS data type is not
   // loaded yet.
+  EXPECT_CALL(delegate_, OnSingleDataTypeWillStart(BOOKMARKS));
+  EXPECT_CALL(delegate_, OnSingleDataTypeWillStart(APPS));
   EXPECT_CALL(delegate_, OnAllDataTypesReadyForConfigure()).Times(0);
 
   model_association_manager.Initialize(types);
@@ -395,6 +409,7 @@
   DataTypeManager::ConfigureResult expected_result(DataTypeManager::OK, types);
   // OnAllDataTypesReadyForConfigure shouldn't be called, APPS data type is not
   // loaded yet.
+  EXPECT_CALL(delegate_, OnSingleDataTypeWillStart(APPS));
   EXPECT_CALL(delegate_, OnAllDataTypesReadyForConfigure()).Times(0);
 
   model_association_manager.Initialize(types);
@@ -436,6 +451,8 @@
 
   // Apps will finish loading but bookmarks won't.
   // OnAllDataTypesReadyForConfigure shouldn't be called.
+  EXPECT_CALL(delegate_, OnSingleDataTypeWillStart(BOOKMARKS));
+  EXPECT_CALL(delegate_, OnSingleDataTypeWillStart(APPS));
   EXPECT_CALL(delegate_, OnAllDataTypesReadyForConfigure()).Times(0);
 
   model_association_manager.Initialize(types);
diff --git a/components/sync/driver/model_type_controller.cc b/components/sync/driver/model_type_controller.cc
index b0d28cf0..c85cf6c 100644
--- a/components/sync/driver/model_type_controller.cc
+++ b/components/sync/driver/model_type_controller.cc
@@ -127,18 +127,7 @@
                             std::move(error_handler), std::move(callback)));
 }
 
-void ModelTypeController::GetAllNodes(const AllNodesCallback& callback) {
-  model_thread_->PostTask(
-      FROM_HERE, base::Bind(&CallGetAllNodesHelper, sync_client_, type(),
-                            BindToCurrentThread(callback)));
-}
-
-void ModelTypeController::GetStatusCounters(
-    const StatusCountersCallback& callback) {
-  model_thread_->PostTask(
-      FROM_HERE,
-      base::Bind(&CallGetStatusCountersHelper, sync_client_, type(), callback));
-}
+void ModelTypeController::BeforeLoadModels(ModelTypeConfigurer* configurer) {}
 
 void ModelTypeController::LoadModelsDone(ConfigureResult result,
                                          const SyncError& error) {
@@ -253,6 +242,19 @@
   return state_;
 }
 
+void ModelTypeController::GetAllNodes(const AllNodesCallback& callback) {
+  model_thread_->PostTask(
+      FROM_HERE, base::Bind(&CallGetAllNodesHelper, sync_client_, type(),
+                            BindToCurrentThread(callback)));
+}
+
+void ModelTypeController::GetStatusCounters(
+    const StatusCountersCallback& callback) {
+  model_thread_->PostTask(
+      FROM_HERE,
+      base::Bind(&CallGetStatusCountersHelper, sync_client_, type(), callback));
+}
+
 void ModelTypeController::ReportModelError(const ModelError& error) {
   DCHECK(CalledOnValidThread());
   LoadModelsDone(UNRECOVERABLE_ERROR,
diff --git a/components/sync/driver/model_type_controller.h b/components/sync/driver/model_type_controller.h
index 92152d7..9092526 100644
--- a/components/sync/driver/model_type_controller.h
+++ b/components/sync/driver/model_type_controller.h
@@ -35,9 +35,8 @@
 
   // DataTypeController implementation.
   bool ShouldLoadModelBeforeConfigure() const override;
+  void BeforeLoadModels(ModelTypeConfigurer* configurer) override;
   void LoadModels(const ModelLoadCallback& model_load_callback) override;
-  void GetAllNodes(const AllNodesCallback& callback) override;
-  void GetStatusCounters(const StatusCountersCallback& callback) override;
   void RegisterWithBackend(base::Callback<void(bool)> set_downloaded,
                            ModelTypeConfigurer* configurer) override;
   void StartAssociating(const StartCallback& start_callback) override;
@@ -46,6 +45,8 @@
   void Stop() override;
   std::string name() const override;
   State state() const override;
+  void GetAllNodes(const AllNodesCallback& callback) override;
+  void GetStatusCounters(const StatusCountersCallback& callback) override;
 
  private:
   void RecordStartFailure(ConfigureResult result) const;
diff --git a/components/sync/driver/model_type_controller_unittest.cc b/components/sync/driver/model_type_controller_unittest.cc
index bf7ef71..1de8370 100644
--- a/components/sync/driver/model_type_controller_unittest.cc
+++ b/components/sync/driver/model_type_controller_unittest.cc
@@ -92,6 +92,15 @@
     NOTREACHED() << "Not implemented.";
   }
 
+  void RegisterDirectoryDataType(ModelType type,
+                                 ModelSafeGroup group) override {
+    NOTREACHED() << "Not implemented.";
+  }
+
+  void UnregisterDirectoryDataType(ModelType type) override {
+    NOTREACHED() << "Not implemented.";
+  }
+
   void ActivateDirectoryDataType(ModelType type,
                                  ModelSafeGroup group,
                                  ChangeProcessor* change_processor) override {
diff --git a/components/sync/driver/proxy_data_type_controller.cc b/components/sync/driver/proxy_data_type_controller.cc
index 16e291e0..0c1beb6cd 100644
--- a/components/sync/driver/proxy_data_type_controller.cc
+++ b/components/sync/driver/proxy_data_type_controller.cc
@@ -21,6 +21,9 @@
   return false;
 }
 
+void ProxyDataTypeController::BeforeLoadModels(
+    ModelTypeConfigurer* configurer) {}
+
 void ProxyDataTypeController::LoadModels(
     const ModelLoadCallback& model_load_callback) {
   DCHECK(CalledOnValidThread());
diff --git a/components/sync/driver/proxy_data_type_controller.h b/components/sync/driver/proxy_data_type_controller.h
index 635e656..2036f2a 100644
--- a/components/sync/driver/proxy_data_type_controller.h
+++ b/components/sync/driver/proxy_data_type_controller.h
@@ -23,6 +23,7 @@
 
   // DataTypeController interface.
   bool ShouldLoadModelBeforeConfigure() const override;
+  void BeforeLoadModels(ModelTypeConfigurer* configurer) override;
   void LoadModels(const ModelLoadCallback& model_load_callback) override;
   void RegisterWithBackend(base::Callback<void(bool)> set_downloaded,
                            ModelTypeConfigurer* configurer) override;
diff --git a/components/sync/engine/fake_model_type_connector.cc b/components/sync/engine/fake_model_type_connector.cc
index 59b80266..5142c12 100644
--- a/components/sync/engine/fake_model_type_connector.cc
+++ b/components/sync/engine/fake_model_type_connector.cc
@@ -12,10 +12,15 @@
 
 FakeModelTypeConnector::~FakeModelTypeConnector() {}
 
-void FakeModelTypeConnector::ConnectType(
+void FakeModelTypeConnector::ConnectNonBlockingType(
     ModelType type,
     std::unique_ptr<ActivationContext> activation_context) {}
 
-void FakeModelTypeConnector::DisconnectType(ModelType type) {}
+void FakeModelTypeConnector::DisconnectNonBlockingType(ModelType type) {}
+
+void FakeModelTypeConnector::RegisterDirectoryType(ModelType type,
+                                                   ModelSafeGroup group) {}
+
+void FakeModelTypeConnector::UnregisterDirectoryType(ModelType type) {}
 
 }  // namespace syncer
diff --git a/components/sync/engine/fake_model_type_connector.h b/components/sync/engine/fake_model_type_connector.h
index 7c47378..978e24aa 100644
--- a/components/sync/engine/fake_model_type_connector.h
+++ b/components/sync/engine/fake_model_type_connector.h
@@ -17,10 +17,12 @@
   FakeModelTypeConnector();
   ~FakeModelTypeConnector() override;
 
-  void ConnectType(
+  void ConnectNonBlockingType(
       ModelType type,
       std::unique_ptr<ActivationContext> activation_context) override;
-  void DisconnectType(ModelType type) override;
+  void DisconnectNonBlockingType(ModelType type) override;
+  void RegisterDirectoryType(ModelType type, ModelSafeGroup group) override;
+  void UnregisterDirectoryType(ModelType type) override;
 };
 
 }  // namespace syncer
diff --git a/components/sync/engine/fake_sync_engine.cc b/components/sync/engine/fake_sync_engine.cc
index e40e673..8b35a10e 100644
--- a/components/sync/engine/fake_sync_engine.cc
+++ b/components/sync/engine/fake_sync_engine.cc
@@ -24,6 +24,8 @@
 
 void FakeSyncEngine::UpdateCredentials(const SyncCredentials& credentials) {}
 
+void FakeSyncEngine::StartConfiguration() {}
+
 void FakeSyncEngine::StartSyncingWithServer() {}
 
 void FakeSyncEngine::SetEncryptionPassphrase(const std::string& passphrase,
@@ -39,6 +41,11 @@
 
 void FakeSyncEngine::ConfigureDataTypes(ConfigureParams params) {}
 
+void FakeSyncEngine::RegisterDirectoryDataType(ModelType type,
+                                               ModelSafeGroup group) {}
+
+void FakeSyncEngine::UnregisterDirectoryDataType(ModelType type) {}
+
 void FakeSyncEngine::EnableEncryptEverything() {}
 
 void FakeSyncEngine::ActivateDirectoryDataType(
diff --git a/components/sync/engine/fake_sync_engine.h b/components/sync/engine/fake_sync_engine.h
index 70f3627..b71bec9 100644
--- a/components/sync/engine/fake_sync_engine.h
+++ b/components/sync/engine/fake_sync_engine.h
@@ -32,6 +32,8 @@
 
   void UpdateCredentials(const SyncCredentials& credentials) override;
 
+  void StartConfiguration() override;
+
   void StartSyncingWithServer() override;
 
   void SetEncryptionPassphrase(const std::string& passphrase,
@@ -45,6 +47,10 @@
 
   void ConfigureDataTypes(ConfigureParams params) override;
 
+  void RegisterDirectoryDataType(ModelType type, ModelSafeGroup group) override;
+
+  void UnregisterDirectoryDataType(ModelType type) override;
+
   void EnableEncryptEverything() override;
 
   void ActivateDirectoryDataType(ModelType type,
diff --git a/components/sync/engine/fake_sync_manager.cc b/components/sync/engine/fake_sync_manager.cc
index b97e933..e9f9ce8 100644
--- a/components/sync/engine/fake_sync_manager.cc
+++ b/components/sync/engine/fake_sync_manager.cc
@@ -17,10 +17,8 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "components/sync/base/weak_handle.h"
 #include "components/sync/engine/engine_components_factory.h"
-#include "components/sync/engine/fake_model_type_connector.h"
 #include "components/sync/engine/net/http_post_provider_factory.h"
 #include "components/sync/syncable/directory.h"
-#include "components/sync/test/fake_sync_encryption_handler.h"
 
 class GURL;
 
@@ -33,9 +31,7 @@
       progress_marker_types_(progress_marker_types),
       configure_fail_types_(configure_fail_types),
       last_configure_reason_(CONFIGURE_REASON_UNKNOWN),
-      num_invalidations_received_(0) {
-  fake_encryption_handler_ = base::MakeUnique<FakeSyncEncryptionHandler>();
-}
+      num_invalidations_received_(0) {}
 
 FakeSyncManager::~FakeSyncManager() {}
 
@@ -57,12 +53,6 @@
   return downloaded_types;
 }
 
-ModelTypeSet FakeSyncManager::GetAndResetEnabledTypes() {
-  ModelTypeSet enabled_types = enabled_types_;
-  enabled_types_.Clear();
-  return enabled_types;
-}
-
 ConfigureReason FakeSyncManager::GetAndResetConfigureReason() {
   ConfigureReason reason = last_configure_reason_;
   last_configure_reason_ = CONFIGURE_REASON_UNKNOWN;
@@ -144,20 +134,20 @@
   NOTIMPLEMENTED();
 }
 
-void FakeSyncManager::StartSyncingNormally(
-    const ModelSafeRoutingInfo& routing_info,
-    base::Time last_poll_time) {
+void FakeSyncManager::StartSyncingNormally(base::Time last_poll_time) {
+  // Do nothing.
+}
+
+void FakeSyncManager::StartConfiguration() {
   // Do nothing.
 }
 
 void FakeSyncManager::ConfigureSyncer(
     ConfigureReason reason,
     ModelTypeSet to_download,
-    const ModelSafeRoutingInfo& new_routing_info,
     const base::Closure& ready_task,
     const base::Closure& retry_task) {
   last_configure_reason_ = reason;
-  enabled_types_ = GetRoutingInfoTypes(new_routing_info);
   ModelTypeSet success_types = to_download;
   success_types.RemoveAll(configure_fail_types_);
 
@@ -208,6 +198,10 @@
   return test_user_share_.user_share();
 }
 
+ModelTypeConnector* FakeSyncManager::GetModelTypeConnector() {
+  return &fake_model_type_connector_;
+}
+
 std::unique_ptr<ModelTypeConnector>
 FakeSyncManager::GetModelTypeConnectorProxy() {
   return base::MakeUnique<FakeModelTypeConnector>();
@@ -227,7 +221,7 @@
 }
 
 SyncEncryptionHandler* FakeSyncManager::GetEncryptionHandler() {
-  return fake_encryption_handler_.get();
+  return &fake_encryption_handler_;
 }
 
 std::vector<std::unique_ptr<ProtocolEvent>>
diff --git a/components/sync/engine/fake_sync_manager.h b/components/sync/engine/fake_sync_manager.h
index 31f47440..8098e4dc 100644
--- a/components/sync/engine/fake_sync_manager.h
+++ b/components/sync/engine/fake_sync_manager.h
@@ -12,8 +12,10 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/observer_list.h"
+#include "components/sync/engine/fake_model_type_connector.h"
 #include "components/sync/engine/sync_manager.h"
 #include "components/sync/syncable/test_user_share.h"
+#include "components/sync/test/fake_sync_encryption_handler.h"
 
 namespace base {
 class SequencedTaskRunner;
@@ -55,11 +57,6 @@
   // GetAndResetDownloadedTypes(), or since startup if never called.
   ModelTypeSet GetAndResetDownloadedTypes();
 
-  // Returns those types that have been marked as enabled since the
-  // last call to GetAndResetEnabledTypes(), or since startup if never
-  // called.
-  ModelTypeSet GetAndResetEnabledTypes();
-
   // Returns the types that have most recently received a refresh request.
   ModelTypeSet GetLastRefreshRequestTypes();
 
@@ -85,11 +82,10 @@
                           ModelTypeSet to_journal,
                           ModelTypeSet to_unapply) override;
   void UpdateCredentials(const SyncCredentials& credentials) override;
-  void StartSyncingNormally(const ModelSafeRoutingInfo& routing_info,
-                            base::Time last_poll_time) override;
+  void StartSyncingNormally(base::Time last_poll_time) override;
+  void StartConfiguration() override;
   void ConfigureSyncer(ConfigureReason reason,
                        ModelTypeSet to_download,
-                       const ModelSafeRoutingInfo& new_routing_info,
                        const base::Closure& ready_task,
                        const base::Closure& retry_task) override;
   void OnIncomingInvalidation(
@@ -102,6 +98,7 @@
   void SaveChanges() override;
   void ShutdownOnSyncThread(ShutdownReason reason) override;
   UserShare* GetUserShare() override;
+  ModelTypeConnector* GetModelTypeConnector() override;
   std::unique_ptr<ModelTypeConnector> GetModelTypeConnectorProxy() override;
   const std::string cache_guid() override;
   bool ReceivedExperiment(Experiments* experiments) override;
@@ -140,8 +137,6 @@
   ModelTypeSet unapplied_types_;
   // The set of types that have been downloaded.
   ModelTypeSet downloaded_types_;
-  // The set of types that have been enabled.
-  ModelTypeSet enabled_types_;
 
   // The types for which a refresh was most recently requested.
   ModelTypeSet last_refresh_request_types_;
@@ -149,7 +144,9 @@
   // The most recent configure reason.
   ConfigureReason last_configure_reason_;
 
-  std::unique_ptr<FakeSyncEncryptionHandler> fake_encryption_handler_;
+  FakeModelTypeConnector fake_model_type_connector_;
+
+  FakeSyncEncryptionHandler fake_encryption_handler_;
 
   TestUserShare test_user_share_;
 
diff --git a/components/sync/engine/model_type_configurer.h b/components/sync/engine/model_type_configurer.h
index a913a35..72d0951 100644
--- a/components/sync/engine/model_type_configurer.h
+++ b/components/sync/engine/model_type_configurer.h
@@ -56,6 +56,16 @@
   // Changes the set of data types that are currently being synced.
   virtual void ConfigureDataTypes(ConfigureParams params) = 0;
 
+  // Registers directory type with sync engine. This function creates update
+  // handler for the type and thus needs to be called before ConfigureDataType
+  // that includes the type in |to_download| type set.
+  virtual void RegisterDirectoryDataType(ModelType type,
+                                         ModelSafeGroup group) = 0;
+
+  // Unregisters directory type from sync engine. After this call updates and
+  // local change will not be synced with server.
+  virtual void UnregisterDirectoryDataType(ModelType type) = 0;
+
   // Activates change processing for the given directory data type.  This must
   // be called synchronously with the data type's model association so
   // no changes are dropped between model association and change
diff --git a/components/sync/engine/model_type_connector.h b/components/sync/engine/model_type_connector.h
index 1917100..d95d8de 100644
--- a/components/sync/engine/model_type_connector.h
+++ b/components/sync/engine/model_type_connector.h
@@ -8,13 +8,17 @@
 #include <memory>
 
 #include "components/sync/base/model_type.h"
+#include "components/sync/engine/model_safe_worker.h"
 
 namespace syncer {
 struct ActivationContext;
 
-// An interface into the core parts of sync for USS model types. Handles
-// creating the connection between the ModelTypeWorker (CommitQueue) on the sync
-// side and the (Shared)ModelTypeProcessor on the model type side.
+// An interface into the core parts of sync for model types. By adding/removing
+// types through methods of this interface consumer controls which types will be
+// syncing (receiving updates and committing local changes).
+// In addition it handles creating the connection between the ModelTypeWorker
+// (CommitQueue) on the sync side and the (Shared)ModelTypeProcessor on the
+// model type side for non-blocking types.
 class ModelTypeConnector {
  public:
   ModelTypeConnector();
@@ -24,7 +28,7 @@
   // thread. Note that in production |activation_context| actually owns a
   // processor proxy that forwards calls to the model thread and is safe to call
   // from the sync thread.
-  virtual void ConnectType(
+  virtual void ConnectNonBlockingType(
       ModelType type,
       std::unique_ptr<ActivationContext> activation_context) = 0;
 
@@ -33,7 +37,16 @@
   // This is the sync thread's chance to clear state associated with the type.
   // It also causes the syncer to stop requesting updates for this type, and to
   // abort any in-progress commit requests.
-  virtual void DisconnectType(ModelType type) = 0;
+  virtual void DisconnectNonBlockingType(ModelType type) = 0;
+
+  // Registers directory based type with sync engine. Sync engine will create
+  // update handler and commit contributor objects for this type. It will start
+  // including the type in GetUpdates and commit requests.
+  virtual void RegisterDirectoryType(ModelType type, ModelSafeGroup group) = 0;
+
+  // Unregisters directory based type from sync engine. Type will no longer be
+  // included in communications with server.
+  virtual void UnregisterDirectoryType(ModelType type) = 0;
 };
 
 }  // namespace syncer
diff --git a/components/sync/engine/sync_engine.h b/components/sync/engine/sync_engine.h
index af4e53d0..55cd760c 100644
--- a/components/sync/engine/sync_engine.h
+++ b/components/sync/engine/sync_engine.h
@@ -95,6 +95,11 @@
   // Updates the engine's SyncCredentials.
   virtual void UpdateCredentials(const SyncCredentials& credentials) = 0;
 
+  // Switches sync engine into configuration mode. In this mode only initial
+  // data for newly enabled types is downloaded from server. No local changes
+  // are committed to server.
+  virtual void StartConfiguration() = 0;
+
   // This starts the sync engine running a Syncer object to communicate with
   // sync servers. Until this is called, no changes will leave or enter this
   // browser from the cloud / sync servers.
diff --git a/components/sync/engine/sync_manager.h b/components/sync/engine/sync_manager.h
index 37e7de63..b853b54 100644
--- a/components/sync/engine/sync_manager.h
+++ b/components/sync/engine/sync_manager.h
@@ -304,8 +304,11 @@
   virtual void UpdateCredentials(const SyncCredentials& credentials) = 0;
 
   // Put the syncer in normal mode ready to perform nudges and polls.
-  virtual void StartSyncingNormally(const ModelSafeRoutingInfo& routing_info,
-                                    base::Time last_poll_time) = 0;
+  virtual void StartSyncingNormally(base::Time last_poll_time) = 0;
+
+  // Put syncer in configuration mode. Only configuration sync cycles are
+  // performed. No local changes are committed to the server.
+  virtual void StartConfiguration() = 0;
 
   // Switches the mode of operation to CONFIGURATION_MODE and performs
   // any configuration tasks needed as determined by the params. Once complete,
@@ -317,7 +320,6 @@
   //              does finish.
   virtual void ConfigureSyncer(ConfigureReason reason,
                                ModelTypeSet to_download,
-                               const ModelSafeRoutingInfo& new_routing_info,
                                const base::Closure& ready_task,
                                const base::Closure& retry_task) = 0;
 
@@ -352,7 +354,13 @@
   // May be called from any thread.
   virtual UserShare* GetUserShare() = 0;
 
-  // Returns an instance of the main interface for non-blocking sync types.
+  // Returns non-owning pointer to ModelTypeConnector. In contrast with
+  // ModelTypeConnectorProxy all calls are executed synchronously, thus the
+  // pointer should be used on sync thread.
+  virtual ModelTypeConnector* GetModelTypeConnector() = 0;
+
+  // Returns an instance of the main interface for registering sync types with
+  // sync engine.
   virtual std::unique_ptr<ModelTypeConnector> GetModelTypeConnectorProxy() = 0;
 
   // Returns the cache_guid of the currently open database.
diff --git a/components/sync/engine_impl/cycle/sync_cycle.h b/components/sync/engine_impl/cycle/sync_cycle.h
index e25fad03..72c0789 100644
--- a/components/sync/engine_impl/cycle/sync_cycle.h
+++ b/components/sync/engine_impl/cycle/sync_cycle.h
@@ -16,7 +16,6 @@
 #include "base/time/time.h"
 #include "components/sync/base/model_type.h"
 #include "components/sync/engine/cycle/sync_cycle_snapshot.h"
-#include "components/sync/engine/model_safe_worker.h"
 #include "components/sync/engine_impl/cycle/status_controller.h"
 #include "components/sync/engine_impl/cycle/sync_cycle_context.h"
 #include "components/sync/engine_impl/sync_cycle_event.h"
diff --git a/components/sync/engine_impl/cycle/sync_cycle_context.cc b/components/sync/engine_impl/cycle/sync_cycle_context.cc
index 744fa4bc..c50ea25 100644
--- a/components/sync/engine_impl/cycle/sync_cycle_context.cc
+++ b/components/sync/engine_impl/cycle/sync_cycle_context.cc
@@ -43,9 +43,4 @@
   return model_type_registry_->GetEnabledTypes();
 }
 
-void SyncCycleContext::SetRoutingInfo(
-    const ModelSafeRoutingInfo& routing_info) {
-  model_type_registry_->SetEnabledDirectoryTypes(routing_info);
-}
-
 }  // namespace syncer
diff --git a/components/sync/engine_impl/cycle/sync_cycle_context.h b/components/sync/engine_impl/cycle/sync_cycle_context.h
index b7d50de..1e7e0aef 100644
--- a/components/sync/engine_impl/cycle/sync_cycle_context.h
+++ b/components/sync/engine_impl/cycle/sync_cycle_context.h
@@ -56,8 +56,6 @@
 
   ModelTypeSet GetEnabledTypes() const;
 
-  void SetRoutingInfo(const ModelSafeRoutingInfo& routing_info);
-
   ExtensionsActivity* extensions_activity() {
     return extensions_activity_.get();
   }
diff --git a/components/sync/engine_impl/model_type_connector_proxy.cc b/components/sync/engine_impl/model_type_connector_proxy.cc
index c863117..86adea02 100644
--- a/components/sync/engine_impl/model_type_connector_proxy.cc
+++ b/components/sync/engine_impl/model_type_connector_proxy.cc
@@ -18,19 +18,32 @@
 
 ModelTypeConnectorProxy::~ModelTypeConnectorProxy() {}
 
-void ModelTypeConnectorProxy::ConnectType(
+void ModelTypeConnectorProxy::ConnectNonBlockingType(
     ModelType type,
     std::unique_ptr<ActivationContext> activation_context) {
-  task_runner_->PostTask(
-      FROM_HERE,
-      base::Bind(&ModelTypeConnector::ConnectType, model_type_connector_, type,
-                 base::Passed(&activation_context)));
+  task_runner_->PostTask(FROM_HERE,
+                         base::Bind(&ModelTypeConnector::ConnectNonBlockingType,
+                                    model_type_connector_, type,
+                                    base::Passed(&activation_context)));
 }
 
-void ModelTypeConnectorProxy::DisconnectType(ModelType type) {
+void ModelTypeConnectorProxy::DisconnectNonBlockingType(ModelType type) {
+  task_runner_->PostTask(
+      FROM_HERE, base::Bind(&ModelTypeConnector::DisconnectNonBlockingType,
+                            model_type_connector_, type));
+}
+
+void ModelTypeConnectorProxy::RegisterDirectoryType(ModelType type,
+                                                    ModelSafeGroup group) {
   task_runner_->PostTask(FROM_HERE,
-                         base::Bind(&ModelTypeConnector::DisconnectType,
-                                    model_type_connector_, type));
+                         base::Bind(&ModelTypeConnector::RegisterDirectoryType,
+                                    model_type_connector_, type, group));
+}
+
+void ModelTypeConnectorProxy::UnregisterDirectoryType(ModelType type) {
+  task_runner_->PostTask(
+      FROM_HERE, base::Bind(&ModelTypeConnector::UnregisterDirectoryType,
+                            model_type_connector_, type));
 }
 
 }  // namespace syncer
diff --git a/components/sync/engine_impl/model_type_connector_proxy.h b/components/sync/engine_impl/model_type_connector_proxy.h
index ddf751b..6c2e4a9 100644
--- a/components/sync/engine_impl/model_type_connector_proxy.h
+++ b/components/sync/engine_impl/model_type_connector_proxy.h
@@ -10,6 +10,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/sequenced_task_runner.h"
 #include "components/sync/base/model_type.h"
+#include "components/sync/engine/model_safe_worker.h"
 #include "components/sync/engine/model_type_connector.h"
 
 namespace syncer {
@@ -25,10 +26,12 @@
   ~ModelTypeConnectorProxy() override;
 
   // ModelTypeConnector implementation
-  void ConnectType(
+  void ConnectNonBlockingType(
       ModelType type,
       std::unique_ptr<ActivationContext> activation_context) override;
-  void DisconnectType(ModelType type) override;
+  void DisconnectNonBlockingType(ModelType type) override;
+  void RegisterDirectoryType(ModelType type, ModelSafeGroup group) override;
+  void UnregisterDirectoryType(ModelType type) override;
 
  private:
   // A SequencedTaskRunner representing the thread where the ModelTypeConnector
diff --git a/components/sync/engine_impl/model_type_registry.cc b/components/sync/engine_impl/model_type_registry.cc
index 72450f4..33af9514 100644
--- a/components/sync/engine_impl/model_type_registry.cc
+++ b/components/sync/engine_impl/model_type_registry.cc
@@ -71,72 +71,7 @@
 
 ModelTypeRegistry::~ModelTypeRegistry() {}
 
-void ModelTypeRegistry::SetEnabledDirectoryTypes(
-    const ModelSafeRoutingInfo& routing_info) {
-  // Remove all existing directory processors and delete them.  The
-  // DebugInfoEmitters are not deleted here, since we want to preserve their
-  // counters.
-  for (ModelTypeSet::Iterator it = enabled_directory_types_.First(); it.Good();
-       it.Inc()) {
-    size_t result1 = update_handler_map_.erase(it.Get());
-    size_t result2 = commit_contributor_map_.erase(it.Get());
-    DCHECK_EQ(1U, result1);
-    DCHECK_EQ(1U, result2);
-  }
-
-  // Clear the old instances of directory update handlers and commit
-  // contributors, deleting their contents in the processs.
-  directory_update_handlers_.clear();
-  directory_commit_contributors_.clear();
-
-  enabled_directory_types_.Clear();
-
-  // Create new ones and add them to the appropriate containers.
-  for (const auto& routing_kv : routing_info) {
-    ModelType type = routing_kv.first;
-    ModelSafeGroup group = routing_kv.second;
-    if (group == GROUP_NON_BLOCKING)
-      continue;
-
-    std::map<ModelSafeGroup, scoped_refptr<ModelSafeWorker>>::iterator
-        worker_it = workers_map_.find(group);
-    DCHECK(worker_it != workers_map_.end());
-    scoped_refptr<ModelSafeWorker> worker = worker_it->second;
-
-    DataTypeDebugInfoEmitter* emitter = GetEmitter(type);
-    if (emitter == nullptr) {
-      auto new_emitter = base::MakeUnique<DirectoryTypeDebugInfoEmitter>(
-          directory(), type, &type_debug_info_observers_);
-      emitter = new_emitter.get();
-      data_type_debug_info_emitter_map_.insert(
-          std::make_pair(type, std::move(new_emitter)));
-    }
-
-    auto updater = base::MakeUnique<DirectoryUpdateHandler>(directory(), type,
-                                                            worker, emitter);
-    bool updater_inserted =
-        update_handler_map_.insert(std::make_pair(type, updater.get())).second;
-    DCHECK(updater_inserted)
-        << "Attempt to override existing type handler in map";
-    directory_update_handlers_.push_back(std::move(updater));
-
-    auto committer = base::MakeUnique<DirectoryCommitContributor>(
-        directory(), type, emitter);
-    bool committer_inserted =
-        commit_contributor_map_.insert(std::make_pair(type, committer.get()))
-            .second;
-    DCHECK(committer_inserted)
-        << "Attempt to override existing type handler in map";
-    directory_commit_contributors_.push_back(std::move(committer));
-
-    enabled_directory_types_.Put(type);
-  }
-
-  DCHECK(Intersection(GetEnabledDirectoryTypes(), GetEnabledNonBlockingTypes())
-             .Empty());
-}
-
-void ModelTypeRegistry::ConnectType(
+void ModelTypeRegistry::ConnectNonBlockingType(
     ModelType type,
     std::unique_ptr<ActivationContext> activation_context) {
   DCHECK(update_handler_map_.find(type) == update_handler_map_.end());
@@ -204,7 +139,7 @@
              .Empty());
 }
 
-void ModelTypeRegistry::DisconnectType(ModelType type) {
+void ModelTypeRegistry::DisconnectNonBlockingType(ModelType type) {
   DVLOG(1) << "Disabling an off-thread sync type: " << ModelTypeToString(type);
   DCHECK(update_handler_map_.find(type) != update_handler_map_.end());
   DCHECK(commit_contributor_map_.find(type) != commit_contributor_map_.end());
@@ -225,6 +160,58 @@
   }
 }
 
+void ModelTypeRegistry::RegisterDirectoryType(ModelType type,
+                                              ModelSafeGroup group) {
+  DCHECK(update_handler_map_.find(type) == update_handler_map_.end());
+  DCHECK(commit_contributor_map_.find(type) == commit_contributor_map_.end());
+  DCHECK(directory_update_handlers_.find(type) ==
+         directory_update_handlers_.end());
+  DCHECK(directory_commit_contributors_.find(type) ==
+         directory_commit_contributors_.end());
+  DCHECK(data_type_debug_info_emitter_map_.find(type) ==
+         data_type_debug_info_emitter_map_.end());
+  DCHECK_NE(GROUP_NON_BLOCKING, group);
+  DCHECK(workers_map_.find(group) != workers_map_.end());
+
+  auto worker = workers_map_[group];
+  DCHECK(GetEmitter(type) == nullptr);
+  auto owned_emitter = base::MakeUnique<DirectoryTypeDebugInfoEmitter>(
+      directory(), type, &type_debug_info_observers_);
+  DataTypeDebugInfoEmitter* emitter_ptr = owned_emitter.get();
+  data_type_debug_info_emitter_map_[type] = std::move(owned_emitter);
+
+  auto updater = base::MakeUnique<DirectoryUpdateHandler>(directory(), type,
+                                                          worker, emitter_ptr);
+  auto committer = base::MakeUnique<DirectoryCommitContributor>(
+      directory(), type, emitter_ptr);
+
+  update_handler_map_[type] = updater.get();
+  commit_contributor_map_[type] = committer.get();
+
+  directory_update_handlers_[type] = std::move(updater);
+  directory_commit_contributors_[type] = std::move(committer);
+
+  DCHECK(Intersection(GetEnabledDirectoryTypes(), GetEnabledNonBlockingTypes())
+             .Empty());
+}
+
+void ModelTypeRegistry::UnregisterDirectoryType(ModelType type) {
+  DCHECK(update_handler_map_.find(type) != update_handler_map_.end());
+  DCHECK(commit_contributor_map_.find(type) != commit_contributor_map_.end());
+  DCHECK(directory_update_handlers_.find(type) !=
+         directory_update_handlers_.end());
+  DCHECK(directory_commit_contributors_.find(type) !=
+         directory_commit_contributors_.end());
+  DCHECK(data_type_debug_info_emitter_map_.find(type) !=
+         data_type_debug_info_emitter_map_.end());
+
+  update_handler_map_.erase(type);
+  commit_contributor_map_.erase(type);
+  directory_update_handlers_.erase(type);
+  directory_commit_contributors_.erase(type);
+  data_type_debug_info_emitter_map_.erase(type);
+}
+
 ModelTypeSet ModelTypeRegistry::GetEnabledTypes() const {
   return Union(GetEnabledDirectoryTypes(), GetEnabledNonBlockingTypes());
 }
@@ -351,7 +338,10 @@
 }
 
 ModelTypeSet ModelTypeRegistry::GetEnabledDirectoryTypes() const {
-  return enabled_directory_types_;
+  ModelTypeSet enabled_directory_types;
+  for (const auto& kv : directory_update_handlers_)
+    enabled_directory_types.Put(kv.first);
+  return enabled_directory_types;
 }
 
 ModelTypeSet ModelTypeRegistry::GetEnabledNonBlockingTypes() const {
diff --git a/components/sync/engine_impl/model_type_registry.h b/components/sync/engine_impl/model_type_registry.h
index 5229f0d6..3e25257 100644
--- a/components/sync/engine_impl/model_type_registry.h
+++ b/components/sync/engine_impl/model_type_registry.h
@@ -38,21 +38,17 @@
 class ModelTypeRegistry : public ModelTypeConnector,
                           public SyncEncryptionHandler::Observer {
  public:
-  // Constructs a ModelTypeRegistry that supports directory types.
   ModelTypeRegistry(const std::vector<scoped_refptr<ModelSafeWorker>>& workers,
                     UserShare* user_share,
                     NudgeHandler* nudge_handler,
                     const UssMigrator& uss_migrator);
   ~ModelTypeRegistry() override;
 
-  // Sets the set of enabled types.
-  void SetEnabledDirectoryTypes(const ModelSafeRoutingInfo& routing_info);
-
   // Enables an off-thread type for syncing.  Connects the given proxy
   // and its task_runner to the newly created worker.
   //
   // Expects that the proxy's ModelType is not currently enabled.
-  void ConnectType(
+  void ConnectNonBlockingType(
       ModelType type,
       std::unique_ptr<ActivationContext> activation_context) override;
 
@@ -60,7 +56,15 @@
   //
   // Expects that the type is currently enabled.
   // Deletes the worker associated with the type.
-  void DisconnectType(ModelType type) override;
+  void DisconnectNonBlockingType(ModelType type) override;
+
+  // Creates update handler and commit contributor objects for directory type.
+  // Expects that the type is not yet registered.
+  void RegisterDirectoryType(ModelType type, ModelSafeGroup group) override;
+
+  // Deletes objects related to directory type. Expects that the type is
+  // registered.
+  void UnregisterDirectoryType(ModelType type) override;
 
   // Implementation of SyncEncryptionHandler::Observer.
   void OnPassphraseRequired(
@@ -118,9 +122,9 @@
   }
 
   // Sets of handlers and contributors.
-  std::vector<std::unique_ptr<DirectoryCommitContributor>>
+  std::map<ModelType, std::unique_ptr<DirectoryCommitContributor>>
       directory_commit_contributors_;
-  std::vector<std::unique_ptr<DirectoryUpdateHandler>>
+  std::map<ModelType, std::unique_ptr<DirectoryUpdateHandler>>
       directory_update_handlers_;
 
   std::vector<std::unique_ptr<ModelTypeWorker>> model_type_workers_;
@@ -149,9 +153,6 @@
   // The NudgeHandler.  Not owned.
   NudgeHandler* nudge_handler_;
 
-  // The set of enabled directory types.
-  ModelTypeSet enabled_directory_types_;
-
   // Function to call to migrate data from the directory to USS.
   UssMigrator uss_migrator_;
 
diff --git a/components/sync/engine_impl/model_type_registry_unittest.cc b/components/sync/engine_impl/model_type_registry_unittest.cc
index 39d6548e..0b72864 100644
--- a/components/sync/engine_impl/model_type_registry_unittest.cc
+++ b/components/sync/engine_impl/model_type_registry_unittest.cc
@@ -9,6 +9,7 @@
 #include "base/deferred_sequenced_task_runner.h"
 #include "base/memory/ptr_util.h"
 #include "base/message_loop/message_loop.h"
+#include "base/test/gtest_util.h"
 #include "components/sync/engine/activation_context.h"
 #include "components/sync/engine/fake_model_type_processor.h"
 #include "components/sync/protocol/model_type_state.pb.h"
@@ -24,11 +25,29 @@
 
 class ModelTypeRegistryTest : public ::testing::Test {
  public:
-  ModelTypeRegistryTest();
-  void SetUp() override;
-  void TearDown() override;
+  void SetUp() override {
+    test_user_share_.SetUp();
+    scoped_refptr<ModelSafeWorker> passive_worker(
+        new FakeModelWorker(GROUP_PASSIVE));
+    scoped_refptr<ModelSafeWorker> ui_worker(new FakeModelWorker(GROUP_UI));
+    scoped_refptr<ModelSafeWorker> db_worker(new FakeModelWorker(GROUP_DB));
+    workers_.push_back(passive_worker);
+    workers_.push_back(ui_worker);
+    workers_.push_back(db_worker);
 
-  ModelTypeRegistry* registry();
+    registry_ = base::MakeUnique<ModelTypeRegistry>(
+        workers_, test_user_share_.user_share(), &mock_nudge_handler_,
+        base::Bind(&ModelTypeRegistryTest::MigrateDirectory,
+                   base::Unretained(this)));
+  }
+
+  void TearDown() override {
+    registry_.reset();
+    workers_.clear();
+    test_user_share_.TearDown();
+  }
+
+  ModelTypeRegistry* registry() { return registry_.get(); }
 
   static sync_pb::ModelTypeState MakeInitialModelTypeState(ModelType type) {
     sync_pb::ModelTypeState state;
@@ -66,7 +85,9 @@
     return true;
   }
 
-  syncable::Directory* directory();
+  syncable::Directory* directory() {
+    return test_user_share_.user_share()->directory.get();
+  }
 
   base::MessageLoop message_loop_;
 
@@ -77,127 +98,51 @@
   bool migration_attempted_ = false;
 };
 
-ModelTypeRegistryTest::ModelTypeRegistryTest() {}
-
-void ModelTypeRegistryTest::SetUp() {
-  test_user_share_.SetUp();
-  scoped_refptr<ModelSafeWorker> passive_worker(
-      new FakeModelWorker(GROUP_PASSIVE));
-  scoped_refptr<ModelSafeWorker> ui_worker(new FakeModelWorker(GROUP_UI));
-  scoped_refptr<ModelSafeWorker> db_worker(new FakeModelWorker(GROUP_DB));
-  workers_.push_back(passive_worker);
-  workers_.push_back(ui_worker);
-  workers_.push_back(db_worker);
-
-  registry_ = base::MakeUnique<ModelTypeRegistry>(
-      workers_, test_user_share_.user_share(), &mock_nudge_handler_,
-      base::Bind(&ModelTypeRegistryTest::MigrateDirectory,
-                 base::Unretained(this)));
-}
-
-void ModelTypeRegistryTest::TearDown() {
-  registry_.reset();
-  workers_.clear();
-  test_user_share_.TearDown();
-}
-
-ModelTypeRegistry* ModelTypeRegistryTest::registry() {
-  return registry_.get();
-}
-
-syncable::Directory* ModelTypeRegistryTest::directory() {
-  return test_user_share_.user_share()->directory.get();
-}
-
-// Create some directory update handlers and commit contributors.
-//
-// We don't get to inspect any of the state we're modifying.  This test is
-// useful only for detecting crashes or memory leaks.
-TEST_F(ModelTypeRegistryTest, SetEnabledDirectoryTypes_Once) {
-  ModelSafeRoutingInfo routing_info;
-  routing_info.insert(std::make_pair(NIGORI, GROUP_PASSIVE));
-  routing_info.insert(std::make_pair(BOOKMARKS, GROUP_UI));
-  routing_info.insert(std::make_pair(AUTOFILL, GROUP_DB));
-  routing_info.insert(std::make_pair(APPS, GROUP_NON_BLOCKING));
-
-  registry()->SetEnabledDirectoryTypes(routing_info);
-
+// Tests operations with directory types.
+// Registering/unregistering type should affect enabled types and handlers map.
+// Registering/unregistering type twice should trigger DCHECK.
+// Registering type with unknown ModelSafeGroup should trigger DCHECK.
+TEST_F(ModelTypeRegistryTest, DirectoryTypes) {
   UpdateHandlerMap* update_handler_map = registry()->update_handler_map();
-  // Apps is non-blocking type, SetEnabledDirectoryTypes shouldn't instantiate
-  // update_handler for it.
-  EXPECT_TRUE(update_handler_map->find(APPS) == update_handler_map->end());
-}
+  EXPECT_TRUE(registry()->GetEnabledTypes().Empty());
 
-// Try two different routing info settings.
-//
-// We don't get to inspect any of the state we're modifying.  This test is
-// useful only for detecting crashes or memory leaks.
-TEST_F(ModelTypeRegistryTest, SetEnabledDirectoryTypes_Repeatedly) {
-  ModelSafeRoutingInfo routing_info1;
-  routing_info1.insert(std::make_pair(NIGORI, GROUP_PASSIVE));
-  routing_info1.insert(std::make_pair(BOOKMARKS, GROUP_PASSIVE));
-  routing_info1.insert(std::make_pair(AUTOFILL, GROUP_PASSIVE));
-  routing_info1.insert(std::make_pair(APPS, GROUP_NON_BLOCKING));
+  registry()->RegisterDirectoryType(AUTOFILL, GROUP_DB);
+  EXPECT_EQ(ModelTypeSet(AUTOFILL), registry()->GetEnabledTypes());
 
-  registry()->SetEnabledDirectoryTypes(routing_info1);
+  registry()->RegisterDirectoryType(BOOKMARKS, GROUP_UI);
+  EXPECT_EQ(ModelTypeSet(AUTOFILL, BOOKMARKS), registry()->GetEnabledTypes());
 
-  ModelSafeRoutingInfo routing_info2;
-  routing_info2.insert(std::make_pair(NIGORI, GROUP_PASSIVE));
-  routing_info2.insert(std::make_pair(BOOKMARKS, GROUP_UI));
-  routing_info2.insert(std::make_pair(AUTOFILL, GROUP_DB));
-  routing_info2.insert(std::make_pair(APPS, GROUP_NON_BLOCKING));
+  // Try registering already registered type.
+  EXPECT_DCHECK_DEATH(registry()->RegisterDirectoryType(BOOKMARKS, GROUP_UI));
 
-  registry()->SetEnabledDirectoryTypes(routing_info2);
-}
+  EXPECT_TRUE(update_handler_map->find(AUTOFILL) != update_handler_map->end());
+  EXPECT_TRUE(update_handler_map->find(BOOKMARKS) != update_handler_map->end());
 
-// Test removing all types from the list.
-//
-// We don't get to inspect any of the state we're modifying.  This test is
-// useful only for detecting crashes or memory leaks.
-TEST_F(ModelTypeRegistryTest, SetEnabledDirectoryTypes_Clear) {
-  ModelSafeRoutingInfo routing_info1;
-  routing_info1.insert(std::make_pair(NIGORI, GROUP_PASSIVE));
-  routing_info1.insert(std::make_pair(BOOKMARKS, GROUP_UI));
-  routing_info1.insert(std::make_pair(AUTOFILL, GROUP_DB));
-  routing_info1.insert(std::make_pair(APPS, GROUP_NON_BLOCKING));
+  registry()->UnregisterDirectoryType(AUTOFILL);
+  EXPECT_EQ(ModelTypeSet(BOOKMARKS), registry()->GetEnabledTypes());
+  EXPECT_TRUE(update_handler_map->find(AUTOFILL) == update_handler_map->end());
+  EXPECT_TRUE(update_handler_map->find(BOOKMARKS) != update_handler_map->end());
 
-  registry()->SetEnabledDirectoryTypes(routing_info1);
+  // Try unregistering already unregistered type.
+  EXPECT_DCHECK_DEATH(registry()->UnregisterDirectoryType(AUTOFILL));
 
-  ModelSafeRoutingInfo routing_info2;
-  registry()->SetEnabledDirectoryTypes(routing_info2);
-}
-
-// Test disabling then re-enabling some directory types.
-//
-// We don't get to inspect any of the state we're modifying.  This test is
-// useful only for detecting crashes or memory leaks.
-TEST_F(ModelTypeRegistryTest, SetEnabledDirectoryTypes_OffAndOn) {
-  ModelSafeRoutingInfo routing_info1;
-  routing_info1.insert(std::make_pair(NIGORI, GROUP_PASSIVE));
-  routing_info1.insert(std::make_pair(BOOKMARKS, GROUP_UI));
-  routing_info1.insert(std::make_pair(AUTOFILL, GROUP_DB));
-  routing_info1.insert(std::make_pair(APPS, GROUP_NON_BLOCKING));
-
-  registry()->SetEnabledDirectoryTypes(routing_info1);
-
-  ModelSafeRoutingInfo routing_info2;
-  registry()->SetEnabledDirectoryTypes(routing_info2);
-
-  registry()->SetEnabledDirectoryTypes(routing_info1);
+  // Try registering type with unknown worker.
+  EXPECT_DCHECK_DEATH(
+      registry()->RegisterDirectoryType(SESSIONS, GROUP_HISTORY));
 }
 
 TEST_F(ModelTypeRegistryTest, NonBlockingTypes) {
   EXPECT_TRUE(registry()->GetEnabledTypes().Empty());
 
-  registry()->ConnectType(
+  registry()->ConnectNonBlockingType(
       THEMES, MakeActivationContext(MakeInitialModelTypeState(THEMES)));
   EXPECT_EQ(ModelTypeSet(THEMES), registry()->GetEnabledTypes());
 
-  registry()->ConnectType(
+  registry()->ConnectNonBlockingType(
       SESSIONS, MakeActivationContext(MakeInitialModelTypeState(SESSIONS)));
   EXPECT_EQ(ModelTypeSet(THEMES, SESSIONS), registry()->GetEnabledTypes());
 
-  registry()->DisconnectType(THEMES);
+  registry()->DisconnectNonBlockingType(THEMES);
   EXPECT_EQ(ModelTypeSet(SESSIONS), registry()->GetEnabledTypes());
 
   // Allow ModelTypeRegistry destruction to delete the
@@ -205,73 +150,70 @@
 }
 
 TEST_F(ModelTypeRegistryTest, NonBlockingTypesWithDirectoryTypes) {
-  ModelSafeRoutingInfo routing_info1;
-  routing_info1.insert(std::make_pair(NIGORI, GROUP_PASSIVE));
-  routing_info1.insert(std::make_pair(BOOKMARKS, GROUP_UI));
-  routing_info1.insert(std::make_pair(AUTOFILL, GROUP_DB));
-  routing_info1.insert(std::make_pair(THEMES, GROUP_NON_BLOCKING));
-  routing_info1.insert(std::make_pair(SESSIONS, GROUP_NON_BLOCKING));
-
   ModelTypeSet directory_types(NIGORI, BOOKMARKS, AUTOFILL);
 
   ModelTypeSet current_types;
   EXPECT_TRUE(registry()->GetEnabledTypes().Empty());
 
   // Add the themes non-blocking type.
-  registry()->ConnectType(
+  registry()->ConnectNonBlockingType(
       THEMES, MakeActivationContext(MakeInitialModelTypeState(THEMES)));
   current_types.Put(THEMES);
   EXPECT_EQ(current_types, registry()->GetEnabledTypes());
 
   // Add some directory types.
-  registry()->SetEnabledDirectoryTypes(routing_info1);
+  for (auto it = directory_types.First(); it.Good(); it.Inc())
+    registry()->RegisterDirectoryType(it.Get(), GROUP_PASSIVE);
   current_types.PutAll(directory_types);
   EXPECT_EQ(current_types, registry()->GetEnabledTypes());
 
   // Add sessions non-blocking type.
-  registry()->ConnectType(
+  registry()->ConnectNonBlockingType(
       SESSIONS, MakeActivationContext(MakeInitialModelTypeState(SESSIONS)));
   current_types.Put(SESSIONS);
   EXPECT_EQ(current_types, registry()->GetEnabledTypes());
 
   // Remove themes non-blocking type.
-  registry()->DisconnectType(THEMES);
+  registry()->DisconnectNonBlockingType(THEMES);
   current_types.Remove(THEMES);
   EXPECT_EQ(current_types, registry()->GetEnabledTypes());
 
   // Clear all directory types.
-  ModelSafeRoutingInfo routing_info2;
-  registry()->SetEnabledDirectoryTypes(routing_info2);
+  for (auto it = directory_types.First(); it.Good(); it.Inc())
+    registry()->UnregisterDirectoryType(it.Get());
   current_types.RemoveAll(directory_types);
   EXPECT_EQ(current_types, registry()->GetEnabledTypes());
 }
 
 // Tests correct result returned from GetInitialSyncEndedTypes.
 TEST_F(ModelTypeRegistryTest, GetInitialSyncEndedTypes) {
-  ModelSafeRoutingInfo routing_info;
-  // Add two directory and two non-blocking types.
-  routing_info.insert(std::make_pair(AUTOFILL, GROUP_PASSIVE));
-  routing_info.insert(std::make_pair(BOOKMARKS, GROUP_PASSIVE));
-  routing_info.insert(std::make_pair(THEMES, GROUP_NON_BLOCKING));
-  routing_info.insert(std::make_pair(SESSIONS, GROUP_NON_BLOCKING));
-  registry()->SetEnabledDirectoryTypes(routing_info);
+  // Add two directory types.
+  registry()->RegisterDirectoryType(AUTOFILL, GROUP_PASSIVE);
+  registry()->RegisterDirectoryType(BOOKMARKS, GROUP_PASSIVE);
 
   // Only Autofill and Themes types finished initial sync.
   MarkInitialSyncEndedForDirectoryType(AUTOFILL);
 
+  // Add two non-blocking type.
   sync_pb::ModelTypeState model_type_state = MakeInitialModelTypeState(THEMES);
   model_type_state.set_initial_sync_done(true);
-  registry()->ConnectType(THEMES, MakeActivationContext(model_type_state));
+  registry()->ConnectNonBlockingType(THEMES,
+                                     MakeActivationContext(model_type_state));
+
+  registry()->ConnectNonBlockingType(
+      SESSIONS, MakeActivationContext(MakeInitialModelTypeState(SESSIONS)));
 
   EXPECT_EQ(ModelTypeSet(AUTOFILL, THEMES),
             registry()->GetInitialSyncEndedTypes());
 }
 
+// Tests that when directory data is present for type ConnectNonBlockingType
+// triggers USS migration.
 TEST_F(ModelTypeRegistryTest, UssMigrationAttempted) {
   EXPECT_FALSE(migration_attempted());
 
   MarkInitialSyncEndedForDirectoryType(THEMES);
-  registry()->ConnectType(
+  registry()->ConnectNonBlockingType(
       THEMES, MakeActivationContext(MakeInitialModelTypeState(THEMES)));
 
   EXPECT_TRUE(migration_attempted());
diff --git a/components/sync/engine_impl/sync_manager_impl.cc b/components/sync/engine_impl/sync_manager_impl.cc
index e52090e..b4f52a50 100644
--- a/components/sync/engine_impl/sync_manager_impl.cc
+++ b/components/sync/engine_impl/sync_manager_impl.cc
@@ -182,7 +182,6 @@
 void SyncManagerImpl::ConfigureSyncer(
     ConfigureReason reason,
     ModelTypeSet to_download,
-    const ModelSafeRoutingInfo& new_routing_info,
     const base::Closure& ready_task,
     const base::Closure& retry_task) {
   DCHECK(thread_checker_.CalledOnValidThread());
@@ -195,12 +194,9 @@
 
   DVLOG(1) << "Configuring -"
            << "\n\t"
-           << "current types: "
-           << ModelTypeSetToString(GetRoutingInfoTypes(new_routing_info))
-           << "\n\t"
            << "types to download: " << ModelTypeSetToString(to_download);
   ConfigurationParams params(GetSourceFromReason(reason), to_download,
-                             new_routing_info, ready_task, retry_task);
+                             ready_task, retry_task);
 
   scheduler_->Start(SyncScheduler::CONFIGURATION_MODE, base::Time());
   scheduler_->ScheduleConfiguration(params);
@@ -396,18 +392,17 @@
     const SyncEncryptionHandler::NigoriState& nigori_state) {}
 
 void SyncManagerImpl::StartSyncingNormally(
-    const ModelSafeRoutingInfo& routing_info,
     base::Time last_poll_time) {
   // Start the sync scheduler.
-  // TODO(sync): We always want the newest set of routes when we switch back
-  // to normal mode. Figure out how to enforce set_routing_info is always
-  // appropriately set and that it's only modified when switching to normal
-  // mode.
   DCHECK(thread_checker_.CalledOnValidThread());
-  cycle_context_->SetRoutingInfo(routing_info);
   scheduler_->Start(SyncScheduler::NORMAL_MODE, last_poll_time);
 }
 
+void SyncManagerImpl::StartConfiguration() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  scheduler_->Start(SyncScheduler::CONFIGURATION_MODE, base::Time());
+}
+
 syncable::Directory* SyncManagerImpl::directory() {
   return share_.directory.get();
 }
@@ -906,6 +901,11 @@
   return &share_;
 }
 
+ModelTypeConnector* SyncManagerImpl::GetModelTypeConnector() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  return model_type_registry_.get();
+}
+
 std::unique_ptr<ModelTypeConnector>
 SyncManagerImpl::GetModelTypeConnectorProxy() {
   DCHECK(initialized_);
diff --git a/components/sync/engine_impl/sync_manager_impl.h b/components/sync/engine_impl/sync_manager_impl.h
index 4b396e9..6dbc42a 100644
--- a/components/sync/engine_impl/sync_manager_impl.h
+++ b/components/sync/engine_impl/sync_manager_impl.h
@@ -72,11 +72,10 @@
                           ModelTypeSet to_journal,
                           ModelTypeSet to_unapply) override;
   void UpdateCredentials(const SyncCredentials& credentials) override;
-  void StartSyncingNormally(const ModelSafeRoutingInfo& routing_info,
-                            base::Time last_poll_time) override;
+  void StartSyncingNormally(base::Time last_poll_time) override;
+  void StartConfiguration() override;
   void ConfigureSyncer(ConfigureReason reason,
                        ModelTypeSet to_download,
-                       const ModelSafeRoutingInfo& new_routing_info,
                        const base::Closure& ready_task,
                        const base::Closure& retry_task) override;
   void SetInvalidatorEnabled(bool invalidator_enabled) override;
@@ -89,6 +88,7 @@
   void SaveChanges() override;
   void ShutdownOnSyncThread(ShutdownReason reason) override;
   UserShare* GetUserShare() override;
+  ModelTypeConnector* GetModelTypeConnector() override;
   std::unique_ptr<ModelTypeConnector> GetModelTypeConnectorProxy() override;
   const std::string cache_guid() override;
   bool ReceivedExperiment(Experiments* experiments) override;
diff --git a/components/sync/engine_impl/sync_manager_impl_unittest.cc b/components/sync/engine_impl/sync_manager_impl_unittest.cc
index afaab93..8bf15f9 100644
--- a/components/sync/engine_impl/sync_manager_impl_unittest.cc
+++ b/components/sync/engine_impl/sync_manager_impl_unittest.cc
@@ -1017,8 +1017,6 @@
     EXPECT_FALSE(js_backend_.IsInitialized());
 
     std::vector<scoped_refptr<ModelSafeWorker>> workers;
-    ModelSafeRoutingInfo routing_info;
-    GetModelSafeRoutingInfo(&routing_info);
 
     // This works only because all routing info types are GROUP_PASSIVE.
     // If we had types in other groups, we would need additional workers
@@ -1052,10 +1050,10 @@
     EXPECT_EQ(EngineComponentsFactory::STORAGE_ON_DISK, storage_used_);
 
     if (initialization_succeeded_) {
-      for (ModelSafeRoutingInfo::iterator i = routing_info.begin();
-           i != routing_info.end(); ++i) {
-        type_roots_[i->first] =
-            MakeTypeRoot(sync_manager_.GetUserShare(), i->first);
+      ModelTypeSet enabled_types = GetEnabledTypes();
+      for (auto it = enabled_types.First(); it.Good(); it.Inc()) {
+        type_roots_[it.Get()] =
+            MakeTypeRoot(sync_manager_.GetUserShare(), it.Get());
       }
     }
 
@@ -1071,23 +1069,20 @@
     PumpLoop();
   }
 
-  void GetModelSafeRoutingInfo(ModelSafeRoutingInfo* out) {
-    (*out)[NIGORI] = GROUP_PASSIVE;
-    (*out)[DEVICE_INFO] = GROUP_PASSIVE;
-    (*out)[EXPERIMENTS] = GROUP_PASSIVE;
-    (*out)[BOOKMARKS] = GROUP_PASSIVE;
-    (*out)[THEMES] = GROUP_PASSIVE;
-    (*out)[SESSIONS] = GROUP_PASSIVE;
-    (*out)[PASSWORDS] = GROUP_PASSIVE;
-    (*out)[PREFERENCES] = GROUP_PASSIVE;
-    (*out)[PRIORITY_PREFERENCES] = GROUP_PASSIVE;
-    (*out)[ARTICLES] = GROUP_PASSIVE;
-  }
-
   ModelTypeSet GetEnabledTypes() {
-    ModelSafeRoutingInfo routing_info;
-    GetModelSafeRoutingInfo(&routing_info);
-    return GetRoutingInfoTypes(routing_info);
+    ModelTypeSet enabled_types;
+    enabled_types.Put(NIGORI);
+    enabled_types.Put(DEVICE_INFO);
+    enabled_types.Put(EXPERIMENTS);
+    enabled_types.Put(BOOKMARKS);
+    enabled_types.Put(THEMES);
+    enabled_types.Put(SESSIONS);
+    enabled_types.Put(PASSWORDS);
+    enabled_types.Put(PREFERENCES);
+    enabled_types.Put(PRIORITY_PREFERENCES);
+    enabled_types.Put(ARTICLES);
+
+    return enabled_types;
   }
 
   void OnChangesApplied(ModelType model_type,
@@ -2663,18 +2658,15 @@
 // Verify transaction version of a model type is incremented when node of
 // that type is updated.
 TEST_F(SyncManagerTest, IncrementTransactionVersion) {
-  ModelSafeRoutingInfo routing_info;
-  GetModelSafeRoutingInfo(&routing_info);
-
   {
     ReadTransaction read_trans(FROM_HERE, sync_manager_.GetUserShare());
-    for (ModelSafeRoutingInfo::iterator i = routing_info.begin();
-         i != routing_info.end(); ++i) {
+    ModelTypeSet enabled_types = GetEnabledTypes();
+    for (auto it = enabled_types.First(); it.Good(); it.Inc()) {
       // Transaction version is incremented when SyncManagerTest::SetUp()
       // creates a node of each type.
       EXPECT_EQ(1,
                 sync_manager_.GetUserShare()->directory->GetTransactionVersion(
-                    i->first));
+                    it.Get()));
     }
   }
 
@@ -2688,11 +2680,11 @@
 
   {
     ReadTransaction read_trans(FROM_HERE, sync_manager_.GetUserShare());
-    for (ModelSafeRoutingInfo::iterator i = routing_info.begin();
-         i != routing_info.end(); ++i) {
-      EXPECT_EQ(i->first == BOOKMARKS ? 2 : 1,
+    ModelTypeSet enabled_types = GetEnabledTypes();
+    for (auto it = enabled_types.First(); it.Good(); it.Inc()) {
+      EXPECT_EQ(it.Get() == BOOKMARKS ? 2 : 1,
                 sync_manager_.GetUserShare()->directory->GetTransactionVersion(
-                    i->first));
+                    it.Get()));
     }
   }
 }
@@ -2783,21 +2775,34 @@
 };
 
 // Test that the configuration params are properly created and sent to
-// ScheduleConfigure. No callback should be invoked. Any disabled datatypes
-// should be purged.
+// ScheduleConfigure. No callback should be invoked.
 TEST_F(SyncManagerTestWithMockScheduler, BasicConfiguration) {
   ConfigureReason reason = CONFIGURE_REASON_RECONFIGURATION;
   ModelTypeSet types_to_download(BOOKMARKS, PREFERENCES);
-  ModelSafeRoutingInfo new_routing_info;
-  GetModelSafeRoutingInfo(&new_routing_info);
-  ModelTypeSet enabled_types = GetRoutingInfoTypes(new_routing_info);
-  ModelTypeSet disabled_types = Difference(ModelTypeSet::All(), enabled_types);
 
   ConfigurationParams params;
   EXPECT_CALL(*scheduler(), Start(SyncScheduler::CONFIGURATION_MODE, _));
   EXPECT_CALL(*scheduler(), ScheduleConfiguration(_))
       .WillOnce(SaveArg<0>(&params));
 
+  CallbackCounter ready_task_counter, retry_task_counter;
+  sync_manager_.ConfigureSyncer(
+      reason, types_to_download,
+      base::Bind(&CallbackCounter::Callback,
+                 base::Unretained(&ready_task_counter)),
+      base::Bind(&CallbackCounter::Callback,
+                 base::Unretained(&retry_task_counter)));
+  EXPECT_EQ(0, ready_task_counter.times_called());
+  EXPECT_EQ(0, retry_task_counter.times_called());
+  EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::RECONFIGURATION, params.source);
+  EXPECT_EQ(types_to_download, params.types_to_download);
+}
+
+// Test that PurgeDisabledTypes only purges recently disabled types leaving
+// others intact.
+TEST_F(SyncManagerTestWithMockScheduler, PurgeDisabledTypes) {
+  ModelTypeSet enabled_types = GetEnabledTypes();
+  ModelTypeSet disabled_types = Difference(ModelTypeSet::All(), enabled_types);
   // Set data for all types.
   ModelTypeSet protocol_types = ProtocolTypes();
   for (ModelTypeSet::Iterator iter = protocol_types.First(); iter.Good();
@@ -2807,19 +2812,6 @@
 
   sync_manager_.PurgeDisabledTypes(disabled_types, ModelTypeSet(),
                                    ModelTypeSet());
-  CallbackCounter ready_task_counter, retry_task_counter;
-  sync_manager_.ConfigureSyncer(
-      reason, types_to_download, new_routing_info,
-      base::Bind(&CallbackCounter::Callback,
-                 base::Unretained(&ready_task_counter)),
-      base::Bind(&CallbackCounter::Callback,
-                 base::Unretained(&retry_task_counter)));
-  EXPECT_EQ(0, ready_task_counter.times_called());
-  EXPECT_EQ(0, retry_task_counter.times_called());
-  EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::RECONFIGURATION, params.source);
-  EXPECT_EQ(types_to_download, params.types_to_download);
-  EXPECT_EQ(new_routing_info, params.routing_info);
-
   // Verify all the disabled types were purged.
   EXPECT_EQ(enabled_types,
             sync_manager_.GetUserShare()->directory->InitialSyncEndedTypes());
@@ -2827,60 +2819,6 @@
                                 ModelTypeSet::All()));
 }
 
-// Test that on a reconfiguration (configuration where the session context
-// already has routing info), only those recently disabled types are purged.
-TEST_F(SyncManagerTestWithMockScheduler, ReConfiguration) {
-  ConfigureReason reason = CONFIGURE_REASON_RECONFIGURATION;
-  ModelTypeSet types_to_download(BOOKMARKS, PREFERENCES);
-  ModelTypeSet disabled_types = ModelTypeSet(THEMES, SESSIONS);
-  ModelSafeRoutingInfo old_routing_info;
-  ModelSafeRoutingInfo new_routing_info;
-  GetModelSafeRoutingInfo(&old_routing_info);
-  new_routing_info = old_routing_info;
-  new_routing_info.erase(THEMES);
-  new_routing_info.erase(SESSIONS);
-  ModelTypeSet enabled_types = GetRoutingInfoTypes(new_routing_info);
-
-  ConfigurationParams params;
-  EXPECT_CALL(*scheduler(), Start(SyncScheduler::CONFIGURATION_MODE, _));
-  EXPECT_CALL(*scheduler(), ScheduleConfiguration(_))
-      .WillOnce(SaveArg<0>(&params));
-
-  // Set data for all types except those recently disabled (so we can verify
-  // only those recently disabled are purged) .
-  ModelTypeSet protocol_types = ProtocolTypes();
-  for (ModelTypeSet::Iterator iter = protocol_types.First(); iter.Good();
-       iter.Inc()) {
-    if (!disabled_types.Has(iter.Get())) {
-      SetProgressMarkerForType(iter.Get(), true);
-    } else {
-      SetProgressMarkerForType(iter.Get(), false);
-    }
-  }
-
-  // Set the context to have the old routing info.
-  cycle_context()->SetRoutingInfo(old_routing_info);
-
-  CallbackCounter ready_task_counter, retry_task_counter;
-  sync_manager_.PurgeDisabledTypes(ModelTypeSet(), ModelTypeSet(),
-                                   ModelTypeSet());
-  sync_manager_.ConfigureSyncer(
-      reason, types_to_download, new_routing_info,
-      base::Bind(&CallbackCounter::Callback,
-                 base::Unretained(&ready_task_counter)),
-      base::Bind(&CallbackCounter::Callback,
-                 base::Unretained(&retry_task_counter)));
-  EXPECT_EQ(0, ready_task_counter.times_called());
-  EXPECT_EQ(0, retry_task_counter.times_called());
-  EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::RECONFIGURATION, params.source);
-  EXPECT_EQ(types_to_download, params.types_to_download);
-  EXPECT_EQ(new_routing_info, params.routing_info);
-
-  // Verify only the recently disabled types were purged.
-  EXPECT_EQ(disabled_types, sync_manager_.GetTypesWithEmptyProgressMarkerToken(
-                                ProtocolTypes()));
-}
-
 // Test that SyncManager::ClearServerData invokes the scheduler.
 TEST_F(SyncManagerTestWithMockScheduler, ClearServerData) {
   EXPECT_CALL(*scheduler(), Start(SyncScheduler::CLEAR_SERVER_DATA_MODE, _));
@@ -2894,9 +2832,7 @@
 // Test that PurgePartiallySyncedTypes purges only those types that have not
 // fully completed their initial download and apply.
 TEST_F(SyncManagerTest, PurgePartiallySyncedTypes) {
-  ModelSafeRoutingInfo routing_info;
-  GetModelSafeRoutingInfo(&routing_info);
-  ModelTypeSet enabled_types = GetRoutingInfoTypes(routing_info);
+  ModelTypeSet enabled_types = GetEnabledTypes();
 
   UserShare* share = sync_manager_.GetUserShare();
 
@@ -2971,9 +2907,7 @@
 // Test CleanupDisabledTypes properly purges all disabled types as specified
 // by the previous and current enabled params.
 TEST_F(SyncManagerTest, PurgeDisabledTypes) {
-  ModelSafeRoutingInfo routing_info;
-  GetModelSafeRoutingInfo(&routing_info);
-  ModelTypeSet enabled_types = GetRoutingInfoTypes(routing_info);
+  ModelTypeSet enabled_types = GetEnabledTypes();
   ModelTypeSet disabled_types = Difference(ModelTypeSet::All(), enabled_types);
 
   // The harness should have initialized the enabled_types for us.
@@ -3014,10 +2948,8 @@
 // Test PurgeDisabledTypes properly unapplies types by deleting their local data
 // and preserving their server data and progress marker.
 TEST_F(SyncManagerTest, PurgeUnappliedTypes) {
-  ModelSafeRoutingInfo routing_info;
-  GetModelSafeRoutingInfo(&routing_info);
   ModelTypeSet unapplied_types = ModelTypeSet(BOOKMARKS, PREFERENCES);
-  ModelTypeSet enabled_types = GetRoutingInfoTypes(routing_info);
+  ModelTypeSet enabled_types = GetEnabledTypes();
   ModelTypeSet disabled_types = Difference(ModelTypeSet::All(), enabled_types);
 
   // The harness should have initialized the enabled_types for us.
diff --git a/components/sync/engine_impl/sync_scheduler.h b/components/sync/engine_impl/sync_scheduler.h
index c1c18b2..160dc1c1 100644
--- a/components/sync/engine_impl/sync_scheduler.h
+++ b/components/sync/engine_impl/sync_scheduler.h
@@ -26,7 +26,6 @@
   ConfigurationParams(
       const sync_pb::GetUpdatesCallerInfo::GetUpdatesSource& source,
       ModelTypeSet types_to_download,
-      const ModelSafeRoutingInfo& routing_info,
       const base::Closure& ready_task,
       const base::Closure& retry_task);
   ConfigurationParams(const ConfigurationParams& other);
@@ -36,8 +35,6 @@
   sync_pb::GetUpdatesCallerInfo::GetUpdatesSource source;
   // The types that should be downloaded.
   ModelTypeSet types_to_download;
-  // The new routing info (superset of types to be downloaded).
-  ModelSafeRoutingInfo routing_info;
   // Callback to invoke on configuration completion.
   base::Closure ready_task;
   // Callback to invoke on configuration failure.
diff --git a/components/sync/engine_impl/sync_scheduler_impl.cc b/components/sync/engine_impl/sync_scheduler_impl.cc
index 69559b51..09a873c 100644
--- a/components/sync/engine_impl/sync_scheduler_impl.cc
+++ b/components/sync/engine_impl/sync_scheduler_impl.cc
@@ -100,12 +100,10 @@
 ConfigurationParams::ConfigurationParams(
     const sync_pb::GetUpdatesCallerInfo::GetUpdatesSource& source,
     ModelTypeSet types_to_download,
-    const ModelSafeRoutingInfo& routing_info,
     const base::Closure& ready_task,
     const base::Closure& retry_task)
     : source(source),
       types_to_download(types_to_download),
-      routing_info(routing_info),
       ready_task(ready_task),
       retry_task(retry_task) {
   DCHECK(!ready_task.is_null());
@@ -270,25 +268,6 @@
     observer.OnSyncCycleEvent(event);
 }
 
-namespace {
-
-// Helper to extract the routing info corresponding to types in
-// |types_to_download| from |current_routes|.
-void BuildModelSafeParams(ModelTypeSet types_to_download,
-                          const ModelSafeRoutingInfo& current_routes,
-                          ModelSafeRoutingInfo* result_routes) {
-  for (ModelTypeSet::Iterator iter = types_to_download.First(); iter.Good();
-       iter.Inc()) {
-    ModelType type = iter.Get();
-    ModelSafeRoutingInfo::const_iterator route = current_routes.find(type);
-    DCHECK(route != current_routes.end());
-    ModelSafeGroup group = route->second;
-    (*result_routes)[type] = group;
-  }
-}
-
-}  // namespace.
-
 void SyncSchedulerImpl::ScheduleConfiguration(
     const ConfigurationParams& params) {
   DCHECK(CalledOnValidThread());
@@ -302,11 +281,6 @@
   // for a pending configure job.
   DCHECK(!pending_configure_params_);
 
-  ModelSafeRoutingInfo restricted_routes;
-  BuildModelSafeParams(params.types_to_download, params.routing_info,
-                       &restricted_routes);
-  cycle_context_->SetRoutingInfo(restricted_routes);
-
   // Only reconfigure if we have types to download.
   if (!params.types_to_download.Empty()) {
     pending_configure_params_ = base::MakeUnique<ConfigurationParams>(params);
diff --git a/components/sync/engine_impl/sync_scheduler_impl_unittest.cc b/components/sync/engine_impl/sync_scheduler_impl_unittest.cc
index d4d6734..93d8a00 100644
--- a/components/sync/engine_impl/sync_scheduler_impl_unittest.cc
+++ b/components/sync/engine_impl/sync_scheduler_impl_unittest.cc
@@ -89,14 +89,6 @@
   RunLoop();
 }
 
-ModelSafeRoutingInfo TypesToRoutingInfo(ModelTypeSet types) {
-  ModelSafeRoutingInfo routes;
-  for (ModelTypeSet::Iterator iter = types.First(); iter.Good(); iter.Inc()) {
-    routes[iter.Get()] = GROUP_PASSIVE;
-  }
-  return routes;
-}
-
 static const size_t kMinNumSamples = 5;
 
 // Test harness for the SyncScheduler.  Test the delays and backoff timers used
@@ -129,11 +121,6 @@
     delay_ = nullptr;
     extensions_activity_ = new ExtensionsActivity();
 
-    routing_info_[THEMES] = GROUP_UI;
-    routing_info_[TYPED_URLS] = GROUP_DB;
-    routing_info_[THEMES] = GROUP_UI;
-    routing_info_[NIGORI] = GROUP_PASSIVE;
-
     workers_.clear();
     workers_.push_back(make_scoped_refptr(new FakeModelWorker(GROUP_UI)));
     workers_.push_back(make_scoped_refptr(new FakeModelWorker(GROUP_DB)));
@@ -146,6 +133,9 @@
     model_type_registry_ = base::MakeUnique<ModelTypeRegistry>(
         workers_, test_user_share_.user_share(), &mock_nudge_handler_,
         UssMigrator());
+    model_type_registry_->RegisterDirectoryType(NIGORI, GROUP_PASSIVE);
+    model_type_registry_->RegisterDirectoryType(THEMES, GROUP_UI);
+    model_type_registry_->RegisterDirectoryType(TYPED_URLS, GROUP_DB);
 
     context_ = base::MakeUnique<SyncCycleContext>(
         connection_.get(), directory(), extensions_activity_.get(),
@@ -154,7 +144,6 @@
         true,   // enable keystore encryption
         false,  // force enable pre-commit GU avoidance
         "fake_invalidator_client_id");
-    context_->SetRoutingInfo(routing_info_);
     context_->set_notifications_enabled(true);
     context_->set_account_name("Test");
     scheduler_ = base::MakeUnique<SyncSchedulerImpl>(
@@ -164,7 +153,6 @@
   }
 
   SyncSchedulerImpl* scheduler() { return scheduler_.get(); }
-  const ModelSafeRoutingInfo& routing_info() { return routing_info_; }
   MockSyncer* syncer() { return syncer_; }
   MockDelayProvider* delay() { return delay_; }
   MockConnectionManager* connection() { return connection_.get(); }
@@ -309,7 +297,6 @@
   MockDelayProvider* delay_;
   std::vector<scoped_refptr<ModelSafeWorker>> workers_;
   scoped_refptr<ExtensionsActivity> extensions_activity_;
-  ModelSafeRoutingInfo routing_info_;
   base::WeakPtrFactory<SyncSchedulerImplTest> weak_ptr_factory_;
 };
 
@@ -393,7 +380,6 @@
   CallbackCounter retry_counter;
   ConfigurationParams params(
       GetUpdatesCallerInfo::RECONFIGURATION, model_types,
-      TypesToRoutingInfo(model_types),
       base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
       base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
   scheduler()->ScheduleConfiguration(params);
@@ -422,7 +408,6 @@
   CallbackCounter retry_counter;
   ConfigurationParams params(
       GetUpdatesCallerInfo::RECONFIGURATION, model_types,
-      TypesToRoutingInfo(model_types),
       base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
       base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
   scheduler()->ScheduleConfiguration(params);
@@ -468,7 +453,6 @@
   CallbackCounter retry_counter;
   ConfigurationParams params(
       GetUpdatesCallerInfo::RECONFIGURATION, model_types,
-      TypesToRoutingInfo(model_types),
       base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
       base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
   scheduler()->ScheduleConfiguration(params);
@@ -490,7 +474,6 @@
   CallbackCounter retry_counter;
   ConfigurationParams params(
       GetUpdatesCallerInfo::RECONFIGURATION, model_types,
-      TypesToRoutingInfo(model_types),
       base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
       base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
   scheduler()->ScheduleConfiguration(params);
@@ -518,7 +501,6 @@
   CallbackCounter retry_counter;
   ConfigurationParams params(
       GetUpdatesCallerInfo::RECONFIGURATION, model_types,
-      TypesToRoutingInfo(model_types),
       base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
       base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
   scheduler()->ScheduleConfiguration(params);
@@ -546,7 +528,6 @@
   CallbackCounter retry_counter;
   ConfigurationParams params(
       GetUpdatesCallerInfo::RECONFIGURATION, model_types,
-      TypesToRoutingInfo(model_types),
       base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
       base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
   scheduler()->ScheduleConfiguration(params);
@@ -807,7 +788,7 @@
   CallbackCounter ready_counter;
   CallbackCounter retry_counter;
   ConfigurationParams params(
-      GetUpdatesCallerInfo::RECONFIGURATION, types, TypesToRoutingInfo(types),
+      GetUpdatesCallerInfo::RECONFIGURATION, types,
       base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
       base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
   scheduler()->ScheduleConfiguration(params);
@@ -891,7 +872,7 @@
   CallbackCounter ready_counter;
   CallbackCounter retry_counter;
   ConfigurationParams params(
-      GetUpdatesCallerInfo::RECONFIGURATION, types, TypesToRoutingInfo(types),
+      GetUpdatesCallerInfo::RECONFIGURATION, types,
       base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
       base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
   scheduler()->ScheduleConfiguration(params);
@@ -1212,7 +1193,6 @@
   CallbackCounter retry_counter;
   ConfigurationParams params(
       GetUpdatesCallerInfo::RECONFIGURATION, config_types,
-      TypesToRoutingInfo(config_types),
       base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
       base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
   scheduler()->ScheduleConfiguration(params);
@@ -1229,9 +1209,6 @@
       .WillOnce(DoAll(Invoke(test_util::SimulateNormalSuccess),
                       RecordSyncShare(&times2, true)));
 
-  // TODO(tim): Figure out how to remove this dangerous need to reset
-  // routing info between mode switches.
-  context()->SetRoutingInfo(routing_info());
   StartSyncScheduler(base::Time());
 
   RunLoop();
@@ -1307,7 +1284,7 @@
   CallbackCounter ready_counter;
   CallbackCounter retry_counter;
   ConfigurationParams params(
-      GetUpdatesCallerInfo::RECONFIGURATION, types, TypesToRoutingInfo(types),
+      GetUpdatesCallerInfo::RECONFIGURATION, types,
       base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
       base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
   scheduler()->ScheduleConfiguration(params);
@@ -1356,7 +1333,7 @@
   CallbackCounter ready_counter;
   CallbackCounter retry_counter;
   ConfigurationParams params(
-      GetUpdatesCallerInfo::RECONFIGURATION, types, TypesToRoutingInfo(types),
+      GetUpdatesCallerInfo::RECONFIGURATION, types,
       base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
       base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
   scheduler()->ScheduleConfiguration(params);
@@ -1589,7 +1566,6 @@
   CallbackCounter retry_counter;
   ConfigurationParams params(
       GetUpdatesCallerInfo::RECONFIGURATION, model_types,
-      TypesToRoutingInfo(model_types),
       base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
       base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
   scheduler()->ScheduleConfiguration(params);
diff --git a/components/sync/engine_impl/syncer_unittest.cc b/components/sync/engine_impl/syncer_unittest.cc
index c07f91a..a66b784 100644
--- a/components/sync/engine_impl/syncer_unittest.cc
+++ b/components/sync/engine_impl/syncer_unittest.cc
@@ -219,15 +219,6 @@
   void OnProtocolEvent(const ProtocolEvent& event) override {}
   void OnSyncProtocolError(const SyncProtocolError& error) override {}
 
-  void GetModelSafeRoutingInfo(ModelSafeRoutingInfo* out) {
-    // We're just testing the sync engine here, so we shunt everything to
-    // the SyncerThread.  Datatypes which aren't enabled aren't in the map.
-    for (ModelTypeSet::Iterator it = enabled_datatypes_.First(); it.Good();
-         it.Inc()) {
-      (*out)[it.Get()] = GROUP_PASSIVE;
-    }
-  }
-
   void OnSyncCycleEvent(const SyncCycleEvent& event) override {
     DVLOG(1) << "HandleSyncEngineEvent in unittest " << event.what_happened;
     // we only test for entry-specific events, not status changed ones.
@@ -271,32 +262,28 @@
     mock_server_ = base::MakeUnique<MockConnectionManager>(
         directory(), &cancelation_signal_);
     debug_info_getter_ = base::MakeUnique<MockDebugInfoGetter>();
-    EnableDatatype(BOOKMARKS);
-    EnableDatatype(EXTENSIONS);
-    EnableDatatype(NIGORI);
-    EnableDatatype(PREFERENCES);
-    EnableDatatype(NIGORI);
     workers_.push_back(
         scoped_refptr<ModelSafeWorker>(new FakeModelWorker(GROUP_PASSIVE)));
     std::vector<SyncEngineEventListener*> listeners;
     listeners.push_back(this);
 
-    ModelSafeRoutingInfo routing_info;
-    GetModelSafeRoutingInfo(&routing_info);
-
     model_type_registry_ = base::MakeUnique<ModelTypeRegistry>(
         workers_, test_user_share_.user_share(), &mock_nudge_handler_,
         UssMigrator());
     model_type_registry_->RegisterDirectoryTypeDebugInfoObserver(
         &debug_info_cache_);
 
+    EnableDatatype(BOOKMARKS);
+    EnableDatatype(EXTENSIONS);
+    EnableDatatype(NIGORI);
+    EnableDatatype(PREFERENCES);
+
     context_ = base::MakeUnique<SyncCycleContext>(
         mock_server_.get(), directory(), extensions_activity_.get(), listeners,
         debug_info_getter_.get(), model_type_registry_.get(),
         true,   // enable keystore encryption
         false,  // force enable pre-commit GU avoidance experiment
         "fake_invalidator_client_id");
-    context_->SetRoutingInfo(routing_info);
     syncer_ = new Syncer(&cancelation_signal_);
     scheduler_ = base::MakeUnique<SyncSchedulerImpl>(
         "TestSyncScheduler", BackoffDelayProvider::FromDefaults(),
@@ -510,27 +497,13 @@
 
   void EnableDatatype(ModelType model_type) {
     enabled_datatypes_.Put(model_type);
-
-    ModelSafeRoutingInfo routing_info;
-    GetModelSafeRoutingInfo(&routing_info);
-
-    if (context_) {
-      context_->SetRoutingInfo(routing_info);
-    }
-
+    model_type_registry_->RegisterDirectoryType(model_type, GROUP_PASSIVE);
     mock_server_->ExpectGetUpdatesRequestTypes(enabled_datatypes_);
   }
 
   void DisableDatatype(ModelType model_type) {
     enabled_datatypes_.Remove(model_type);
-
-    ModelSafeRoutingInfo routing_info;
-    GetModelSafeRoutingInfo(&routing_info);
-
-    if (context_) {
-      context_->SetRoutingInfo(routing_info);
-    }
-
+    model_type_registry_->UnregisterDirectoryType(model_type);
     mock_server_->ExpectGetUpdatesRequestTypes(enabled_datatypes_);
   }
 
@@ -4896,7 +4869,6 @@
   // The expectations of this test happen in the MockConnectionManager's
   // GetUpdates handler.  EnableDatatype sets the expectation value from our
   // set of enabled/disabled datatypes.
-  EnableDatatype(BOOKMARKS);
   EXPECT_TRUE(SyncShareNudge());
   EXPECT_EQ(1, mock_server_->GetAndClearNumGetUpdatesRequests());
 
@@ -4904,10 +4876,6 @@
   EXPECT_TRUE(SyncShareNudge());
   EXPECT_EQ(1, mock_server_->GetAndClearNumGetUpdatesRequests());
 
-  EnableDatatype(PREFERENCES);
-  EXPECT_TRUE(SyncShareNudge());
-  EXPECT_EQ(1, mock_server_->GetAndClearNumGetUpdatesRequests());
-
   DisableDatatype(BOOKMARKS);
   EXPECT_TRUE(SyncShareNudge());
   EXPECT_EQ(1, mock_server_->GetAndClearNumGetUpdatesRequests());
diff --git a/components/sync/model/recording_model_type_change_processor.cc b/components/sync/model/recording_model_type_change_processor.cc
new file mode 100644
index 0000000..13c1850
--- /dev/null
+++ b/components/sync/model/recording_model_type_change_processor.cc
@@ -0,0 +1,43 @@
+// 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 "components/sync/model/recording_model_type_change_processor.h"
+
+#include "components/sync/model/fake_model_type_change_processor.h"
+#include "components/sync/model/metadata_batch.h"
+
+namespace syncer {
+
+RecordingModelTypeChangeProcessor::RecordingModelTypeChangeProcessor() {}
+
+RecordingModelTypeChangeProcessor::~RecordingModelTypeChangeProcessor() {}
+
+void RecordingModelTypeChangeProcessor::Put(
+    const std::string& storage_key,
+    std::unique_ptr<EntityData> entity_data,
+    MetadataChangeList* metadata_changes) {
+  put_multimap_.insert(std::make_pair(storage_key, std::move(entity_data)));
+}
+
+void RecordingModelTypeChangeProcessor::Delete(
+    const std::string& storage_key,
+    MetadataChangeList* metadata_changes) {
+  delete_set_.insert(storage_key);
+}
+
+void RecordingModelTypeChangeProcessor::ModelReadyToSync(
+    std::unique_ptr<MetadataBatch> batch) {
+  std::swap(metadata_, batch);
+}
+
+bool RecordingModelTypeChangeProcessor::IsTrackingMetadata() {
+  return is_tracking_metadata_;
+}
+
+void RecordingModelTypeChangeProcessor::SetIsTrackingMetadata(
+    bool is_tracking) {
+  is_tracking_metadata_ = is_tracking;
+}
+
+}  //  namespace syncer
diff --git a/components/sync/model/recording_model_type_change_processor.h b/components/sync/model/recording_model_type_change_processor.h
new file mode 100644
index 0000000..d0789b4e
--- /dev/null
+++ b/components/sync/model/recording_model_type_change_processor.h
@@ -0,0 +1,48 @@
+// 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 COMPONENTS_SYNC_MODEL_RECORDING_MODEL_TYPE_CHANGE_PROCESSOR_H_
+#define COMPONENTS_SYNC_MODEL_RECORDING_MODEL_TYPE_CHANGE_PROCESSOR_H_
+
+#include "components/sync/model/fake_model_type_change_processor.h"
+
+namespace syncer {
+
+// Augmented FakeModelTypeChangeProcessor that accumulates all instructions in
+// members that can then be accessed for verification.
+class RecordingModelTypeChangeProcessor : public FakeModelTypeChangeProcessor {
+ public:
+  RecordingModelTypeChangeProcessor();
+  ~RecordingModelTypeChangeProcessor() override;
+
+  // FakeModelTypeChangeProcessor overrides.
+  void Put(const std::string& storage_key,
+           std::unique_ptr<EntityData> entity_data,
+           MetadataChangeList* metadata_changes) override;
+  void Delete(const std::string& storage_key,
+              MetadataChangeList* metadata_changes) override;
+  void ModelReadyToSync(std::unique_ptr<MetadataBatch> batch) override;
+  bool IsTrackingMetadata() override;
+
+  void SetIsTrackingMetadata(bool is_tracking);
+
+  const std::multimap<std::string, std::unique_ptr<EntityData>>& put_multimap()
+      const {
+    return put_multimap_;
+  }
+
+  const std::set<std::string>& delete_set() const { return delete_set_; }
+
+  const MetadataBatch* metadata() const { return metadata_.get(); }
+
+ private:
+  std::multimap<std::string, std::unique_ptr<EntityData>> put_multimap_;
+  std::set<std::string> delete_set_;
+  std::unique_ptr<MetadataBatch> metadata_;
+  bool is_tracking_metadata_ = true;
+};
+
+}  //  namespace syncer
+
+#endif  // COMPONENTS_SYNC_MODEL_RECORDING_MODEL_TYPE_CHANGE_PROCESSOR_H_
diff --git a/components/sync/tools/sync_client.cc b/components/sync/tools/sync_client.cc
index 69954bca..2056aea1 100644
--- a/components/sync/tools/sync_client.cc
+++ b/components/sync/tools/sync_client.cc
@@ -378,10 +378,6 @@
   model_types.Put(FAVICON_IMAGES);
   model_types.Put(FAVICON_TRACKING);
 
-  ModelSafeRoutingInfo routing_info;
-  for (ModelTypeSet::Iterator it = model_types.First(); it.Good(); it.Inc()) {
-    routing_info[it.Get()] = GROUP_PASSIVE;
-  }
   scoped_refptr<PassiveModelWorker> passive_model_safe_worker =
       new PassiveModelWorker();
   std::vector<scoped_refptr<ModelSafeWorker>> workers;
@@ -442,7 +438,13 @@
   invalidator->RegisterHandler(shim.get());
   CHECK(invalidator->UpdateRegisteredIds(
       shim.get(), ModelTypeSetToObjectIdSet(model_types)));
-  sync_manager->StartSyncingNormally(routing_info, base::Time());
+  ModelTypeConnector* model_type_connector =
+      sync_manager->GetModelTypeConnector();
+  for (ModelTypeSet::Iterator it = model_types.First(); it.Good(); it.Inc()) {
+    model_type_connector->RegisterDirectoryType(it.Get(), GROUP_PASSIVE);
+  }
+
+  sync_manager->StartSyncingNormally(base::Time());
 
   base::RunLoop().Run();
 
diff --git a/content/browser/browser_child_process_host_impl.cc b/content/browser/browser_child_process_host_impl.cc
index a013741..6da88a2 100644
--- a/content/browser/browser_child_process_host_impl.cc
+++ b/content/browser/browser_child_process_host_impl.cc
@@ -551,6 +551,9 @@
   const base::Process& process = child_process_->GetProcess();
   DCHECK(process.IsValid());
 
+  if (child_connection_)
+    child_connection_->SetProcessHandle(process.Handle());
+
 #if defined(OS_WIN)
   // Start a WaitableEventWatcher that will invoke OnProcessExitedEarly if the
   // child process exits. This watcher is stopped once the IPC channel is
diff --git a/content/browser/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc
index 266d689..0a77951 100644
--- a/content/browser/gpu/gpu_process_host.cc
+++ b/content/browser/gpu/gpu_process_host.cc
@@ -1154,27 +1154,35 @@
   }
 }
 
-std::string GpuProcessHost::GetShaderPrefixKey() {
-  if (shader_prefix_key_.empty()) {
+std::string GpuProcessHost::GetShaderPrefixKey(const std::string& shader) {
+  if (shader_prefix_key_info_.empty()) {
     gpu::GPUInfo info = GpuDataManagerImpl::GetInstance()->GetGPUInfo();
 
-    std::string in_str = GetContentClient()->GetProduct() + "-" +
+    shader_prefix_key_info_ =
+        GetContentClient()->GetProduct() + "-" +
 #if defined(OS_ANDROID)
         base::android::BuildInfo::GetInstance()->android_build_fp() + "-" +
 #endif
-        info.gl_vendor + "-" + info.gl_renderer + "-" +
-        info.driver_version + "-" + info.driver_vendor;
-
-    base::Base64Encode(base::SHA1HashString(in_str), &shader_prefix_key_);
+        info.gl_vendor + "-" + info.gl_renderer + "-" + info.driver_version +
+        "-" + info.driver_vendor;
   }
 
-  return shader_prefix_key_;
+  // The shader prefix key is a SHA1 hash of a set of per-machine info, such as
+  // driver version and os version, as well as the shader data being cached.
+  // This ensures both that the shader was not corrupted on disk, as well as
+  // that the shader is correctly configured for the current hardware.
+  std::string prefix;
+  base::Base64Encode(base::SHA1HashString(shader_prefix_key_info_ + shader),
+                     &prefix);
+  return prefix;
 }
 
 void GpuProcessHost::LoadedShader(const std::string& key,
                                   const std::string& data) {
-  std::string prefix = GetShaderPrefixKey();
-  if (!key.compare(0, prefix.length(), prefix))
+  std::string prefix = GetShaderPrefixKey(data);
+  bool prefix_ok = !key.compare(0, prefix.length(), prefix);
+  UMA_HISTOGRAM_BOOLEAN("GPU.ShaderLoadPrefixOK", prefix_ok);
+  if (prefix_ok)
     Send(new GpuMsg_LoadedShader(data));
 }
 
@@ -1205,7 +1213,7 @@
   // If the cache doesn't exist then this is an off the record profile.
   if (iter == client_id_to_shader_cache_.end())
     return;
-  iter->second->Cache(GetShaderPrefixKey() + ":" + key, shader);
+  iter->second->Cache(GetShaderPrefixKey(shader) + ":" + key, shader);
 }
 
 }  // namespace content
diff --git a/content/browser/gpu/gpu_process_host.h b/content/browser/gpu/gpu_process_host.h
index 7fe8079..dd9702b 100644
--- a/content/browser/gpu/gpu_process_host.h
+++ b/content/browser/gpu/gpu_process_host.h
@@ -219,7 +219,7 @@
   // Update GPU crash counters.  Disable GPU if crash limit is reached.
   void RecordProcessCrash();
 
-  std::string GetShaderPrefixKey();
+  std::string GetShaderPrefixKey(const std::string& shader);
 
   // The serial number of the GpuProcessHost / GpuProcessHostUIShim pair.
   int host_id_;
@@ -287,7 +287,7 @@
       ClientIdToShaderCacheMap;
   ClientIdToShaderCacheMap client_id_to_shader_cache_;
 
-  std::string shader_prefix_key_;
+  std::string shader_prefix_key_info_;
 
   ui::mojom::GpuMainAssociatedPtr gpu_main_ptr_;
 
diff --git a/content/common/service_manager/child_connection.cc b/content/common/service_manager/child_connection.cc
index b5f0bfe..58cca53 100644
--- a/content/common/service_manager/child_connection.cc
+++ b/content/common/service_manager/child_connection.cc
@@ -126,14 +126,15 @@
     const std::string& child_token,
     service_manager::Connector* connector,
     scoped_refptr<base::SequencedTaskRunner> io_task_runner)
-    : context_(new IOThreadContext),
+    : child_token_(child_token),
+      context_(new IOThreadContext),
       child_identity_(service_name,
                       service_manager::mojom::kInheritUserID,
                       instance_id),
       service_token_(mojo::edk::GenerateRandomToken()),
       weak_factory_(this) {
   mojo::ScopedMessagePipeHandle service_pipe =
-      mojo::edk::CreateParentMessagePipe(service_token_, child_token);
+      mojo::edk::CreateParentMessagePipe(service_token_, child_token_);
 
   context_->Initialize(child_identity_, connector, std::move(service_pipe),
                        io_task_runner);
@@ -145,9 +146,18 @@
 
 ChildConnection::~ChildConnection() {
   context_->ShutDown();
+
+  if (process_handle_ == base::kNullProcessHandle) {
+    // The process handle was never set, so we have to assume the process was
+    // not successfully launched. Note that ChildProcessLauncher may also call
+    // call ChildProcessLaunchFailed for the same token, so this is (harmlessly)
+    // redundant in some cases.
+    mojo::edk::ChildProcessLaunchFailed(child_token_);
+  }
 }
 
 void ChildConnection::SetProcessHandle(base::ProcessHandle handle) {
+  process_handle_ = handle;
   context_->SetProcessHandle(handle);
 }
 
diff --git a/content/common/service_manager/child_connection.h b/content/common/service_manager/child_connection.h
index b461ddf9..1e34ac0 100644
--- a/content/common/service_manager/child_connection.h
+++ b/content/common/service_manager/child_connection.h
@@ -61,9 +61,11 @@
  private:
   class IOThreadContext;
 
+  const std::string child_token_;
   scoped_refptr<IOThreadContext> context_;
   service_manager::Identity child_identity_;
   const std::string service_token_;
+  base::ProcessHandle process_handle_ = base::kNullProcessHandle;
 
   service_manager::InterfaceProvider remote_interfaces_;
 
diff --git a/docs/android_build_instructions.md b/docs/android_build_instructions.md
index 6acb3fa3..2e2cf1bf 100644
--- a/docs/android_build_instructions.md
+++ b/docs/android_build_instructions.md
@@ -7,7 +7,6 @@
 
 Are you a Google employee? See
 [go/building-chrome](https://goto.google.com/building-chrome) instead.
-Google employee? See [go/building-chrome](https://goto.google.com/building-chrome) instead.
 
 [TOC]
 
diff --git a/docs/android_studio.md b/docs/android_studio.md
index ee3a6025..2a10aa7a 100644
--- a/docs/android_studio.md
+++ b/docs/android_studio.md
@@ -4,21 +4,23 @@
 
 ## Usage
 
+Make sure you have followed [android build instructions](android_build_instructions.md) already.
+
 ```shell
-build/android/gradle/generate_gradle.py --output-directory out-gn/Debug
+build/android/gradle/generate_gradle.py
 ```
 
-This creates a project at `out-gn/Debug/gradle`. To create elsewhere:
+This creates a project at `out/Debug/gradle`. To create elsewhere:
 
 ```shell
-build/android/gradle/generate_gradle.py --output-directory out-gn/Debug --project-dir my-project
+build/android/gradle/generate_gradle.py --output-directory out/My-Out-Dir --project-dir my-project
 ```
 
 By default, only common targets are generated. To customize the list of targets
 to generate projects for:
 
 ```shell
-build/android/gradle/generate_gradle.py --output-directory out-gn/Debug --target //some:target_apk --target //some/other:target_apk
+build/android/gradle/generate_gradle.py --target //some:target_apk --target //some/other:target_apk
 ```
 
 For first-time Android Studio users:
@@ -107,18 +109,18 @@
 * Use a [gradle daemon](https://docs.gradle.org/2.14.1/userguide/gradle_daemon.html) to speed up builds:
     * Add the line `org.gradle.daemon=true` to `~/.gradle/gradle.properties`, creating it if necessary.
 
-## Status (as of Sept 21, 2016)
+## Status (as of Jan 19, 2017)
 
 ### What works
 
 * Tested with Android Studio v2.2.
-* Basic Java editing and compiling works.
+* Java editing and gradle compile works.
+* Instrumentation tests included as androidTest.
+* Symlinks to existing .so files in jniLibs (doesn't generate them).
 
 ### What doesn't work (yet) ([crbug](https://bugs.chromium.org/p/chromium/issues/detail?id=620034))
 
-* Better support for instrumentation tests (they are treated as non-test .apks right now)
 * Make gradle aware of resources and assets
-* Make gradle aware of native code via pointing it at the location of our .so
 * Add a mode in which gradle is responsible for generating `R.java`
 * Add support for native code editing
 * Make the "Make Project" button work correctly
diff --git a/infra/config/cq.cfg b/infra/config/cq.cfg
index 43a62ad..ef921d5 100644
--- a/infra/config/cq.cfg
+++ b/infra/config/cq.cfg
@@ -58,7 +58,7 @@
       builders { name: "linux_chromium_rel_ng" }
       builders {
         name: "linux_chromium_tsan_rel_ng"
-        experiment_percentage: 10
+        experiment_percentage: 50
       }
     }
     buckets {
diff --git a/media/blink/video_frame_compositor.cc b/media/blink/video_frame_compositor.cc
index 017bedc9..ec20342 100644
--- a/media/blink/video_frame_compositor.cc
+++ b/media/blink/video_frame_compositor.cc
@@ -5,8 +5,8 @@
 #include "media/blink/video_frame_compositor.h"
 
 #include "base/bind.h"
+#include "base/callback_helpers.h"
 #include "base/message_loop/message_loop.h"
-#include "base/metrics/histogram_macros.h"
 #include "base/time/default_tick_clock.h"
 #include "base/trace_event/auto_open_close_event.h"
 #include "base/trace_event/trace_event.h"
@@ -139,6 +139,7 @@
   compositor_task_runner_->PostTask(
       FROM_HERE, base::Bind(&VideoFrameCompositor::OnRendererStateUpdate,
                             base::Unretained(this), false));
+  new_processed_frame_cb_.Reset();
 }
 
 void VideoFrameCompositor::PaintSingleFrame(
@@ -189,9 +190,10 @@
   return current_frame_->timestamp();
 }
 
-void VideoFrameCompositor::SetForegroundTime(base::TimeTicks when) {
+void VideoFrameCompositor::SetOnNewProcessedFrameCallback(
+    const OnNewProcessedFrameCB& cb) {
   DCHECK(compositor_task_runner_->BelongsToCurrentThread());
-  foreground_time_ = when;
+  new_processed_frame_cb_ = cb;
 }
 
 bool VideoFrameCompositor::ProcessNewFrame(
@@ -210,13 +212,8 @@
 
   current_frame_ = frame;
 
-  if (!foreground_time_.is_null()) {
-    base::TimeDelta time_to_first_frame =
-        base::TimeTicks::Now() - foreground_time_;
-    UMA_HISTOGRAM_TIMES("Media.Video.TimeFromForegroundToFirstFrame",
-                        time_to_first_frame);
-    foreground_time_ = base::TimeTicks();
-  }
+  if (!new_processed_frame_cb_.is_null())
+    base::ResetAndReturn(&new_processed_frame_cb_).Run(base::TimeTicks::Now());
 
   return true;
 }
diff --git a/media/blink/video_frame_compositor.h b/media/blink/video_frame_compositor.h
index 03fb4c5..0068933 100644
--- a/media/blink/video_frame_compositor.h
+++ b/media/blink/video_frame_compositor.h
@@ -13,6 +13,7 @@
 #include "base/single_thread_task_runner.h"
 #include "base/synchronization/lock.h"
 #include "base/time/tick_clock.h"
+#include "base/time/time.h"
 #include "base/timer/timer.h"
 #include "cc/layers/video_frame_provider.h"
 #include "media/base/video_renderer_sink.h"
@@ -57,6 +58,9 @@
     : public VideoRendererSink,
       NON_EXPORTED_BASE(public cc::VideoFrameProvider) {
  public:
+  // Used to report back the time when the new frame has been processed.
+  using OnNewProcessedFrameCB = base::Callback<void(base::TimeTicks)>;
+
   // |compositor_task_runner| is the task runner on which this class will live,
   // though it may be constructed on any thread.
   explicit VideoFrameCompositor(
@@ -103,10 +107,10 @@
   // PaintSingleFrame() is not also called while stopped.)
   base::TimeDelta GetCurrentFrameTimestamp() const;
 
-  // Called when the media player is brought to the foreground.
-  // Used to record the time it takes to process the first frame after that.
+  // Sets the callback to be run when the new frame has been processed. The
+  // callback is only run once and then reset.
   // Must be called on the compositor thread.
-  void SetForegroundTime(base::TimeTicks when);
+  void SetOnNewProcessedFrameCallback(const OnNewProcessedFrameCB& cb);
 
   void set_tick_clock_for_testing(std::unique_ptr<base::TickClock> tick_clock) {
     tick_clock_ = std::move(tick_clock);
@@ -162,7 +166,7 @@
   bool new_background_frame_;
   base::TimeDelta last_interval_;
   base::TimeTicks last_background_render_;
-  base::TimeTicks foreground_time_;
+  OnNewProcessedFrameCB new_processed_frame_cb_;
 
   // These values are set on the compositor thread, but also read on the media
   // thread when the VFC is stopped.
diff --git a/media/blink/webmediaplayer_impl.cc b/media/blink/webmediaplayer_impl.cc
index d2a7de2..3b0e829 100644
--- a/media/blink/webmediaplayer_impl.cc
+++ b/media/blink/webmediaplayer_impl.cc
@@ -470,8 +470,7 @@
   // requires that currentTime() == duration() after ending.  We want to ensure
   // |paused_time_| matches currentTime() in this case or a future seek() may
   // incorrectly discard what it thinks is a seek to the existing time.
-  paused_time_ =
-      ended_ ? pipeline_.GetMediaDuration() : pipeline_.GetMediaTime();
+  paused_time_ = ended_ ? GetPipelineMediaDuration() : pipeline_.GetMediaTime();
 
   if (observer_)
     observer_->OnPaused();
@@ -726,7 +725,7 @@
   if (chunk_demuxer_)
     return chunk_demuxer_->GetDuration();
 
-  base::TimeDelta pipeline_duration = pipeline_.GetMediaDuration();
+  base::TimeDelta pipeline_duration = GetPipelineMediaDuration();
   return pipeline_duration == kInfiniteDuration
              ? std::numeric_limits<double>::infinity()
              : pipeline_duration.InSecondsF();
@@ -785,7 +784,7 @@
   Ranges<base::TimeDelta> buffered_time_ranges =
       pipeline_.GetBufferedTimeRanges();
 
-  const base::TimeDelta duration = pipeline_.GetMediaDuration();
+  const base::TimeDelta duration = GetPipelineMediaDuration();
   if (duration != kInfiniteDuration) {
     buffered_data_source_host_.AddBufferedTimeRanges(
         &buffered_time_ranges, duration);
@@ -1409,7 +1408,7 @@
   if (watch_time_reporter_)
     watch_time_reporter_->OnHidden();
 
-  if (ShouldPauseWhenHidden()) {
+  if (ShouldPauseVideoWhenHidden()) {
     if (!paused_when_hidden_) {
       // OnPause() will set |paused_when_hidden_| to false and call
       // UpdatePlayState(), so set the flag to true after and then return.
@@ -1440,10 +1439,20 @@
   if (watch_time_reporter_)
     watch_time_reporter_->OnShown();
 
-  compositor_task_runner_->PostTask(
-      FROM_HERE,
-      base::Bind(&VideoFrameCompositor::SetForegroundTime,
-                 base::Unretained(compositor_), base::TimeTicks::Now()));
+  // Only track the time to the first frame if playing or about to play because
+  // of being shown and only for videos we would optimize background playback
+  // for.
+  if ((!paused_ && IsBackgroundOptimizationCandidate()) ||
+      paused_when_hidden_) {
+    VideoFrameCompositor::OnNewProcessedFrameCB new_processed_frame_cb =
+        BIND_TO_RENDER_LOOP1(
+            &WebMediaPlayerImpl::ReportTimeFromForegroundToFirstFrame,
+            base::TimeTicks::Now());
+    compositor_task_runner_->PostTask(
+        FROM_HERE,
+        base::Bind(&VideoFrameCompositor::SetOnNewProcessedFrameCallback,
+                   base::Unretained(compositor_), new_processed_frame_cb));
+  }
 
   if (paused_when_hidden_) {
     paused_when_hidden_ = false;
@@ -1834,7 +1843,7 @@
     case DelegateState::PLAYING: {
       delegate_->DidPlay(
           delegate_id_, hasVideo(), has_audio,
-          media::DurationToMediaContentType(pipeline_.GetMediaDuration()));
+          media::DurationToMediaContentType(GetPipelineMediaDuration()));
       break;
     }
     case DelegateState::PAUSED:
@@ -2121,30 +2130,46 @@
   client_->activateViewportIntersectionMonitoring(activate);
 }
 
-bool WebMediaPlayerImpl::ShouldPauseWhenHidden() const {
-  DCHECK(IsHidden());
-// Don't pause videos being Cast (Android only) or if the background video
-// optimizations are off (desktop only).
-#if defined(OS_ANDROID)  // WMPI_CAST
-  if (isRemote())
-    return false;
-#else   // defined(OS_ANDROID)
+bool WebMediaPlayerImpl::ShouldPauseVideoWhenHidden() const {
+#if !defined(OS_ANDROID)
+  // On desktop, this behavior is behind the feature flag.
   if (!IsBackgroundVideoTrackOptimizationEnabled())
     return false;
-#endif  // defined(OS_ANDROID)
+#endif
 
-  return hasVideo() && !hasAudio();
+  // Pause video-only players that match the criteria for being optimized.
+  return !hasAudio() && IsBackgroundOptimizationCandidate();
 }
 
 bool WebMediaPlayerImpl::ShouldDisableVideoWhenHidden() const {
-  DCHECK(main_task_runner_->BelongsToCurrentThread());
-  DCHECK(IsHidden());
-
-  if (!IsBackgroundVideoTrackOptimizationEnabled() || !hasVideo() ||
-      !hasAudio() || IsStreaming()) {
+  // This optimization is behind the flag on all platforms.
+  if (!IsBackgroundVideoTrackOptimizationEnabled())
     return false;
-  }
 
+  // Disable video track only for players with audio that match the criteria for
+  // being optimized.
+  return hasAudio() && IsBackgroundOptimizationCandidate();
+}
+
+bool WebMediaPlayerImpl::IsBackgroundOptimizationCandidate() const {
+  DCHECK(main_task_runner_->BelongsToCurrentThread());
+
+// Don't optimize players being Cast (Android only).
+#if defined(OS_ANDROID)  // WMPI_CAST
+  if (isRemote())
+    return false;
+#endif  // defined(OS_ANDROID)
+
+  // Don't optimize audio-only or streaming players.
+  if (!hasVideo() || IsStreaming())
+    return false;
+
+  // Videos shorter than the maximum allowed keyframe distance can be optimized.
+  base::TimeDelta duration = GetPipelineMediaDuration();
+  if (duration < max_keyframe_distance_to_disable_background_video_)
+    return true;
+
+  // Otherwise, only optimize videos with shorter average keyframe distance.
   PipelineStatistics stats = GetPipelineStatistics();
   return stats.video_keyframe_distance_average <
          max_keyframe_distance_to_disable_background_video_;
@@ -2190,4 +2215,30 @@
   return pipeline_statistics_for_test_.value_or(pipeline_.GetStatistics());
 }
 
+void WebMediaPlayerImpl::SetPipelineMediaDurationForTest(
+    base::TimeDelta duration) {
+  pipeline_media_duration_for_test_ = base::make_optional(duration);
+}
+
+base::TimeDelta WebMediaPlayerImpl::GetPipelineMediaDuration() const {
+  DCHECK(main_task_runner_->BelongsToCurrentThread());
+
+  return pipeline_media_duration_for_test_.value_or(
+      pipeline_.GetMediaDuration());
+}
+
+void WebMediaPlayerImpl::ReportTimeFromForegroundToFirstFrame(
+    base::TimeTicks foreground_time,
+    base::TimeTicks new_frame_time) {
+  base::TimeDelta time_to_first_frame = new_frame_time - foreground_time;
+  if (hasAudio()) {
+    UMA_HISTOGRAM_TIMES(
+        "Media.Video.TimeFromForegroundToFirstFrame.DisableTrack",
+        time_to_first_frame);
+  } else {
+    UMA_HISTOGRAM_TIMES("Media.Video.TimeFromForegroundToFirstFrame.Paused",
+                        time_to_first_frame);
+  }
+}
+
 }  // namespace media
diff --git a/media/blink/webmediaplayer_impl.h b/media/blink/webmediaplayer_impl.h
index edaeb353..a4bb832 100644
--- a/media/blink/webmediaplayer_impl.h
+++ b/media/blink/webmediaplayer_impl.h
@@ -300,9 +300,6 @@
   void SetNetworkState(blink::WebMediaPlayer::NetworkState state);
   void SetReadyState(blink::WebMediaPlayer::ReadyState state);
 
-  // Gets the duration value reported by the pipeline.
-  double GetPipelineDuration() const;
-
   // Returns the current video frame from |compositor_|. Blocks until the
   // compositor can return the frame.
   scoped_refptr<VideoFrame> GetCurrentFrameFromCompositor();
@@ -380,14 +377,19 @@
   // is intended for android.
   bool DoesOverlaySupportMetadata() const;
 
-  // Whether the media should be paused when hidden. Uses metadata so has
+  // Whether the video should be paused when hidden. Uses metadata so has
   // meaning only after the pipeline has started, otherwise returns false.
-  bool ShouldPauseWhenHidden() const;
+  bool ShouldPauseVideoWhenHidden() const;
 
   // Whether the video track should be disabled when hidden. Uses metadata so
   // has meaning only after the pipeline has started, otherwise returns false.
   bool ShouldDisableVideoWhenHidden() const;
 
+  // Whether the video is suitable for background playback optimizations (either
+  // pausing it or disabling the video track). Uses metadata so has meaning only
+  // after the pipeline has started, otherwise returns false.
+  bool IsBackgroundOptimizationCandidate() const;
+
   // Disables the video track to save power if possible.
   // Must be called when either of the following happens:
   // - right after the video was hidden,
@@ -404,12 +406,23 @@
   // - right after the pipeline has resumed if the video is not hidden.
   void EnableVideoTrackIfNeeded();
 
-  // Overrides the pipeline statistics returned by GetStatistics() for tests.
+  // Overrides the pipeline statistics returned by GetPiplineStatistics() for
+  // tests.
   void SetPipelineStatisticsForTest(const PipelineStatistics& stats);
 
   // Returns the pipeline statistics or the value overridden by tests.
   PipelineStatistics GetPipelineStatistics() const;
 
+  // Overrides the pipeline media duration returned by
+  // GetPipelineMediaDuration() for tests.
+  void SetPipelineMediaDurationForTest(base::TimeDelta duration);
+
+  // Return the pipeline media duration or the value overridden by tests.
+  base::TimeDelta GetPipelineMediaDuration() const;
+
+  void ReportTimeFromForegroundToFirstFrame(base::TimeTicks foreground_time,
+                                            base::TimeTicks new_frame_time);
+
   blink::WebLocalFrame* frame_;
 
   // The playback state last reported to |delegate_|, to avoid setting duplicate
@@ -650,6 +663,9 @@
   // Pipeline statistics overridden by tests.
   base::Optional<PipelineStatistics> pipeline_statistics_for_test_;
 
+  // Pipeline media duration overridden by tests.
+  base::Optional<base::TimeDelta> pipeline_media_duration_for_test_;
+
   DISALLOW_COPY_AND_ASSIGN(WebMediaPlayerImpl);
 };
 
diff --git a/media/blink/webmediaplayer_impl_unittest.cc b/media/blink/webmediaplayer_impl_unittest.cc
index b0fbb40..b68bba6 100644
--- a/media/blink/webmediaplayer_impl_unittest.cc
+++ b/media/blink/webmediaplayer_impl_unittest.cc
@@ -284,12 +284,24 @@
     return wmpi_->ShouldDisableVideoWhenHidden();
   }
 
+  bool ShouldPauseVideoWhenHidden() const {
+    return wmpi_->ShouldPauseVideoWhenHidden();
+  }
+
+  bool IsBackgroundOptimizationCandidate() const {
+    return wmpi_->IsBackgroundOptimizationCandidate();
+  }
+
   void SetVideoKeyframeDistanceAverage(base::TimeDelta value) {
     PipelineStatistics statistics;
     statistics.video_keyframe_distance_average = value;
     wmpi_->SetPipelineStatisticsForTest(statistics);
   }
 
+  void SetDuration(base::TimeDelta value) {
+    wmpi_->SetPipelineMediaDurationForTest(value);
+  }
+
   // "Renderer" thread.
   base::MessageLoop message_loop_;
 
@@ -668,36 +680,88 @@
   ASSERT_EQ(blink::WebSize(1080, 1920), wmpi_->naturalSize());
 }
 
-TEST_F(WebMediaPlayerImplTest, ShouldDisableVideoWhenHidden) {
+TEST_F(WebMediaPlayerImplTest, BackgroundOptimizationsFeatureEnabled) {
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitAndEnableFeature(kBackgroundVideoTrackOptimization);
-
   InitializeWebMediaPlayerImpl();
-  delegate_.SetFrameHiddenForTesting(true);
-
-  SetMetadata(true, true);
   SetVideoKeyframeDistanceAverage(base::TimeDelta::FromSeconds(5));
+  SetDuration(base::TimeDelta::FromSeconds(300));
+
+  // Audible video.
+  SetMetadata(true, true);
+  EXPECT_TRUE(IsBackgroundOptimizationCandidate());
+  EXPECT_TRUE(ShouldDisableVideoWhenHidden());
+  EXPECT_FALSE(ShouldPauseVideoWhenHidden());
+
+  // Video only.
+  SetMetadata(false, true);
+  EXPECT_TRUE(IsBackgroundOptimizationCandidate());
+  EXPECT_TRUE(ShouldPauseVideoWhenHidden());
+  EXPECT_FALSE(ShouldDisableVideoWhenHidden());
+
+  // Audio only.
+  SetMetadata(true, false);
+  EXPECT_FALSE(IsBackgroundOptimizationCandidate());
+  EXPECT_FALSE(ShouldPauseVideoWhenHidden());
+  EXPECT_FALSE(ShouldDisableVideoWhenHidden());
+
+  // Duration is shorter than max video keyframe distance.
+  SetDuration(base::TimeDelta::FromSeconds(5));
+  SetMetadata(true, true);
+  EXPECT_TRUE(IsBackgroundOptimizationCandidate());
+  EXPECT_FALSE(ShouldPauseVideoWhenHidden());
   EXPECT_TRUE(ShouldDisableVideoWhenHidden());
 
-  SetMetadata(false, true);
-  EXPECT_FALSE(ShouldDisableVideoWhenHidden());
-
-  SetMetadata(true, false);
-  EXPECT_FALSE(ShouldDisableVideoWhenHidden());
-
+  // Average keyframe distance is too big.
   SetVideoKeyframeDistanceAverage(base::TimeDelta::FromSeconds(100));
-  SetMetadata(true, true);
+  SetDuration(base::TimeDelta::FromSeconds(300));
+  EXPECT_FALSE(IsBackgroundOptimizationCandidate());
+  EXPECT_FALSE(ShouldPauseVideoWhenHidden());
   EXPECT_FALSE(ShouldDisableVideoWhenHidden());
 }
 
-TEST_F(WebMediaPlayerImplTest, ShouldDisableVideoWhenHiddenFeatureDisabled) {
+TEST_F(WebMediaPlayerImplTest, BackgroundOptimizationsFeatureDisabled) {
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitAndDisableFeature(kBackgroundVideoTrackOptimization);
 
   InitializeWebMediaPlayerImpl();
-  delegate_.SetFrameHiddenForTesting(true);
+  SetVideoKeyframeDistanceAverage(base::TimeDelta::FromSeconds(5));
+  SetDuration(base::TimeDelta::FromSeconds(300));
 
+  // Audible video.
   SetMetadata(true, true);
+  EXPECT_TRUE(IsBackgroundOptimizationCandidate());
+  EXPECT_FALSE(ShouldDisableVideoWhenHidden());
+  EXPECT_FALSE(ShouldPauseVideoWhenHidden());
+
+  // Video only (pausing is enabled on Android).
+  SetMetadata(false, true);
+  EXPECT_TRUE(IsBackgroundOptimizationCandidate());
+#if defined(OS_ANDROID)
+  EXPECT_TRUE(ShouldPauseVideoWhenHidden());
+#else
+  EXPECT_FALSE(ShouldPauseVideoWhenHidden());
+#endif
+  EXPECT_FALSE(ShouldDisableVideoWhenHidden());
+
+  // Audio only.
+  SetMetadata(true, false);
+  EXPECT_FALSE(IsBackgroundOptimizationCandidate());
+  EXPECT_FALSE(ShouldPauseVideoWhenHidden());
+  EXPECT_FALSE(ShouldDisableVideoWhenHidden());
+
+  // Duration is shorter than max video keyframe distance.
+  SetDuration(base::TimeDelta::FromSeconds(5));
+  SetMetadata(true, true);
+  EXPECT_TRUE(IsBackgroundOptimizationCandidate());
+  EXPECT_FALSE(ShouldPauseVideoWhenHidden());
+  EXPECT_FALSE(ShouldDisableVideoWhenHidden());
+
+  // Average keyframe distance is too big.
+  SetVideoKeyframeDistanceAverage(base::TimeDelta::FromSeconds(100));
+  SetDuration(base::TimeDelta::FromSeconds(300));
+  EXPECT_FALSE(IsBackgroundOptimizationCandidate());
+  EXPECT_FALSE(ShouldPauseVideoWhenHidden());
   EXPECT_FALSE(ShouldDisableVideoWhenHidden());
 }
 
diff --git a/net/net.gypi b/net/net.gypi
index 33ea9be..9509bbe 100644
--- a/net/net.gypi
+++ b/net/net.gypi
@@ -1345,6 +1345,8 @@
       'spdy/hpack/hpack_decoder_interface.h',
       'spdy/hpack/hpack_decoder2.cc',
       'spdy/hpack/hpack_decoder2.h',
+      'spdy/hpack/hpack_decoder3.cc',
+      'spdy/hpack/hpack_decoder3.h',
       'spdy/hpack/hpack_encoder.cc',
       'spdy/hpack/hpack_encoder.h',
       'spdy/hpack/hpack_entry.cc',
@@ -2113,6 +2115,7 @@
       'spdy/header_coalescer_test.cc',
       'spdy/hpack/hpack_decoder_test.cc',
       'spdy/hpack/hpack_decoder2_test.cc',
+      'spdy/hpack/hpack_decoder3_test.cc',
       'spdy/hpack/hpack_encoder_test.cc',
       'spdy/hpack/hpack_entry_test.cc',
       'spdy/hpack/hpack_header_table_test.cc',
diff --git a/net/quic/core/quic_headers_stream_test.cc b/net/quic/core/quic_headers_stream_test.cc
index a3afe00..d4fb9d5c 100644
--- a/net/quic/core/quic_headers_stream_test.cc
+++ b/net/quic/core/quic_headers_stream_test.cc
@@ -40,7 +40,6 @@
 
 // TODO(bnc): Merge these correctly.
 bool FLAGS_use_http2_frame_decoder_adapter;
-bool FLAGS_spdy_use_hpack_decoder2;
 bool FLAGS_spdy_framer_use_new_methods4;
 
 namespace net {
@@ -153,13 +152,15 @@
   return os;
 }
 
-enum HpackDecoderChoice { HPACK_DECODER_SPDY, HPACK_DECODER_NEW };
+enum HpackDecoderChoice { HPACK_DECODER_SPDY, HPACK_DECODER2, HPACK_DECODER3 };
 std::ostream& operator<<(std::ostream& os, HpackDecoderChoice v) {
   switch (v) {
     case HPACK_DECODER_SPDY:
       return os << "SPDY";
-    case HPACK_DECODER_NEW:
-      return os << "NEW";
+    case HPACK_DECODER2:
+      return os << "HPACK_DECODER2";
+    case HPACK_DECODER3:
+      return os << "HPACK_DECODER3";
   }
   return os;
 }
@@ -193,12 +194,16 @@
     }
     switch (hpack_decoder) {
       case HPACK_DECODER_SPDY:
-        FLAGS_spdy_use_hpack_decoder2 = false;
+        FLAGS_chromium_http2_flag_spdy_use_hpack_decoder2 = false;
+        FLAGS_chromium_http2_flag_spdy_use_hpack_decoder3 = false;
         break;
-      case HPACK_DECODER_NEW:
-        FLAGS_spdy_use_hpack_decoder2 = true;
-        // Needs new header methods to be used.
-        FLAGS_spdy_framer_use_new_methods4 = true;
+      case HPACK_DECODER2:
+        FLAGS_chromium_http2_flag_spdy_use_hpack_decoder2 = true;
+        FLAGS_chromium_http2_flag_spdy_use_hpack_decoder3 = false;
+        break;
+      case HPACK_DECODER3:
+        FLAGS_chromium_http2_flag_spdy_use_hpack_decoder2 = false;
+        FLAGS_chromium_http2_flag_spdy_use_hpack_decoder3 = true;
         break;
     }
     QUIC_LOG(INFO) << "TestParams: version: " << QuicVersionToString(version)
@@ -415,7 +420,7 @@
         ::testing::Values(HTTP2_DECODER_SPDY,
                           HTTP2_DECODER_NESTED_SPDY,
                           HTTP2_DECODER_NEW),
-        ::testing::Values(HPACK_DECODER_SPDY, HPACK_DECODER_NEW)));
+        ::testing::Values(HPACK_DECODER_SPDY, HPACK_DECODER2, HPACK_DECODER3)));
 
 TEST_P(QuicHeadersStreamTest, StreamId) {
   EXPECT_EQ(3u, headers_stream_->id());
@@ -849,6 +854,10 @@
 }
 
 TEST_P(QuicHeadersStreamTest, HpackDecoderDebugVisitor) {
+  if (test_params_.hpack_decoder == HPACK_DECODER3) {
+    return;
+  }
+
   StrictMock<MockQuicHpackDebugVisitor>* hpack_decoder_visitor =
       hpack_decoder_visitor_.get();
   QuicSpdySessionPeer::SetHpackDecoderDebugVisitor(
diff --git a/net/spdy/hpack/hpack_decoder2_test.cc b/net/spdy/hpack/hpack_decoder2_test.cc
index efea044..8c70051 100644
--- a/net/spdy/hpack/hpack_decoder2_test.cc
+++ b/net/spdy/hpack/hpack_decoder2_test.cc
@@ -565,8 +565,9 @@
   EXPECT_FALSE(DecodeHeaderBlock(first));
 }
 
-// Round-tripping the header set from E.2.1 should work.
-TEST_P(HpackDecoder2Test, BasicE21) {
+// Round-tripping the header set from RFC 7541 C.3.1 should work.
+// http://httpwg.org/specs/rfc7541.html#rfc.section.C.3.1
+TEST_P(HpackDecoder2Test, BasicC31) {
   HpackEncoder encoder(ObtainHpackHuffmanTable());
 
   SpdyHeaderBlock expected_header_set;
@@ -583,7 +584,9 @@
   EXPECT_EQ(expected_header_set, decoded_block());
 }
 
-TEST_P(HpackDecoder2Test, SectionD4RequestHuffmanExamples) {
+// RFC 7541, Section C.4: Request Examples with Huffman Coding
+// http://httpwg.org/specs/rfc7541.html#rfc.section.C.4
+TEST_P(HpackDecoder2Test, SectionC4RequestHuffmanExamples) {
   // TODO(jamessynge): Use net/http2/hpack/tools/hpack_example.h to parse the
   // example directly, instead of having it as a comment.
   // 82                                      | == Indexed - Add ==
@@ -703,7 +706,9 @@
   EXPECT_EQ(164u, decoder_peer_.header_table()->size());
 }
 
-TEST_P(HpackDecoder2Test, SectionD6ResponseHuffmanExamples) {
+// RFC 7541, Section C.6: Response Examples with Huffman Coding
+// http://httpwg.org/specs/rfc7541.html#rfc.section.C.6
+TEST_P(HpackDecoder2Test, SectionC6ResponseHuffmanExamples) {
   decoder_.ApplyHeaderTableSizeSetting(256);
 
   // 48                                      | == Literal indexed ==
diff --git a/net/spdy/hpack/hpack_decoder3.cc b/net/spdy/hpack/hpack_decoder3.cc
new file mode 100644
index 0000000..d2dcbeb
--- /dev/null
+++ b/net/spdy/hpack/hpack_decoder3.cc
@@ -0,0 +1,151 @@
+// 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 "net/spdy/hpack/hpack_decoder3.h"
+
+#include "base/logging.h"
+#include "net/http2/decoder/decode_buffer.h"
+#include "net/http2/decoder/decode_status.h"
+
+using base::StringPiece;
+
+namespace net {
+namespace {
+const size_t kMaxDecodeBufferSizeBytes = 32 * 1024;  // 32 KB
+}  // namespace
+
+HpackDecoder3::HpackDecoder3()
+    : hpack_decoder_(&listener_adapter_, kMaxDecodeBufferSizeBytes),
+      max_decode_buffer_size_bytes_(kMaxDecodeBufferSizeBytes),
+      header_block_started_(false) {}
+
+HpackDecoder3::~HpackDecoder3() {}
+
+void HpackDecoder3::ApplyHeaderTableSizeSetting(size_t size_setting) {
+  DVLOG(2) << "HpackDecoder3::ApplyHeaderTableSizeSetting";
+  hpack_decoder_.ApplyHeaderTableSizeSetting(size_setting);
+}
+
+void HpackDecoder3::HandleControlFrameHeadersStart(
+    SpdyHeadersHandlerInterface* handler) {
+  DVLOG(2) << "HpackDecoder3::HandleControlFrameHeadersStart";
+  DCHECK(!header_block_started_);
+  listener_adapter_.set_handler(handler);
+}
+
+bool HpackDecoder3::HandleControlFrameHeadersData(const char* headers_data,
+                                                  size_t headers_data_length) {
+  DVLOG(2) << "HpackDecoder3::HandleControlFrameHeadersData: len="
+           << headers_data_length;
+  if (!header_block_started_) {
+    // Initialize the decoding process here rather than in
+    // HandleControlFrameHeadersStart because that method is not always called.
+    total_hpack_bytes_ = 0;
+    header_block_started_ = true;
+    if (!hpack_decoder_.StartDecodingBlock()) {
+      header_block_started_ = false;
+      return false;
+    }
+  }
+
+  // Sometimes we get a call with headers_data==nullptr and
+  // headers_data_length==0, in which case we need to avoid creating
+  // a DecodeBuffer, which would otherwise complain.
+  if (headers_data_length > 0) {
+    DCHECK_NE(headers_data, nullptr);
+    if (headers_data_length > max_decode_buffer_size_bytes_) {
+      DVLOG(1) << "max_decode_buffer_size_bytes_ < headers_data_length: "
+               << max_decode_buffer_size_bytes_ << " < " << headers_data_length;
+      return false;
+    }
+    total_hpack_bytes_ += headers_data_length;
+    DecodeBuffer db(headers_data, headers_data_length);
+    bool ok = hpack_decoder_.DecodeFragment(&db);
+    DCHECK(!ok || db.Empty()) << "Remaining=" << db.Remaining();
+    return ok;
+  }
+  return true;
+}
+
+// TODO(jamessynge): Determine if compressed_len is needed; it is used to
+// produce UUMA stat Net.SpdyHpackDecompressionPercentage, but only for
+// SPDY3, not HTTP2.
+bool HpackDecoder3::HandleControlFrameHeadersComplete(size_t* compressed_len) {
+  DVLOG(2) << "HpackDecoder3::HandleControlFrameHeadersComplete";
+  if (compressed_len != nullptr) {
+    *compressed_len = total_hpack_bytes_;
+  }
+  if (!hpack_decoder_.EndDecodingBlock()) {
+    DVLOG(3) << "EndDecodingBlock returned false";
+    return false;
+  }
+  header_block_started_ = false;
+  return true;
+}
+
+const SpdyHeaderBlock& HpackDecoder3::decoded_block() const {
+  return listener_adapter_.decoded_block();
+}
+
+void HpackDecoder3::SetHeaderTableDebugVisitor(
+    std::unique_ptr<HpackHeaderTable::DebugVisitorInterface> visitor) {
+  DVLOG(2) << "HpackDecoder3::SetHeaderTableDebugVisitor";
+  // Dropping on the floor for now. Not sure yet if needed at all.
+}
+
+void HpackDecoder3::set_max_decode_buffer_size_bytes(
+    size_t max_decode_buffer_size_bytes) {
+  DVLOG(2) << "HpackDecoder3::set_max_decode_buffer_size_bytes";
+  max_decode_buffer_size_bytes_ = max_decode_buffer_size_bytes;
+  hpack_decoder_.set_max_string_size_bytes(max_decode_buffer_size_bytes);
+}
+
+HpackDecoder3::ListenerAdapter::ListenerAdapter() : handler_(nullptr) {}
+HpackDecoder3::ListenerAdapter::~ListenerAdapter() {}
+
+void HpackDecoder3::ListenerAdapter::set_handler(
+    SpdyHeadersHandlerInterface* handler) {
+  handler_ = handler;
+}
+
+void HpackDecoder3::ListenerAdapter::OnHeaderListStart() {
+  DVLOG(2) << "HpackDecoder3::ListenerAdapter::OnHeaderListStart";
+  total_uncompressed_bytes_ = 0;
+  decoded_block_.clear();
+  if (handler_ != nullptr) {
+    handler_->OnHeaderBlockStart();
+  }
+}
+
+void HpackDecoder3::ListenerAdapter::OnHeader(HpackEntryType entry_type,
+                                              const HpackString& name,
+                                              const HpackString& value) {
+  DVLOG(2) << "HpackDecoder3::ListenerAdapter::OnHeader:\n name: " << name
+           << "\n value: " << value;
+  total_uncompressed_bytes_ += name.size() + value.size();
+  if (handler_ == nullptr) {
+    DVLOG(3) << "Adding to decoded_block";
+    decoded_block_.AppendValueOrAddHeader(name, value);
+  } else {
+    DVLOG(3) << "Passing to handler";
+    handler_->OnHeader(name, value);
+  }
+}
+
+void HpackDecoder3::ListenerAdapter::OnHeaderListEnd() {
+  DVLOG(2) << "HpackDecoder3::ListenerAdapter::OnHeaderListEnd";
+  // We don't clear the SpdyHeaderBlock here to allow access to it until the
+  // next HPACK block is decoded.
+  if (handler_ != nullptr) {
+    handler_->OnHeaderBlockEnd(total_uncompressed_bytes_);
+    handler_ = nullptr;
+  }
+}
+
+void HpackDecoder3::ListenerAdapter::OnHeaderErrorDetected(
+    StringPiece error_message) {
+  VLOG(1) << error_message;
+}
+
+}  // namespace net
diff --git a/net/spdy/hpack/hpack_decoder3.h b/net/spdy/hpack/hpack_decoder3.h
new file mode 100644
index 0000000..6203dfd
--- /dev/null
+++ b/net/spdy/hpack/hpack_decoder3.h
@@ -0,0 +1,112 @@
+// 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 NET_SPDY_HPACK_HPACK_DECODER3_H_
+#define NET_SPDY_HPACK_HPACK_DECODER3_H_
+
+// HpackDecoder3 implements HpackDecoderInterface, using Http2HpackDecoder to
+// decode HPACK blocks into HTTP/2 header lists as outlined in
+// http://tools.ietf.org/html/rfc7541.
+
+#include <stddef.h>
+
+#include <memory>
+
+#include "base/macros.h"
+#include "base/strings/string_piece.h"
+#include "net/base/net_export.h"
+#include "net/http2/hpack/decoder/hpack_decoder_listener.h"
+#include "net/http2/hpack/decoder/http2_hpack_decoder.h"
+#include "net/http2/hpack/hpack_string.h"
+#include "net/http2/hpack/http2_hpack_constants.h"
+#include "net/spdy/hpack/hpack_decoder_interface.h"
+#include "net/spdy/hpack/hpack_header_table.h"
+#include "net/spdy/spdy_header_block.h"
+#include "net/spdy/spdy_headers_handler_interface.h"
+
+namespace net {
+namespace test {
+class HpackDecoder3Peer;
+}  // namespace test
+
+class NET_EXPORT_PRIVATE HpackDecoder3 : public HpackDecoderInterface {
+ public:
+  friend test::HpackDecoder3Peer;
+  HpackDecoder3();
+  ~HpackDecoder3() override;
+
+  // Override the HpackDecoderInterface methods:
+
+  void ApplyHeaderTableSizeSetting(size_t size_setting) override;
+  void HandleControlFrameHeadersStart(
+      SpdyHeadersHandlerInterface* handler) override;
+  bool HandleControlFrameHeadersData(const char* headers_data,
+                                     size_t headers_data_length) override;
+  bool HandleControlFrameHeadersComplete(size_t* compressed_len) override;
+  const SpdyHeaderBlock& decoded_block() const override;
+  void SetHeaderTableDebugVisitor(
+      std::unique_ptr<HpackHeaderTable::DebugVisitorInterface> visitor)
+      override;
+  void set_max_decode_buffer_size_bytes(
+      size_t max_decode_buffer_size_bytes) override;
+
+ private:
+  class NET_EXPORT_PRIVATE ListenerAdapter : public HpackDecoderListener {
+   public:
+    ListenerAdapter();
+    ~ListenerAdapter() override;
+
+    // If a SpdyHeadersHandlerInterface is provided, the decoder will emit
+    // headers to it rather than accumulating them in a SpdyHeaderBlock.
+    // Does not take ownership of the handler, but does use the pointer until
+    // the current HPACK block is completely decoded.
+    void set_handler(SpdyHeadersHandlerInterface* handler);
+    const SpdyHeaderBlock& decoded_block() const { return decoded_block_; }
+
+    // Override the HpackDecoderListener methods:
+
+    void OnHeaderListStart() override;
+    void OnHeader(HpackEntryType entry_type,
+                  const HpackString& name,
+                  const HpackString& value) override;
+    void OnHeaderListEnd() override;
+    void OnHeaderErrorDetected(base::StringPiece error_message) override;
+
+   private:
+    // If the caller doesn't provide a handler, the header list is stored in
+    // this SpdyHeaderBlock.
+    SpdyHeaderBlock decoded_block_;
+
+    // If non-NULL, handles decoded headers. Not owned.
+    SpdyHeadersHandlerInterface* handler_;
+
+    // Total bytes of the name and value strings in the current HPACK block.
+    size_t total_uncompressed_bytes_;
+  };
+
+  // Converts calls to HpackDecoderListener into calls to
+  // SpdyHeadersHandlerInterface.
+  ListenerAdapter listener_adapter_;
+
+  // The actual decoder.
+  Http2HpackDecoder hpack_decoder_;
+
+  // Total bytes that have been received as input (i.e. HPACK encoded)
+  // in the current HPACK block.
+  size_t total_hpack_bytes_;
+
+  // How much encoded data this decoder is willing to buffer.
+  size_t max_decode_buffer_size_bytes_;
+
+  // Flag to keep track of having seen the header block start. Needed at the
+  // moment because HandleControlFrameHeadersStart won't be called if a handler
+  // is not being provided by the caller.
+  bool header_block_started_;
+
+  DISALLOW_COPY_AND_ASSIGN(HpackDecoder3);
+};
+
+}  // namespace net
+
+#endif  // NET_SPDY_HPACK_HPACK_DECODER3_H_
diff --git a/net/spdy/hpack/hpack_decoder3_test.cc b/net/spdy/hpack/hpack_decoder3_test.cc
new file mode 100644
index 0000000..3f71724
--- /dev/null
+++ b/net/spdy/hpack/hpack_decoder3_test.cc
@@ -0,0 +1,1012 @@
+// 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 "net/spdy/hpack/hpack_decoder3.h"
+
+// Tests of HpackDecoder3.
+
+#include <stdint.h>
+
+#include <string>
+#include <tuple>
+#include <utility>
+#include <vector>
+
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "net/http2/hpack/decoder/hpack_decoder_state.h"
+#include "net/http2/hpack/decoder/hpack_decoder_tables.h"
+#include "net/http2/hpack/tools/hpack_block_builder.h"
+#include "net/http2/tools/http2_random.h"
+#include "net/spdy/hpack/hpack_constants.h"
+#include "net/spdy/hpack/hpack_encoder.h"
+#include "net/spdy/hpack/hpack_huffman_table.h"
+#include "net/spdy/hpack/hpack_output_stream.h"
+#include "net/spdy/spdy_test_utils.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::StringPiece;
+using std::string;
+using ::testing::ElementsAre;
+using ::testing::Pair;
+
+namespace net {
+namespace test {
+
+class HpackDecoderStatePeer {
+ public:
+  static HpackDecoderTables* GetDecoderTables(HpackDecoderState* state) {
+    return &state->decoder_tables_;
+  }
+};
+
+class Http2HpackDecoderPeer {
+ public:
+  static HpackDecoderState* GetDecoderState(Http2HpackDecoder* decoder) {
+    return &decoder->decoder_state_;
+  }
+  static HpackDecoderTables* GetDecoderTables(Http2HpackDecoder* decoder) {
+    return HpackDecoderStatePeer::GetDecoderTables(GetDecoderState(decoder));
+  }
+};
+
+class HpackDecoder3Peer {
+ public:
+  explicit HpackDecoder3Peer(HpackDecoder3* decoder) : decoder_(decoder) {}
+
+  void HandleHeaderRepresentation(StringPiece name, StringPiece value) {
+    decoder_->listener_adapter_.OnHeader(HpackEntryType::kIndexedLiteralHeader,
+                                         HpackString(name), HpackString(value));
+  }
+
+  HpackDecoderTables* GetDecoderTables() {
+    return Http2HpackDecoderPeer::GetDecoderTables(&decoder_->hpack_decoder_);
+  }
+
+  const HpackStringPair* GetTableEntry(uint32_t index) {
+    return GetDecoderTables()->Lookup(index);
+  }
+
+  size_t current_header_table_size() {
+    return GetDecoderTables()->current_header_table_size();
+  }
+
+  size_t header_table_size_limit() {
+    return GetDecoderTables()->header_table_size_limit();
+  }
+
+  void set_header_table_size_limit(size_t size) {
+    return GetDecoderTables()->DynamicTableSizeUpdate(size);
+  }
+
+ private:
+  HpackDecoder3* decoder_;
+};
+
+namespace {
+
+// Is HandleControlFrameHeadersStart to be called, and with what value?
+enum StartChoice { START_WITH_HANDLER, START_WITHOUT_HANDLER, NO_START };
+
+class HpackDecoder3Test
+    : public ::testing::TestWithParam<std::tuple<StartChoice, bool>> {
+ protected:
+  HpackDecoder3Test() : decoder_(), decoder_peer_(&decoder_) {}
+
+  void SetUp() override {
+    std::tie(start_choice_, randomly_split_input_buffer_) = GetParam();
+  }
+
+  void HandleControlFrameHeadersStart() {
+    switch (start_choice_) {
+      case START_WITH_HANDLER:
+        decoder_.HandleControlFrameHeadersStart(&handler_);
+        break;
+      case START_WITHOUT_HANDLER:
+        decoder_.HandleControlFrameHeadersStart(nullptr);
+        break;
+      case NO_START:
+        break;
+    }
+  }
+
+  bool HandleControlFrameHeadersData(StringPiece str) {
+    VLOG(3) << "HandleControlFrameHeadersData:\n"
+            << base::HexEncode(str.data(), str.size());
+    return decoder_.HandleControlFrameHeadersData(str.data(), str.size());
+  }
+
+  bool HandleControlFrameHeadersComplete(size_t* size) {
+    return decoder_.HandleControlFrameHeadersComplete(size);
+  }
+
+  bool DecodeHeaderBlock(StringPiece str) {
+    // Don't call this again if HandleControlFrameHeadersData failed previously.
+    EXPECT_FALSE(decode_has_failed_);
+    HandleControlFrameHeadersStart();
+    if (randomly_split_input_buffer_) {
+      do {
+        // Decode some fragment of the remaining bytes.
+        size_t bytes = str.length();
+        if (!str.empty()) {
+          bytes = (random_.Rand8() % str.length()) + 1;
+        }
+        EXPECT_LE(bytes, str.length());
+        if (!HandleControlFrameHeadersData(str.substr(0, bytes))) {
+          decode_has_failed_ = true;
+          return false;
+        }
+        str.remove_prefix(bytes);
+      } while (!str.empty());
+    } else if (!HandleControlFrameHeadersData(str)) {
+      decode_has_failed_ = true;
+      return false;
+    }
+    if (!HandleControlFrameHeadersComplete(nullptr)) {
+      decode_has_failed_ = true;
+      return false;
+    }
+    return true;
+  }
+
+  bool EncodeAndDecodeDynamicTableSizeUpdates(size_t first, size_t second) {
+    HpackBlockBuilder hbb;
+    hbb.AppendDynamicTableSizeUpdate(first);
+    if (second != first) {
+      hbb.AppendDynamicTableSizeUpdate(second);
+    }
+    return DecodeHeaderBlock(hbb.buffer());
+  }
+
+  const SpdyHeaderBlock& decoded_block() const {
+    if (start_choice_ == START_WITH_HANDLER) {
+      return handler_.decoded_block();
+    } else {
+      return decoder_.decoded_block();
+    }
+  }
+
+  const SpdyHeaderBlock& DecodeBlockExpectingSuccess(StringPiece str) {
+    EXPECT_TRUE(DecodeHeaderBlock(str));
+    return decoded_block();
+  }
+
+  void expectEntry(size_t index,
+                   size_t size,
+                   const string& name,
+                   const string& value) {
+    const HpackStringPair* entry = decoder_peer_.GetTableEntry(index);
+    EXPECT_EQ(name, entry->name) << "index " << index;
+    EXPECT_EQ(value, entry->value);
+    EXPECT_EQ(size, entry->size());
+  }
+
+  SpdyHeaderBlock MakeHeaderBlock(
+      const std::vector<std::pair<string, string>>& headers) {
+    SpdyHeaderBlock result;
+    for (const auto& kv : headers) {
+      result.AppendValueOrAddHeader(kv.first, kv.second);
+    }
+    return result;
+  }
+
+  Http2Random random_;
+  HpackHuffmanTable huffman_table_;
+  HpackDecoder3 decoder_;
+  test::HpackDecoder3Peer decoder_peer_;
+  TestHeadersHandler handler_;
+  StartChoice start_choice_;
+  bool randomly_split_input_buffer_;
+  bool decode_has_failed_ = false;
+};
+
+INSTANTIATE_TEST_CASE_P(
+    StartChoiceAndRandomlySplitChoice,
+    HpackDecoder3Test,
+    ::testing::Combine(
+        ::testing::Values(START_WITH_HANDLER, START_WITHOUT_HANDLER, NO_START),
+        ::testing::Bool()));
+
+TEST_P(HpackDecoder3Test, AddHeaderDataWithHandleControlFrameHeadersData) {
+  // The hpack decode buffer size is limited in size. This test verifies that
+  // adding encoded data under that limit is accepted, and data that exceeds the
+  // limit is rejected.
+  HandleControlFrameHeadersStart();
+  const size_t kMaxBufferSizeBytes = 50;
+  const string a_value = string(49, 'x');
+  decoder_.set_max_decode_buffer_size_bytes(kMaxBufferSizeBytes);
+  HpackBlockBuilder hbb;
+  hbb.AppendLiteralNameAndValue(HpackEntryType::kNeverIndexedLiteralHeader,
+                                false, "a", false, a_value);
+  const string& s = hbb.buffer();
+  EXPECT_GT(s.size(), kMaxBufferSizeBytes);
+
+  // Any one in input buffer must not exceed kMaxBufferSizeBytes.
+  EXPECT_TRUE(HandleControlFrameHeadersData(s.substr(0, s.size() / 2)));
+  EXPECT_TRUE(HandleControlFrameHeadersData(s.substr(s.size() / 2)));
+
+  EXPECT_FALSE(HandleControlFrameHeadersData(s));
+  SpdyHeaderBlock expected_block = MakeHeaderBlock({{"a", a_value}});
+  EXPECT_EQ(expected_block, decoded_block());
+}
+
+TEST_P(HpackDecoder3Test, NameTooLong) {
+  // Verify that a name longer than the allowed size generates an error.
+  const size_t kMaxBufferSizeBytes = 50;
+  const string name = string(2 * kMaxBufferSizeBytes, 'x');
+  const string value = "abc";
+
+  decoder_.set_max_decode_buffer_size_bytes(kMaxBufferSizeBytes);
+
+  HpackBlockBuilder hbb;
+  hbb.AppendLiteralNameAndValue(HpackEntryType::kNeverIndexedLiteralHeader,
+                                false, name, false, value);
+
+  const size_t fragment_size = (3 * kMaxBufferSizeBytes) / 2;
+  const string fragment = hbb.buffer().substr(0, fragment_size);
+
+  HandleControlFrameHeadersStart();
+  EXPECT_FALSE(HandleControlFrameHeadersData(fragment));
+}
+
+TEST_P(HpackDecoder3Test, HeaderTooLongToBuffer) {
+  // Verify that a header longer than the allowed size generates an error if
+  // it isn't all in one input buffer.
+  const string name = "some-key";
+  const string value = "some-value";
+  const size_t kMaxBufferSizeBytes = name.size() + value.size() - 2;
+  decoder_.set_max_decode_buffer_size_bytes(kMaxBufferSizeBytes);
+
+  HpackBlockBuilder hbb;
+  hbb.AppendLiteralNameAndValue(HpackEntryType::kNeverIndexedLiteralHeader,
+                                false, name, false, value);
+  const size_t fragment_size = hbb.size() - 1;
+  const string fragment = hbb.buffer().substr(0, fragment_size);
+
+  HandleControlFrameHeadersStart();
+  EXPECT_FALSE(HandleControlFrameHeadersData(fragment));
+}
+
+// Decode with incomplete data in buffer.
+TEST_P(HpackDecoder3Test, DecodeWithIncompleteData) {
+  HandleControlFrameHeadersStart();
+
+  // No need to wait for more data.
+  EXPECT_TRUE(HandleControlFrameHeadersData("\x82\x85\x82"));
+  std::vector<std::pair<string, string>> expected_headers = {
+      {":method", "GET"}, {":path", "/index.html"}, {":method", "GET"}};
+
+  SpdyHeaderBlock expected_block1 = MakeHeaderBlock(expected_headers);
+  EXPECT_EQ(expected_block1, decoded_block());
+
+  // Full and partial headers, won't add partial to the headers.
+  EXPECT_TRUE(
+      HandleControlFrameHeadersData("\x40\x03goo"
+                                    "\x03gar\xbe\x40\x04spam"));
+  expected_headers.push_back({"goo", "gar"});
+  expected_headers.push_back({"goo", "gar"});
+
+  SpdyHeaderBlock expected_block2 = MakeHeaderBlock(expected_headers);
+  EXPECT_EQ(expected_block2, decoded_block());
+
+  // Add the needed data.
+  EXPECT_TRUE(HandleControlFrameHeadersData("\x04gggs"));
+
+  size_t size = 0;
+  EXPECT_TRUE(HandleControlFrameHeadersComplete(&size));
+  EXPECT_EQ(24u, size);
+
+  expected_headers.push_back({"spam", "gggs"});
+
+  SpdyHeaderBlock expected_block3 = MakeHeaderBlock(expected_headers);
+  EXPECT_EQ(expected_block3, decoded_block());
+}
+
+TEST_P(HpackDecoder3Test, HandleHeaderRepresentation) {
+  // Make sure the decoder is properly initialized.
+  HandleControlFrameHeadersStart();
+  HandleControlFrameHeadersData("");
+
+  // All cookie crumbs are joined.
+  decoder_peer_.HandleHeaderRepresentation("cookie", " part 1");
+  decoder_peer_.HandleHeaderRepresentation("cookie", "part 2 ");
+  decoder_peer_.HandleHeaderRepresentation("cookie", "part3");
+
+  // Already-delimited headers are passed through.
+  decoder_peer_.HandleHeaderRepresentation("passed-through",
+                                           string("foo\0baz", 7));
+
+  // Other headers are joined on \0. Case matters.
+  decoder_peer_.HandleHeaderRepresentation("joined", "not joined");
+  decoder_peer_.HandleHeaderRepresentation("joineD", "value 1");
+  decoder_peer_.HandleHeaderRepresentation("joineD", "value 2");
+
+  // Empty headers remain empty.
+  decoder_peer_.HandleHeaderRepresentation("empty", "");
+
+  // Joined empty headers work as expected.
+  decoder_peer_.HandleHeaderRepresentation("empty-joined", "");
+  decoder_peer_.HandleHeaderRepresentation("empty-joined", "foo");
+  decoder_peer_.HandleHeaderRepresentation("empty-joined", "");
+  decoder_peer_.HandleHeaderRepresentation("empty-joined", "");
+
+  // Non-contiguous cookie crumb.
+  decoder_peer_.HandleHeaderRepresentation("cookie", " fin!");
+
+  // Finish and emit all headers.
+  decoder_.HandleControlFrameHeadersComplete(nullptr);
+
+  // Resulting decoded headers are in the same order as the inputs.
+  EXPECT_THAT(decoded_block(),
+              ElementsAre(Pair("cookie", " part 1; part 2 ; part3;  fin!"),
+                          Pair("passed-through", StringPiece("foo\0baz", 7)),
+                          Pair("joined", "not joined"),
+                          Pair("joineD", StringPiece("value 1\0value 2", 15)),
+                          Pair("empty", ""),
+                          Pair("empty-joined", StringPiece("\0foo\0\0", 6))));
+}
+
+// Decoding indexed static table field should work.
+TEST_P(HpackDecoder3Test, IndexedHeaderStatic) {
+  // Reference static table entries #2 and #5.
+  const SpdyHeaderBlock& header_set1 = DecodeBlockExpectingSuccess("\x82\x85");
+  SpdyHeaderBlock expected_header_set1;
+  expected_header_set1[":method"] = "GET";
+  expected_header_set1[":path"] = "/index.html";
+  EXPECT_EQ(expected_header_set1, header_set1);
+
+  // Reference static table entry #2.
+  const SpdyHeaderBlock& header_set2 = DecodeBlockExpectingSuccess("\x82");
+  SpdyHeaderBlock expected_header_set2;
+  expected_header_set2[":method"] = "GET";
+  EXPECT_EQ(expected_header_set2, header_set2);
+}
+
+TEST_P(HpackDecoder3Test, IndexedHeaderDynamic) {
+  // First header block: add an entry to header table.
+  const SpdyHeaderBlock& header_set1 = DecodeBlockExpectingSuccess(
+      "\x40\x03"
+      "foo"
+      "\x03"
+      "bar");
+  SpdyHeaderBlock expected_header_set1;
+  expected_header_set1["foo"] = "bar";
+  EXPECT_EQ(expected_header_set1, header_set1);
+
+  // Second header block: add another entry to header table.
+  const SpdyHeaderBlock& header_set2 = DecodeBlockExpectingSuccess(
+      "\xbe\x40\x04"
+      "spam"
+      "\x04"
+      "eggs");
+  SpdyHeaderBlock expected_header_set2;
+  expected_header_set2["foo"] = "bar";
+  expected_header_set2["spam"] = "eggs";
+  EXPECT_EQ(expected_header_set2, header_set2);
+
+  // Third header block: refer to most recently added entry.
+  const SpdyHeaderBlock& header_set3 = DecodeBlockExpectingSuccess("\xbe");
+  SpdyHeaderBlock expected_header_set3;
+  expected_header_set3["spam"] = "eggs";
+  EXPECT_EQ(expected_header_set3, header_set3);
+}
+
+// Test a too-large indexed header.
+TEST_P(HpackDecoder3Test, InvalidIndexedHeader) {
+  // High-bit set, and a prefix of one more than the number of static entries.
+  EXPECT_FALSE(DecodeHeaderBlock("\xbe"));
+}
+
+TEST_P(HpackDecoder3Test, ContextUpdateMaximumSize) {
+  EXPECT_EQ(kDefaultHeaderTableSizeSetting,
+            decoder_peer_.header_table_size_limit());
+  string input;
+  {
+    // Maximum-size update with size 126. Succeeds.
+    HpackOutputStream output_stream;
+    output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode);
+    output_stream.AppendUint32(126);
+
+    output_stream.TakeString(&input);
+    EXPECT_TRUE(DecodeHeaderBlock(StringPiece(input)));
+    EXPECT_EQ(126u, decoder_peer_.header_table_size_limit());
+  }
+  {
+    // Maximum-size update with kDefaultHeaderTableSizeSetting. Succeeds.
+    HpackOutputStream output_stream;
+    output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode);
+    output_stream.AppendUint32(kDefaultHeaderTableSizeSetting);
+
+    output_stream.TakeString(&input);
+    EXPECT_TRUE(DecodeHeaderBlock(StringPiece(input)));
+    EXPECT_EQ(kDefaultHeaderTableSizeSetting,
+              decoder_peer_.header_table_size_limit());
+  }
+  {
+    // Maximum-size update with kDefaultHeaderTableSizeSetting + 1. Fails.
+    HpackOutputStream output_stream;
+    output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode);
+    output_stream.AppendUint32(kDefaultHeaderTableSizeSetting + 1);
+
+    output_stream.TakeString(&input);
+    EXPECT_FALSE(DecodeHeaderBlock(StringPiece(input)));
+    EXPECT_EQ(kDefaultHeaderTableSizeSetting,
+              decoder_peer_.header_table_size_limit());
+  }
+}
+
+// Two HeaderTableSizeUpdates may appear at the beginning of the block
+TEST_P(HpackDecoder3Test, TwoTableSizeUpdates) {
+  string input;
+  {
+    // Should accept two table size updates, update to second one
+    HpackOutputStream output_stream;
+    output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode);
+    output_stream.AppendUint32(0);
+    output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode);
+    output_stream.AppendUint32(122);
+
+    output_stream.TakeString(&input);
+    EXPECT_TRUE(DecodeHeaderBlock(StringPiece(input)));
+    EXPECT_EQ(122u, decoder_peer_.header_table_size_limit());
+  }
+}
+
+// Three HeaderTableSizeUpdates should result in an error
+TEST_P(HpackDecoder3Test, ThreeTableSizeUpdatesError) {
+  string input;
+  {
+    // Should reject three table size updates, update to second one
+    HpackOutputStream output_stream;
+    output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode);
+    output_stream.AppendUint32(5);
+    output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode);
+    output_stream.AppendUint32(10);
+    output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode);
+    output_stream.AppendUint32(15);
+
+    output_stream.TakeString(&input);
+
+    EXPECT_FALSE(DecodeHeaderBlock(StringPiece(input)));
+    EXPECT_EQ(10u, decoder_peer_.header_table_size_limit());
+  }
+}
+
+// HeaderTableSizeUpdates may only appear at the beginning of the block
+// Any other updates should result in an error
+TEST_P(HpackDecoder3Test, TableSizeUpdateSecondError) {
+  string input;
+  {
+    // Should reject a table size update appearing after a different entry
+    // The table size should remain as the default
+    HpackOutputStream output_stream;
+    output_stream.AppendBytes("\x82\x85");
+    output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode);
+    output_stream.AppendUint32(123);
+
+    output_stream.TakeString(&input);
+
+    EXPECT_FALSE(DecodeHeaderBlock(StringPiece(input)));
+    EXPECT_EQ(kDefaultHeaderTableSizeSetting,
+              decoder_peer_.header_table_size_limit());
+  }
+}
+
+// HeaderTableSizeUpdates may only appear at the beginning of the block
+// Any other updates should result in an error
+TEST_P(HpackDecoder3Test, TableSizeUpdateFirstThirdError) {
+  string input;
+  {
+    // Should reject the second table size update
+    // if a different entry appears after the first update
+    // The table size should update to the first but not the second
+    HpackOutputStream output_stream;
+    output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode);
+    output_stream.AppendUint32(60);
+    output_stream.AppendBytes("\x82\x85");
+    output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode);
+    output_stream.AppendUint32(125);
+
+    output_stream.TakeString(&input);
+
+    EXPECT_FALSE(DecodeHeaderBlock(StringPiece(input)));
+    EXPECT_EQ(60u, decoder_peer_.header_table_size_limit());
+  }
+}
+
+// Decoding two valid encoded literal headers with no indexing should
+// work.
+TEST_P(HpackDecoder3Test, LiteralHeaderNoIndexing) {
+  // First header with indexed name, second header with string literal
+  // name.
+  const char input[] = "\x04\x0c/sample/path\x00\x06:path2\x0e/sample/path/2";
+  const SpdyHeaderBlock& header_set =
+      DecodeBlockExpectingSuccess(StringPiece(input, arraysize(input) - 1));
+
+  SpdyHeaderBlock expected_header_set;
+  expected_header_set[":path"] = "/sample/path";
+  expected_header_set[":path2"] = "/sample/path/2";
+  EXPECT_EQ(expected_header_set, header_set);
+}
+
+// Decoding two valid encoded literal headers with incremental
+// indexing and string literal names should work.
+TEST_P(HpackDecoder3Test, LiteralHeaderIncrementalIndexing) {
+  const char input[] = "\x44\x0c/sample/path\x40\x06:path2\x0e/sample/path/2";
+  const SpdyHeaderBlock& header_set =
+      DecodeBlockExpectingSuccess(StringPiece(input, arraysize(input) - 1));
+
+  SpdyHeaderBlock expected_header_set;
+  expected_header_set[":path"] = "/sample/path";
+  expected_header_set[":path2"] = "/sample/path/2";
+  EXPECT_EQ(expected_header_set, header_set);
+}
+
+TEST_P(HpackDecoder3Test, LiteralHeaderWithIndexingInvalidNameIndex) {
+  decoder_.ApplyHeaderTableSizeSetting(0);
+  EXPECT_TRUE(EncodeAndDecodeDynamicTableSizeUpdates(0, 0));
+
+  // Name is the last static index. Works.
+  EXPECT_TRUE(DecodeHeaderBlock(StringPiece("\x7d\x03ooo")));
+  // Name is one beyond the last static index. Fails.
+  EXPECT_FALSE(DecodeHeaderBlock(StringPiece("\x7e\x03ooo")));
+}
+
+TEST_P(HpackDecoder3Test, LiteralHeaderNoIndexingInvalidNameIndex) {
+  // Name is the last static index. Works.
+  EXPECT_TRUE(DecodeHeaderBlock(StringPiece("\x0f\x2e\x03ooo")));
+  // Name is one beyond the last static index. Fails.
+  EXPECT_FALSE(DecodeHeaderBlock(StringPiece("\x0f\x2f\x03ooo")));
+}
+
+TEST_P(HpackDecoder3Test, LiteralHeaderNeverIndexedInvalidNameIndex) {
+  // Name is the last static index. Works.
+  EXPECT_TRUE(DecodeHeaderBlock(StringPiece("\x1f\x2e\x03ooo")));
+  // Name is one beyond the last static index. Fails.
+  EXPECT_FALSE(DecodeHeaderBlock(StringPiece("\x1f\x2f\x03ooo")));
+}
+
+TEST_P(HpackDecoder3Test, TruncatedIndex) {
+  // Indexed Header, varint for index requires multiple bytes,
+  // but only one provided.
+  EXPECT_FALSE(DecodeHeaderBlock(StringPiece("\xff", 1)));
+}
+
+TEST_P(HpackDecoder3Test, TruncatedHuffmanLiteral) {
+  // Literal value, Huffman encoded, but with the last byte missing (i.e.
+  // drop the final ff shown below).
+  //
+  // 41                                      | == Literal indexed ==
+  //                                         |   Indexed name (idx = 1)
+  //                                         |     :authority
+  // 8c                                      |   Literal value (len = 12)
+  //                                         |     Huffman encoded:
+  // f1e3 c2e5 f23a 6ba0 ab90 f4ff           | .....:k.....
+  //                                         |     Decoded:
+  //                                         | www.example.com
+  //                                         | -> :authority: www.example.com
+
+  string first = a2b_hex("418cf1e3c2e5f23a6ba0ab90f4ff");
+  EXPECT_TRUE(DecodeHeaderBlock(first));
+  first = a2b_hex("418cf1e3c2e5f23a6ba0ab90f4");
+  EXPECT_FALSE(DecodeHeaderBlock(first));
+}
+
+TEST_P(HpackDecoder3Test, HuffmanEOSError) {
+  // Literal value, Huffman encoded, but with an additional ff byte at the end
+  // of the string, i.e. an EOS that is longer than permitted.
+  //
+  // 41                                      | == Literal indexed ==
+  //                                         |   Indexed name (idx = 1)
+  //                                         |     :authority
+  // 8d                                      |   Literal value (len = 13)
+  //                                         |     Huffman encoded:
+  // f1e3 c2e5 f23a 6ba0 ab90 f4ff           | .....:k.....
+  //                                         |     Decoded:
+  //                                         | www.example.com
+  //                                         | -> :authority: www.example.com
+
+  string first = a2b_hex("418cf1e3c2e5f23a6ba0ab90f4ff");
+  EXPECT_TRUE(DecodeHeaderBlock(first));
+  first = a2b_hex("418df1e3c2e5f23a6ba0ab90f4ffff");
+  EXPECT_FALSE(DecodeHeaderBlock(first));
+}
+
+// Round-tripping the header set from RFC 7541 C.3.1 should work.
+// http://httpwg.org/specs/rfc7541.html#rfc.section.C.3.1
+TEST_P(HpackDecoder3Test, BasicC31) {
+  HpackEncoder encoder(ObtainHpackHuffmanTable());
+
+  SpdyHeaderBlock expected_header_set;
+  expected_header_set[":method"] = "GET";
+  expected_header_set[":scheme"] = "http";
+  expected_header_set[":path"] = "/";
+  expected_header_set[":authority"] = "www.example.com";
+
+  string encoded_header_set;
+  EXPECT_TRUE(
+      encoder.EncodeHeaderSet(expected_header_set, &encoded_header_set));
+
+  EXPECT_TRUE(DecodeHeaderBlock(encoded_header_set));
+  EXPECT_EQ(expected_header_set, decoded_block());
+}
+
+// RFC 7541, Section C.4: Request Examples with Huffman Coding
+// http://httpwg.org/specs/rfc7541.html#rfc.section.C.4
+TEST_P(HpackDecoder3Test, SectionC4RequestHuffmanExamples) {
+  // TODO(jamessynge): Use net/http2/hpack/tools/hpack_example.h to parse the
+  // example directly, instead of having it as a comment.
+  // 82                                      | == Indexed - Add ==
+  //                                         |   idx = 2
+  //                                         | -> :method: GET
+  // 86                                      | == Indexed - Add ==
+  //                                         |   idx = 6
+  //                                         | -> :scheme: http
+  // 84                                      | == Indexed - Add ==
+  //                                         |   idx = 4
+  //                                         | -> :path: /
+  // 41                                      | == Literal indexed ==
+  //                                         |   Indexed name (idx = 1)
+  //                                         |     :authority
+  // 8c                                      |   Literal value (len = 12)
+  //                                         |     Huffman encoded:
+  // f1e3 c2e5 f23a 6ba0 ab90 f4ff           | .....:k.....
+  //                                         |     Decoded:
+  //                                         | www.example.com
+  //                                         | -> :authority: www.example.com
+  string first = a2b_hex("828684418cf1e3c2e5f23a6ba0ab90f4ff");
+  const SpdyHeaderBlock& first_header_set = DecodeBlockExpectingSuccess(first);
+
+  EXPECT_THAT(first_header_set,
+              ElementsAre(
+                  // clang-format off
+      Pair(":method", "GET"),
+      Pair(":scheme", "http"),
+      Pair(":path", "/"),
+      Pair(":authority", "www.example.com")));
+  // clang-format on
+
+  expectEntry(62, 57, ":authority", "www.example.com");
+  EXPECT_EQ(57u, decoder_peer_.current_header_table_size());
+
+  // 82                                      | == Indexed - Add ==
+  //                                         |   idx = 2
+  //                                         | -> :method: GET
+  // 86                                      | == Indexed - Add ==
+  //                                         |   idx = 6
+  //                                         | -> :scheme: http
+  // 84                                      | == Indexed - Add ==
+  //                                         |   idx = 4
+  //                                         | -> :path: /
+  // be                                      | == Indexed - Add ==
+  //                                         |   idx = 62
+  //                                         | -> :authority: www.example.com
+  // 58                                      | == Literal indexed ==
+  //                                         |   Indexed name (idx = 24)
+  //                                         |     cache-control
+  // 86                                      |   Literal value (len = 8)
+  //                                         |     Huffman encoded:
+  // a8eb 1064 9cbf                          | ...d..
+  //                                         |     Decoded:
+  //                                         | no-cache
+  //                                         | -> cache-control: no-cache
+
+  string second = a2b_hex("828684be5886a8eb10649cbf");
+  const SpdyHeaderBlock& second_header_set =
+      DecodeBlockExpectingSuccess(second);
+
+  EXPECT_THAT(second_header_set,
+              ElementsAre(
+                  // clang-format off
+      Pair(":method", "GET"),
+      Pair(":scheme", "http"),
+      Pair(":path", "/"),
+      Pair(":authority", "www.example.com"),
+      Pair("cache-control", "no-cache")));
+  // clang-format on
+
+  expectEntry(62, 53, "cache-control", "no-cache");
+  expectEntry(63, 57, ":authority", "www.example.com");
+  EXPECT_EQ(110u, decoder_peer_.current_header_table_size());
+
+  // 82                                      | == Indexed - Add ==
+  //                                         |   idx = 2
+  //                                         | -> :method: GET
+  // 87                                      | == Indexed - Add ==
+  //                                         |   idx = 7
+  //                                         | -> :scheme: https
+  // 85                                      | == Indexed - Add ==
+  //                                         |   idx = 5
+  //                                         | -> :path: /index.html
+  // bf                                      | == Indexed - Add ==
+  //                                         |   idx = 63
+  //                                         | -> :authority: www.example.com
+  // 40                                      | == Literal indexed ==
+  // 88                                      |   Literal name (len = 10)
+  //                                         |     Huffman encoded:
+  // 25a8 49e9 5ba9 7d7f                     | %.I.[.}.
+  //                                         |     Decoded:
+  //                                         | custom-key
+  // 89                                      |   Literal value (len = 12)
+  //                                         |     Huffman encoded:
+  // 25a8 49e9 5bb8 e8b4 bf                  | %.I.[....
+  //                                         |     Decoded:
+  //                                         | custom-value
+  //                                         | -> custom-key: custom-value
+  string third = a2b_hex("828785bf408825a849e95ba97d7f8925a849e95bb8e8b4bf");
+  const SpdyHeaderBlock& third_header_set = DecodeBlockExpectingSuccess(third);
+
+  EXPECT_THAT(
+      third_header_set,
+      ElementsAre(
+          // clang-format off
+      Pair(":method", "GET"),
+      Pair(":scheme", "https"),
+      Pair(":path", "/index.html"),
+      Pair(":authority", "www.example.com"),
+      Pair("custom-key", "custom-value")));
+  // clang-format on
+
+  expectEntry(62, 54, "custom-key", "custom-value");
+  expectEntry(63, 53, "cache-control", "no-cache");
+  expectEntry(64, 57, ":authority", "www.example.com");
+  EXPECT_EQ(164u, decoder_peer_.current_header_table_size());
+}
+
+// RFC 7541, Section C.6: Response Examples with Huffman Coding
+// http://httpwg.org/specs/rfc7541.html#rfc.section.C.6
+TEST_P(HpackDecoder3Test, SectionC6ResponseHuffmanExamples) {
+  // The example is based on a maximum dynamic table size of 256,
+  // which allows for testing dynamic table evictions.
+  decoder_peer_.set_header_table_size_limit(256);
+
+  // 48                                      | == Literal indexed ==
+  //                                         |   Indexed name (idx = 8)
+  //                                         |     :status
+  // 82                                      |   Literal value (len = 3)
+  //                                         |     Huffman encoded:
+  // 6402                                    | d.
+  //                                         |     Decoded:
+  //                                         | 302
+  //                                         | -> :status: 302
+  // 58                                      | == Literal indexed ==
+  //                                         |   Indexed name (idx = 24)
+  //                                         |     cache-control
+  // 85                                      |   Literal value (len = 7)
+  //                                         |     Huffman encoded:
+  // aec3 771a 4b                            | ..w.K
+  //                                         |     Decoded:
+  //                                         | private
+  //                                         | -> cache-control: private
+  // 61                                      | == Literal indexed ==
+  //                                         |   Indexed name (idx = 33)
+  //                                         |     date
+  // 96                                      |   Literal value (len = 29)
+  //                                         |     Huffman encoded:
+  // d07a be94 1054 d444 a820 0595 040b 8166 | .z...T.D. .....f
+  // e082 a62d 1bff                          | ...-..
+  //                                         |     Decoded:
+  //                                         | Mon, 21 Oct 2013 20:13:21
+  //                                         | GMT
+  //                                         | -> date: Mon, 21 Oct 2013
+  //                                         |   20:13:21 GMT
+  // 6e                                      | == Literal indexed ==
+  //                                         |   Indexed name (idx = 46)
+  //                                         |     location
+  // 91                                      |   Literal value (len = 23)
+  //                                         |     Huffman encoded:
+  // 9d29 ad17 1863 c78f 0b97 c8e9 ae82 ae43 | .)...c.........C
+  // d3                                      | .
+  //                                         |     Decoded:
+  //                                         | https://www.example.com
+  //                                         | -> location: https://www.e
+  //                                         |    xample.com
+
+  string first = a2b_hex(
+      "488264025885aec3771a4b6196d07abe"
+      "941054d444a8200595040b8166e082a6"
+      "2d1bff6e919d29ad171863c78f0b97c8"
+      "e9ae82ae43d3");
+  const SpdyHeaderBlock& first_header_set = DecodeBlockExpectingSuccess(first);
+
+  EXPECT_THAT(first_header_set,
+              ElementsAre(
+                  // clang-format off
+      Pair(":status", "302"),
+      Pair("cache-control", "private"),
+      Pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"),
+      Pair("location", "https://www.example.com")));
+  // clang-format on
+
+  expectEntry(62, 63, "location", "https://www.example.com");
+  expectEntry(63, 65, "date", "Mon, 21 Oct 2013 20:13:21 GMT");
+  expectEntry(64, 52, "cache-control", "private");
+  expectEntry(65, 42, ":status", "302");
+  EXPECT_EQ(222u, decoder_peer_.current_header_table_size());
+
+  // 48                                      | == Literal indexed ==
+  //                                         |   Indexed name (idx = 8)
+  //                                         |     :status
+  // 83                                      |   Literal value (len = 3)
+  //                                         |     Huffman encoded:
+  // 640e ff                                 | d..
+  //                                         |     Decoded:
+  //                                         | 307
+  //                                         | - evict: :status: 302
+  //                                         | -> :status: 307
+  // c1                                      | == Indexed - Add ==
+  //                                         |   idx = 65
+  //                                         | -> cache-control: private
+  // c0                                      | == Indexed - Add ==
+  //                                         |   idx = 64
+  //                                         | -> date: Mon, 21 Oct 2013
+  //                                         |   20:13:21 GMT
+  // bf                                      | == Indexed - Add ==
+  //                                         |   idx = 63
+  //                                         | -> location:
+  //                                         |   https://www.example.com
+  string second = a2b_hex("4883640effc1c0bf");
+  const SpdyHeaderBlock& second_header_set =
+      DecodeBlockExpectingSuccess(second);
+
+  EXPECT_THAT(second_header_set,
+              ElementsAre(
+                  // clang-format off
+      Pair(":status", "307"),
+      Pair("cache-control", "private"),
+      Pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"),
+      Pair("location", "https://www.example.com")));
+  // clang-format on
+
+  expectEntry(62, 42, ":status", "307");
+  expectEntry(63, 63, "location", "https://www.example.com");
+  expectEntry(64, 65, "date", "Mon, 21 Oct 2013 20:13:21 GMT");
+  expectEntry(65, 52, "cache-control", "private");
+  EXPECT_EQ(222u, decoder_peer_.current_header_table_size());
+
+  // 88                                      | == Indexed - Add ==
+  //                                         |   idx = 8
+  //                                         | -> :status: 200
+  // c1                                      | == Indexed - Add ==
+  //                                         |   idx = 65
+  //                                         | -> cache-control: private
+  // 61                                      | == Literal indexed ==
+  //                                         |   Indexed name (idx = 33)
+  //                                         |     date
+  // 96                                      |   Literal value (len = 22)
+  //                                         |     Huffman encoded:
+  // d07a be94 1054 d444 a820 0595 040b 8166 | .z...T.D. .....f
+  // e084 a62d 1bff                          | ...-..
+  //                                         |     Decoded:
+  //                                         | Mon, 21 Oct 2013 20:13:22
+  //                                         | GMT
+  //                                         | - evict: cache-control:
+  //                                         |   private
+  //                                         | -> date: Mon, 21 Oct 2013
+  //                                         |   20:13:22 GMT
+  // c0                                      | == Indexed - Add ==
+  //                                         |   idx = 64
+  //                                         | -> location:
+  //                                         |    https://www.example.com
+  // 5a                                      | == Literal indexed ==
+  //                                         |   Indexed name (idx = 26)
+  //                                         |     content-encoding
+  // 83                                      |   Literal value (len = 3)
+  //                                         |     Huffman encoded:
+  // 9bd9 ab                                 | ...
+  //                                         |     Decoded:
+  //                                         | gzip
+  //                                         | - evict: date: Mon, 21 Oct
+  //                                         |    2013 20:13:21 GMT
+  //                                         | -> content-encoding: gzip
+  // 77                                      | == Literal indexed ==
+  //                                         |   Indexed name (idx = 55)
+  //                                         |     set-cookie
+  // ad                                      |   Literal value (len = 45)
+  //                                         |     Huffman encoded:
+  // 94e7 821d d7f2 e6c7 b335 dfdf cd5b 3960 | .........5...[9`
+  // d5af 2708 7f36 72c1 ab27 0fb5 291f 9587 | ..'..6r..'..)...
+  // 3160 65c0 03ed 4ee5 b106 3d50 07        | 1`e...N...=P.
+  //                                         |     Decoded:
+  //                                         | foo=ASDJKHQKBZXOQWEOPIUAXQ
+  //                                         | WEOIU; max-age=3600; versi
+  //                                         | on=1
+  //                                         | - evict: location:
+  //                                         |   https://www.example.com
+  //                                         | - evict: :status: 307
+  //                                         | -> set-cookie: foo=ASDJKHQ
+  //                                         |   KBZXOQWEOPIUAXQWEOIU;
+  //                                         |   max-age=3600; version=1
+  string third = a2b_hex(
+      "88c16196d07abe941054d444a8200595"
+      "040b8166e084a62d1bffc05a839bd9ab"
+      "77ad94e7821dd7f2e6c7b335dfdfcd5b"
+      "3960d5af27087f3672c1ab270fb5291f"
+      "9587316065c003ed4ee5b1063d5007");
+  const SpdyHeaderBlock& third_header_set = DecodeBlockExpectingSuccess(third);
+
+  EXPECT_THAT(third_header_set,
+              ElementsAre(
+                  // clang-format off
+      Pair(":status", "200"),
+      Pair("cache-control", "private"),
+      Pair("date", "Mon, 21 Oct 2013 20:13:22 GMT"),
+      Pair("location", "https://www.example.com"),
+      Pair("content-encoding", "gzip"),
+      Pair("set-cookie", "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU;"
+           " max-age=3600; version=1")));
+  // clang-format on
+
+  expectEntry(62, 98, "set-cookie",
+              "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU;"
+              " max-age=3600; version=1");
+  expectEntry(63, 52, "content-encoding", "gzip");
+  expectEntry(64, 65, "date", "Mon, 21 Oct 2013 20:13:22 GMT");
+  EXPECT_EQ(215u, decoder_peer_.current_header_table_size());
+}
+
+// Regression test: Found that entries with dynamic indexed names and literal
+// values caused "use after free" MSAN failures if the name was evicted as it
+// was being re-used.
+TEST_P(HpackDecoder3Test, ReuseNameOfEvictedEntry) {
+  // Each entry is measured as 32 bytes plus the sum of the lengths of the name
+  // and the value. Set the size big enough for at most one entry, and a fairly
+  // small one at that (31 ASCII characters).
+  decoder_.ApplyHeaderTableSizeSetting(63);
+
+  HpackBlockBuilder hbb;
+  hbb.AppendDynamicTableSizeUpdate(0);
+  hbb.AppendDynamicTableSizeUpdate(63);
+
+  const StringPiece name("some-name");
+  const StringPiece value1("some-value");
+  const StringPiece value2("another-value");
+  const StringPiece value3("yet-another-value");
+
+  // Add an entry that will become the first in the dynamic table, entry 62.
+  hbb.AppendLiteralNameAndValue(HpackEntryType::kIndexedLiteralHeader, false,
+                                name, false, value1);
+
+  // Confirm that entry has been added by re-using it.
+  hbb.AppendIndexedHeader(62);
+
+  // Add another entry referring to the name of the first. This will evict the
+  // first.
+  hbb.AppendNameIndexAndLiteralValue(HpackEntryType::kIndexedLiteralHeader, 62,
+                                     false, value2);
+
+  // Confirm that entry has been added by re-using it.
+  hbb.AppendIndexedHeader(62);
+
+  // Add another entry referring to the name of the second. This will evict the
+  // second.
+  hbb.AppendNameIndexAndLiteralValue(HpackEntryType::kIndexedLiteralHeader, 62,
+                                     false, value3);
+
+  // Confirm that entry has been added by re-using it.
+  hbb.AppendIndexedHeader(62);
+
+  EXPECT_TRUE(DecodeHeaderBlock(hbb.buffer()));
+
+  SpdyHeaderBlock expected_header_set;
+  expected_header_set.AppendValueOrAddHeader(name, value1);
+  expected_header_set.AppendValueOrAddHeader(name, value1);
+  expected_header_set.AppendValueOrAddHeader(name, value2);
+  expected_header_set.AppendValueOrAddHeader(name, value2);
+  expected_header_set.AppendValueOrAddHeader(name, value3);
+  expected_header_set.AppendValueOrAddHeader(name, value3);
+
+  // SpdyHeaderBlock stores these 6 strings as '\0' separated values.
+  // Make sure that is what happened.
+  string joined_values = expected_header_set[name].as_string();
+  EXPECT_EQ(joined_values.size(),
+            2 * value1.size() + 2 * value2.size() + 2 * value3.size() + 5);
+
+  EXPECT_EQ(expected_header_set, decoded_block());
+}
+
+}  // namespace
+}  // namespace test
+}  // namespace net
diff --git a/net/spdy/hpack/hpack_decoder_interface.h b/net/spdy/hpack/hpack_decoder_interface.h
index 8adb62ff..1103e31 100644
--- a/net/spdy/hpack/hpack_decoder_interface.h
+++ b/net/spdy/hpack/hpack_decoder_interface.h
@@ -28,11 +28,13 @@
 
   // If a SpdyHeadersHandlerInterface is provided, the decoder will emit
   // headers to it rather than accumulating them in a SpdyHeaderBlock.
+  // Does not take ownership of the handler, but does use the pointer until
+  // the current HPACK block is completely decoded.
   virtual void HandleControlFrameHeadersStart(
       SpdyHeadersHandlerInterface* handler) = 0;
 
   // Called as HPACK block fragments arrive. Returns false if an error occurred
-  // while decoding the block.
+  // while decoding the block. Does not take ownership of headers_data.
   virtual bool HandleControlFrameHeadersData(const char* headers_data,
                                              size_t headers_data_length) = 0;
 
@@ -57,6 +59,11 @@
       std::unique_ptr<HpackHeaderTable::DebugVisitorInterface> visitor) = 0;
 
   // Set how much encoded data this decoder is willing to buffer.
+  // TODO(jamessynge): Resolve definition of this value, as it is currently
+  // too tied to a single implementation. We probably want to limit one or more
+  // of these: individual name or value strings, header entries, the entire
+  // header list, or the HPACK block; we probably shouldn't care about the size
+  // of individual transport buffers.
   virtual void set_max_decode_buffer_size_bytes(
       size_t max_decode_buffer_size_bytes) = 0;
 };
diff --git a/net/spdy/hpack/hpack_decoder_test.cc b/net/spdy/hpack/hpack_decoder_test.cc
index a0fe74f..5a26633a 100644
--- a/net/spdy/hpack/hpack_decoder_test.cc
+++ b/net/spdy/hpack/hpack_decoder_test.cc
@@ -543,8 +543,9 @@
   EXPECT_EQ(21u, input_stream.ParsedBytes());
 }
 
-// Round-tripping the header set from E.2.1 should work.
-TEST_P(HpackDecoderTest, BasicE21) {
+// Round-tripping the header set from RFC 7541 C.3.1 should work.
+// http://httpwg.org/specs/rfc7541.html#rfc.section.C.3.1
+TEST_P(HpackDecoderTest, BasicC31) {
   HpackEncoder encoder(ObtainHpackHuffmanTable());
 
   SpdyHeaderBlock expected_header_set;
@@ -561,7 +562,9 @@
   EXPECT_EQ(expected_header_set, decoded_block());
 }
 
-TEST_P(HpackDecoderTest, SectionD4RequestHuffmanExamples) {
+// RFC 7541, Section C.4: Request Examples with Huffman Coding
+// http://httpwg.org/specs/rfc7541.html#rfc.section.C.4
+TEST_P(HpackDecoderTest, SectionC4RequestHuffmanExamples) {
   // 82                                      | == Indexed - Add ==
   //                                         |   idx = 2
   //                                         | -> :method: GET
@@ -668,7 +671,9 @@
   EXPECT_EQ(164u, decoder_peer_.header_table()->size());
 }
 
-TEST_P(HpackDecoderTest, SectionD6ResponseHuffmanExamples) {
+// RFC 7541, Section C.6: Response Examples with Huffman Coding
+// http://httpwg.org/specs/rfc7541.html#rfc.section.C.6
+TEST_P(HpackDecoderTest, SectionC6ResponseHuffmanExamples) {
   decoder_.ApplyHeaderTableSizeSetting(256);
 
   // 48                                      | == Literal indexed ==
diff --git a/net/spdy/spdy_flags.cc b/net/spdy/spdy_flags.cc
index fa380d4..1f342d8 100644
--- a/net/spdy/spdy_flags.cc
+++ b/net/spdy/spdy_flags.cc
@@ -12,9 +12,12 @@
 // If true, remove use of SpdyFrameBuilder::OverwriteLength().
 bool FLAGS_chromium_http2_flag_remove_rewritelength = true;
 
-// Use //net/http2/hpack/decoder as HPACK decoder.
+// Use //net/http2/hpack/decoder as HPACK entry decoder.
 bool FLAGS_chromium_http2_flag_spdy_use_hpack_decoder2 = false;
 
+// Use //net/http2/hpack/decoder as complete HPACK decoder.
+bool FLAGS_chromium_http2_flag_spdy_use_hpack_decoder3 = false;
+
 // If true, increase HPACK table size up to optimal size kOptTableSize if
 // clients allow it.
 bool FLAGS_chromium_reloadable_flag_increase_hpack_table_size = false;
diff --git a/net/spdy/spdy_flags.h b/net/spdy/spdy_flags.h
index d44cb9de..d448594 100644
--- a/net/spdy/spdy_flags.h
+++ b/net/spdy/spdy_flags.h
@@ -14,6 +14,8 @@
 NET_EXPORT_PRIVATE extern bool
     FLAGS_chromium_http2_flag_spdy_use_hpack_decoder2;
 NET_EXPORT_PRIVATE extern bool
+    FLAGS_chromium_http2_flag_spdy_use_hpack_decoder3;
+NET_EXPORT_PRIVATE extern bool
     FLAGS_chromium_reloadable_flag_increase_hpack_table_size;
 NET_EXPORT_PRIVATE extern bool FLAGS_use_http2_frame_decoder_adapter;
 NET_EXPORT_PRIVATE extern bool FLAGS_use_nested_spdy_framer_decoder;
diff --git a/net/spdy/spdy_framer.cc b/net/spdy/spdy_framer.cc
index 85e8426..db06280 100644
--- a/net/spdy/spdy_framer.cc
+++ b/net/spdy/spdy_framer.cc
@@ -25,6 +25,7 @@
 #include "net/spdy/hpack/hpack_constants.h"
 #include "net/spdy/hpack/hpack_decoder.h"
 #include "net/spdy/hpack/hpack_decoder2.h"
+#include "net/spdy/hpack/hpack_decoder3.h"
 #include "net/spdy/http2_frame_decoder_adapter.h"
 #include "net/spdy/spdy_bitmasks.h"
 #include "net/spdy/spdy_bug_tracker.h"
@@ -2471,7 +2472,11 @@
 
 HpackDecoderInterface* SpdyFramer::GetHpackDecoder() {
   if (hpack_decoder_.get() == nullptr) {
-    if (FLAGS_chromium_http2_flag_spdy_use_hpack_decoder2) {
+    if (FLAGS_chromium_http2_flag_spdy_use_hpack_decoder3) {
+      SPDY_BUG_IF(FLAGS_chromium_http2_flag_spdy_use_hpack_decoder2)
+          << "Both alternate decoders are enabled.";
+      hpack_decoder_.reset(new HpackDecoder3());
+    } else if (FLAGS_chromium_http2_flag_spdy_use_hpack_decoder2) {
       hpack_decoder_.reset(new HpackDecoder2());
     } else {
       hpack_decoder_.reset(new HpackDecoder());
diff --git a/net/spdy/spdy_framer_test.cc b/net/spdy/spdy_framer_test.cc
index 90ffade..e3b3fff9 100644
--- a/net/spdy/spdy_framer_test.cc
+++ b/net/spdy/spdy_framer_test.cc
@@ -608,7 +608,7 @@
 }
 
 enum DecoderChoice { DECODER_SELF, DECODER_NESTED, DECODER_HTTP2 };
-enum HpackChoice { HPACK_DECODER_1, HPACK_DECODER_2 };
+enum HpackChoice { HPACK_DECODER_1, HPACK_DECODER_2, HPACK_DECODER_3 };
 
 class SpdyFramerTest
     : public ::testing::TestWithParam<std::tuple<DecoderChoice, HpackChoice>> {
@@ -632,9 +632,15 @@
     switch (std::get<1>(param)) {
       case HPACK_DECODER_1:
         FLAGS_chromium_http2_flag_spdy_use_hpack_decoder2 = false;
+        FLAGS_chromium_http2_flag_spdy_use_hpack_decoder3 = false;
         break;
       case HPACK_DECODER_2:
         FLAGS_chromium_http2_flag_spdy_use_hpack_decoder2 = true;
+        FLAGS_chromium_http2_flag_spdy_use_hpack_decoder3 = false;
+        break;
+      case HPACK_DECODER_3:
+        FLAGS_chromium_http2_flag_spdy_use_hpack_decoder2 = false;
+        FLAGS_chromium_http2_flag_spdy_use_hpack_decoder3 = true;
         break;
     }
   }
@@ -661,13 +667,12 @@
   }
 };
 
-INSTANTIATE_TEST_CASE_P(SpdyFramerTests,
-                        SpdyFramerTest,
-                        ::testing::Combine(::testing::Values(DECODER_SELF,
-                                                             DECODER_NESTED,
-                                                             DECODER_HTTP2),
-                                           ::testing::Values(HPACK_DECODER_1,
-                                                             HPACK_DECODER_2)));
+INSTANTIATE_TEST_CASE_P(
+    SpdyFramerTests,
+    SpdyFramerTest,
+    ::testing::Combine(
+        ::testing::Values(DECODER_SELF, DECODER_NESTED, DECODER_HTTP2),
+        ::testing::Values(HPACK_DECODER_1, HPACK_DECODER_2, HPACK_DECODER_3)));
 
 // Test that we can encode and decode a SpdyHeaderBlock in serialized form.
 TEST_P(SpdyFramerTest, HeaderBlockInBuffer) {
diff --git a/services/preferences/public/cpp/pref_observer_store.cc b/services/preferences/public/cpp/pref_observer_store.cc
index 7b38fe8..2b553d5 100644
--- a/services/preferences/public/cpp/pref_observer_store.cc
+++ b/services/preferences/public/cpp/pref_observer_store.cc
@@ -11,14 +11,15 @@
 namespace preferences {
 
 PrefObserverStore::PrefObserverStore(
-    prefs::mojom::PreferencesManagerPtr prefs_manager_ptr)
+    prefs::mojom::PreferencesFactoryPtr pref_factory_ptr)
     : prefs_binding_(this),
-      prefs_manager_ptr_(std::move(prefs_manager_ptr)),
-      initialized_(false) {}
+      pref_factory_ptr_(std::move(pref_factory_ptr)),
+      initialized_(false) {
+  pref_factory_ptr_->Create(prefs_binding_.CreateInterfacePtrAndBind(),
+                            mojo::MakeRequest(&prefs_manager_ptr_));
+}
 
 void PrefObserverStore::Subscribe(const std::set<std::string>& keys) {
-  if (keys_.empty())
-    prefs_manager_ptr_->AddObserver(prefs_binding_.CreateInterfacePtrAndBind());
   keys_.insert(keys.begin(), keys.end());
 
   std::vector<std::string> pref_array;
diff --git a/services/preferences/public/cpp/pref_observer_store.h b/services/preferences/public/cpp/pref_observer_store.h
index 0b723463..67e3f83 100644
--- a/services/preferences/public/cpp/pref_observer_store.h
+++ b/services/preferences/public/cpp/pref_observer_store.h
@@ -30,7 +30,7 @@
                           public prefs::mojom::PreferencesObserver {
  public:
   explicit PrefObserverStore(
-      prefs::mojom::PreferencesManagerPtr prefs_manager_ptr);
+      prefs::mojom::PreferencesFactoryPtr pref_factory_ptr);
 
   // Adds a set of |keys| which PrefObserverStore will handle. Begins listening
   // for changes to these from |prefs_manager_|.
@@ -67,6 +67,7 @@
       std::unique_ptr<base::DictionaryValue> preferences) override;
 
   mojo::Binding<prefs::mojom::PreferencesObserver> prefs_binding_;
+  prefs::mojom::PreferencesFactoryPtr pref_factory_ptr_;
   prefs::mojom::PreferencesManagerPtr prefs_manager_ptr_;
 
   std::set<std::string> keys_;
diff --git a/services/preferences/public/cpp/tests/pref_observer_store_unittest.cc b/services/preferences/public/cpp/tests/pref_observer_store_unittest.cc
index 9dbd0a5..f5fa5a7 100644
--- a/services/preferences/public/cpp/tests/pref_observer_store_unittest.cc
+++ b/services/preferences/public/cpp/tests/pref_observer_store_unittest.cc
@@ -21,37 +21,27 @@
  public:
   TestPreferenceManager(
       mojo::InterfaceRequest<prefs::mojom::PreferencesManager> request)
-      : add_observer_called_(false),
-        set_preferences_called_(false),
-        binding_(this, std::move(request)) {}
+      : set_preferences_called_(false), binding_(this, std::move(request)) {}
   ~TestPreferenceManager() override {}
 
-  bool add_observer_called() { return add_observer_called_; }
   const std::set<std::string>& last_preference_set() {
     return last_preference_set_;
   }
   bool set_preferences_called() { return set_preferences_called_; }
 
   // prefs::mojom::TestPreferenceManager:
-  void AddObserver(prefs::mojom::PreferencesObserverPtr client) override;
   void SetPreferences(
       std::unique_ptr<base::DictionaryValue> preferences) override;
   void Subscribe(const std::vector<std::string>& preferences) override;
 
  private:
-  bool add_observer_called_;
   std::set<std::string> last_preference_set_;
   bool set_preferences_called_;
-  mojo::Binding<PreferencesManager> binding_;
+  mojo::Binding<prefs::mojom::PreferencesManager> binding_;
 
   DISALLOW_COPY_AND_ASSIGN(TestPreferenceManager);
 };
 
-void TestPreferenceManager::AddObserver(
-    prefs::mojom::PreferencesObserverPtr client) {
-  add_observer_called_ = true;
-}
-
 void TestPreferenceManager::SetPreferences(
     std::unique_ptr<base::DictionaryValue> preferences) {
   set_preferences_called_ = true;
@@ -63,6 +53,33 @@
   last_preference_set_.insert(preferences.begin(), preferences.end());
 }
 
+// Test implementation of prefs::mojom::PreferencesFactory which simply creates
+// the TestPreferenceManager used for testing.
+class TestPreferenceFactory : public prefs::mojom::PreferencesFactory {
+ public:
+  TestPreferenceFactory(
+      mojo::InterfaceRequest<prefs::mojom::PreferencesFactory> request)
+      : binding_(this, std::move(request)) {}
+  ~TestPreferenceFactory() override {}
+
+  TestPreferenceManager* manager() { return manager_.get(); }
+
+  void Create(prefs::mojom::PreferencesObserverPtr observer,
+              prefs::mojom::PreferencesManagerRequest manager) override;
+
+ private:
+  mojo::Binding<prefs::mojom::PreferencesFactory> binding_;
+  std::unique_ptr<TestPreferenceManager> manager_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestPreferenceFactory);
+};
+
+void TestPreferenceFactory::Create(
+    prefs::mojom::PreferencesObserverPtr observer,
+    prefs::mojom::PreferencesManagerRequest manager) {
+  manager_.reset(new TestPreferenceManager(std::move(manager)));
+}
+
 }  // namespace
 
 namespace preferences {
@@ -72,7 +89,7 @@
   PrefObserverStoreTest() {}
   ~PrefObserverStoreTest() override {}
 
-  TestPreferenceManager* manager() { return manager_.get(); }
+  TestPreferenceManager* manager() { return factory_->manager(); }
   PrefStoreObserverMock* observer() { return &observer_; }
   PrefObserverStore* store() { return store_.get(); }
 
@@ -87,8 +104,8 @@
 
  private:
   scoped_refptr<PrefObserverStore> store_;
-  prefs::mojom::PreferencesManagerPtr proxy_;
-  std::unique_ptr<TestPreferenceManager> manager_;
+  prefs::mojom::PreferencesFactoryPtr factory_proxy_;
+  std::unique_ptr<TestPreferenceFactory> factory_;
   PrefStoreObserverMock observer_;
   // Required by mojo binding code within PrefObserverStore.
   base::MessageLoop message_loop_;
@@ -97,8 +114,9 @@
 };
 
 void PrefObserverStoreTest::SetUp() {
-  manager_.reset(new TestPreferenceManager(mojo::MakeRequest(&proxy_)));
-  store_ = new PrefObserverStore(std::move(proxy_));
+  factory_.reset(new TestPreferenceFactory(mojo::MakeRequest(&factory_proxy_)));
+  store_ = new PrefObserverStore(std::move(factory_proxy_));
+  base::RunLoop().RunUntilIdle();
   store_->AddObserver(&observer_);
 }
 
diff --git a/services/preferences/public/interfaces/preferences.mojom b/services/preferences/public/interfaces/preferences.mojom
index 27d43d31..cae6a15f5 100644
--- a/services/preferences/public/interfaces/preferences.mojom
+++ b/services/preferences/public/interfaces/preferences.mojom
@@ -8,6 +8,13 @@
 
 const string kServiceName = "preferences";
 
+// Used for the creation of a PreferencesManager and to ensure that the
+// PreferencesObserver is bound at creation time.
+interface PreferencesFactory {
+  // Creates a PreferencesManager bound to the provided |observer|.
+  Create(PreferencesObserver observer, PreferencesManager& manager);
+};
+
 // Used to subscribe to preference changes within PreferenceManager. After
 // requesting to observe, the current values for all requested keys are sent.
 interface PreferencesObserver {
@@ -17,7 +24,6 @@
 // Manages actual read/write of preference data. Accepts observers who subscribe
 // to preferences, notifying them of changes.
 interface PreferencesManager {
-  AddObserver(PreferencesObserver client);
   SetPreferences(mojo.common.mojom.DictionaryValue preferences);
   Subscribe(array<string> preferences);
 };
diff --git a/testing/buildbot/chromium.perf.json b/testing/buildbot/chromium.perf.json
index f5039e1..2675422 100644
--- a/testing/buildbot/chromium.perf.json
+++ b/testing/buildbot/chromium.perf.json
@@ -44659,6 +44659,11125 @@
       }
     ]
   },
+  "Mac Mini 8GB 10.12 Perf": {
+    "isolated_scripts": [
+      {
+        "args": [
+          "battor.power_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "battor.power_cases",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build26-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "battor.power_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "battor.power_cases.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build26-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "battor.power_cases_no_chrome_trace",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "battor.power_cases_no_chrome_trace",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "battor.power_cases_no_chrome_trace",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "battor.power_cases_no_chrome_trace.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "battor.steady_state",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "battor.steady_state",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "battor.steady_state",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "battor.steady_state.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "battor.tough_video_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "battor.tough_video_cases",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "battor.tough_video_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "battor.tough_video_cases.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "battor.trivial_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "battor.trivial_pages",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "battor.trivial_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "battor.trivial_pages.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "blink_perf.bindings",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "blink_perf.bindings",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "blink_perf.bindings",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "blink_perf.bindings.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "blink_perf.blink_gc",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "blink_perf.blink_gc",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "blink_perf.blink_gc",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "blink_perf.blink_gc.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "blink_perf.canvas",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "blink_perf.canvas",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "blink_perf.canvas",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "blink_perf.canvas.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "blink_perf.css",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "blink_perf.css",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build26-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "blink_perf.css",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "blink_perf.css.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build26-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "blink_perf.dom",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "blink_perf.dom",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build26-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "blink_perf.dom",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "blink_perf.dom.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build26-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "blink_perf.events",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "blink_perf.events",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build24-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "blink_perf.events",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "blink_perf.events.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build24-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "blink_perf.layout",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "blink_perf.layout",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build24-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "blink_perf.layout",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "blink_perf.layout.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build24-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "blink_perf.paint",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "blink_perf.paint",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "blink_perf.paint",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "blink_perf.paint.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "blink_perf.parser",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "blink_perf.parser",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "blink_perf.parser",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "blink_perf.parser.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "blink_perf.pywebsocket",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "blink_perf.pywebsocket",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build24-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "blink_perf.pywebsocket",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "blink_perf.pywebsocket.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build24-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "blink_perf.shadow_dom",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "blink_perf.shadow_dom",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "blink_perf.shadow_dom",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "blink_perf.shadow_dom.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "blink_perf.svg",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "blink_perf.svg",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build24-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "blink_perf.svg",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "blink_perf.svg.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build24-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "blink_perf.xml_http_request",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "blink_perf.xml_http_request",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build26-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "blink_perf.xml_http_request",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "blink_perf.xml_http_request.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build26-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "blink_style.key_mobile_sites",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "blink_style.key_mobile_sites",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "blink_style.key_mobile_sites",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "blink_style.key_mobile_sites.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "blink_style.polymer",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "blink_style.polymer",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "blink_style.polymer",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "blink_style.polymer.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "blink_style.top_25",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "blink_style.top_25",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build26-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "blink_style.top_25",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "blink_style.top_25.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build26-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "blob_storage.blob_storage",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "blob_storage.blob_storage",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "blob_storage.blob_storage",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "blob_storage.blob_storage.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "dromaeo.cssqueryjquery",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "dromaeo.cssqueryjquery",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "dromaeo.cssqueryjquery",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "dromaeo.cssqueryjquery.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "dromaeo.domcoreattr",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "dromaeo.domcoreattr",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "dromaeo.domcoreattr",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "dromaeo.domcoreattr.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "dromaeo.domcoremodify",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "dromaeo.domcoremodify",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "dromaeo.domcoremodify",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "dromaeo.domcoremodify.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "dromaeo.domcorequery",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "dromaeo.domcorequery",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "dromaeo.domcorequery",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "dromaeo.domcorequery.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "dromaeo.domcoretraverse",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "dromaeo.domcoretraverse",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "dromaeo.domcoretraverse",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "dromaeo.domcoretraverse.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "dromaeo.jslibattrjquery",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "dromaeo.jslibattrjquery",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build26-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "dromaeo.jslibattrjquery",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "dromaeo.jslibattrjquery.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build26-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "dromaeo.jslibattrprototype",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "dromaeo.jslibattrprototype",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "dromaeo.jslibattrprototype",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "dromaeo.jslibattrprototype.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "dromaeo.jslibeventjquery",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "dromaeo.jslibeventjquery",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "dromaeo.jslibeventjquery",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "dromaeo.jslibeventjquery.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "dromaeo.jslibeventprototype",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "dromaeo.jslibeventprototype",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build24-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "dromaeo.jslibeventprototype",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "dromaeo.jslibeventprototype.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build24-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "dromaeo.jslibmodifyjquery",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "dromaeo.jslibmodifyjquery",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build26-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "dromaeo.jslibmodifyjquery",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "dromaeo.jslibmodifyjquery.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build26-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "dromaeo.jslibmodifyprototype",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "dromaeo.jslibmodifyprototype",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "dromaeo.jslibmodifyprototype",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "dromaeo.jslibmodifyprototype.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "dromaeo.jslibstylejquery",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "dromaeo.jslibstylejquery",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "dromaeo.jslibstylejquery",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "dromaeo.jslibstylejquery.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "dromaeo.jslibstyleprototype",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "dromaeo.jslibstyleprototype",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "dromaeo.jslibstyleprototype",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "dromaeo.jslibstyleprototype.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "dromaeo.jslibtraversejquery",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "dromaeo.jslibtraversejquery",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build24-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "dromaeo.jslibtraversejquery",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "dromaeo.jslibtraversejquery.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build24-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "dromaeo.jslibtraverseprototype",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "dromaeo.jslibtraverseprototype",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build24-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "dromaeo.jslibtraverseprototype",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "dromaeo.jslibtraverseprototype.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build24-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "dummy_benchmark.noisy_benchmark_1",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "dummy_benchmark.noisy_benchmark_1",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "dummy_benchmark.noisy_benchmark_1",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "dummy_benchmark.noisy_benchmark_1.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "dummy_benchmark.stable_benchmark_1",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "dummy_benchmark.stable_benchmark_1",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build26-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "dummy_benchmark.stable_benchmark_1",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "dummy_benchmark.stable_benchmark_1.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build26-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "gpu_times.gpu_rasterization.key_mobile_sites_smooth",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "gpu_times.gpu_rasterization.key_mobile_sites_smooth",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build24-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "gpu_times.gpu_rasterization.key_mobile_sites_smooth",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "gpu_times.gpu_rasterization.key_mobile_sites_smooth.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build24-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "gpu_times.gpu_rasterization.top_25_smooth",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "gpu_times.gpu_rasterization.top_25_smooth",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "gpu_times.gpu_rasterization.top_25_smooth",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "gpu_times.gpu_rasterization.top_25_smooth.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "gpu_times.key_mobile_sites_smooth",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "gpu_times.key_mobile_sites_smooth",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "gpu_times.key_mobile_sites_smooth",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "gpu_times.key_mobile_sites_smooth.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "gpu_times.top_25_smooth",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "gpu_times.top_25_smooth",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "gpu_times.top_25_smooth",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "gpu_times.top_25_smooth.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "image_decoding.image_decoding_measurement",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "image_decoding.image_decoding_measurement",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "image_decoding.image_decoding_measurement",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "image_decoding.image_decoding_measurement.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "indexeddb_perf",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "indexeddb_perf",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build26-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "indexeddb_perf",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "indexeddb_perf.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build26-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "jetstream",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "jetstream",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "jetstream",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "jetstream.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "jitter",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "jitter",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "jitter",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "jitter.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "kraken",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "kraken",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "kraken",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "kraken.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "loading.cluster_telemetry",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "loading.cluster_telemetry",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "loading.cluster_telemetry",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "loading.cluster_telemetry.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "loading.mobile",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "loading.mobile",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 14400,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "loading.mobile",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "loading.mobile.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 14400,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "media.android.tough_video_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "media.android.tough_video_cases",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "media.android.tough_video_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "media.android.tough_video_cases.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "media.chromeOS.tough_video_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "media.chromeOS.tough_video_cases",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "media.chromeOS.tough_video_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "media.chromeOS.tough_video_cases.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "media.chromeOS4kOnly.tough_video_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "media.chromeOS4kOnly.tough_video_cases",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "media.chromeOS4kOnly.tough_video_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "media.chromeOS4kOnly.tough_video_cases.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "media.media_cns_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "media.media_cns_cases",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "media.media_cns_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "media.media_cns_cases.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "media.mse_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "media.mse_cases",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build24-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "media.mse_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "media.mse_cases.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build24-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "media.tough_video_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "media.tough_video_cases",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build24-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "media.tough_video_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "media.tough_video_cases.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build24-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "media.tough_video_cases_extra",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "media.tough_video_cases_extra",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build26-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "media.tough_video_cases_extra",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "media.tough_video_cases_extra.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build26-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "memory.blink_memory_mobile",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "memory.blink_memory_mobile",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "memory.blink_memory_mobile",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "memory.blink_memory_mobile.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "memory.dual_browser_test",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "memory.dual_browser_test",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build26-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "memory.dual_browser_test",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "memory.dual_browser_test.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build26-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "memory.long_running_dual_browser_test",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "memory.long_running_dual_browser_test",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "memory.long_running_dual_browser_test",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "memory.long_running_dual_browser_test.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "memory.long_running_idle_gmail_background_tbmv2",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "memory.long_running_idle_gmail_background_tbmv2",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build26-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "memory.long_running_idle_gmail_background_tbmv2",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "memory.long_running_idle_gmail_background_tbmv2.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build26-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "memory.long_running_idle_gmail_tbmv2",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "memory.long_running_idle_gmail_tbmv2",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build24-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "memory.long_running_idle_gmail_tbmv2",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "memory.long_running_idle_gmail_tbmv2.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build24-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "memory.top_10_mobile",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "memory.top_10_mobile",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build24-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "memory.top_10_mobile",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "memory.top_10_mobile.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build24-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "memory.top_10_mobile_stress",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "memory.top_10_mobile_stress",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "memory.top_10_mobile_stress",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "memory.top_10_mobile_stress.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "octane",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "octane",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "octane",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "octane.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "oilpan_gc_times.blink_perf_stress",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "oilpan_gc_times.blink_perf_stress",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "oilpan_gc_times.blink_perf_stress",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "oilpan_gc_times.blink_perf_stress.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "oilpan_gc_times.key_silk_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "oilpan_gc_times.key_silk_cases",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "oilpan_gc_times.key_silk_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "oilpan_gc_times.key_silk_cases.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "oilpan_gc_times.sync_scroll.key_mobile_sites_smooth",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "oilpan_gc_times.sync_scroll.key_mobile_sites_smooth",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "oilpan_gc_times.sync_scroll.key_mobile_sites_smooth",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "oilpan_gc_times.sync_scroll.key_mobile_sites_smooth.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "oilpan_gc_times.tough_animation_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "oilpan_gc_times.tough_animation_cases",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build26-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "oilpan_gc_times.tough_animation_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "oilpan_gc_times.tough_animation_cases.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build26-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "oortonline",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "oortonline",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "oortonline",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "oortonline.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "oortonline_tbmv2",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "oortonline_tbmv2",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build24-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "oortonline_tbmv2",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "oortonline_tbmv2.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build24-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "page_cycler_v2.basic_oopif",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "page_cycler_v2.basic_oopif",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build26-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "page_cycler_v2.basic_oopif",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "page_cycler_v2.basic_oopif.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build26-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "page_cycler_v2.intl_ar_fa_he",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "page_cycler_v2.intl_ar_fa_he",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build26-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "page_cycler_v2.intl_ar_fa_he",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "page_cycler_v2.intl_ar_fa_he.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build26-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "page_cycler_v2.intl_es_fr_pt-BR",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "page_cycler_v2.intl_es_fr_pt-BR",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "page_cycler_v2.intl_es_fr_pt-BR",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "page_cycler_v2.intl_es_fr_pt-BR.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "page_cycler_v2.intl_hi_ru",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "page_cycler_v2.intl_hi_ru",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build26-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "page_cycler_v2.intl_hi_ru",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "page_cycler_v2.intl_hi_ru.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build26-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "page_cycler_v2.intl_ja_zh",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "page_cycler_v2.intl_ja_zh",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "page_cycler_v2.intl_ja_zh",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "page_cycler_v2.intl_ja_zh.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "page_cycler_v2.intl_ko_th_vi",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "page_cycler_v2.intl_ko_th_vi",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "page_cycler_v2.intl_ko_th_vi",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "page_cycler_v2.intl_ko_th_vi.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "page_cycler_v2.top_10_mobile",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "page_cycler_v2.top_10_mobile",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build24-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "page_cycler_v2.top_10_mobile",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "page_cycler_v2.top_10_mobile.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build24-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "page_cycler_v2.tough_layout_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "page_cycler_v2.tough_layout_cases",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "page_cycler_v2.tough_layout_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "page_cycler_v2.tough_layout_cases.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "page_cycler_v2.typical_25",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "page_cycler_v2.typical_25",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build26-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "page_cycler_v2.typical_25",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "page_cycler_v2.typical_25.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build26-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "page_cycler_v2_site_isolation.basic_oopif",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "page_cycler_v2_site_isolation.basic_oopif",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "page_cycler_v2_site_isolation.basic_oopif",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "page_cycler_v2_site_isolation.basic_oopif.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "power.android_acceptance",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "power.android_acceptance",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "power.android_acceptance",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "power.android_acceptance.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "power.gpu_rasterization.top_10",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "power.gpu_rasterization.top_10",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "power.gpu_rasterization.top_10",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "power.gpu_rasterization.top_10.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "power.gpu_rasterization.top_25",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "power.gpu_rasterization.top_25",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "power.gpu_rasterization.top_25",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "power.gpu_rasterization.top_25.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "power.gpu_rasterization.typical_10_mobile",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "power.gpu_rasterization.typical_10_mobile",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build24-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "power.gpu_rasterization.typical_10_mobile",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "power.gpu_rasterization.typical_10_mobile.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build24-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "power.steady_state",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "power.steady_state",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build24-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "power.steady_state",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "power.steady_state.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build24-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "power.top_10",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "power.top_10",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build24-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "power.top_10",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "power.top_10.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build24-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "power.top_25",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "power.top_25",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "power.top_25",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "power.top_25.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "power.tough_ad_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "power.tough_ad_cases",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "power.tough_ad_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "power.tough_ad_cases.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "power.trivial_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "power.trivial_pages",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "power.trivial_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "power.trivial_pages.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "power.typical_10_mobile",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "power.typical_10_mobile",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "power.typical_10_mobile",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "power.typical_10_mobile.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "power.typical_10_mobile_reload",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "power.typical_10_mobile_reload",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "power.typical_10_mobile_reload",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "power.typical_10_mobile_reload.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "rasterize_and_record_micro.key_mobile_sites",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "rasterize_and_record_micro.key_mobile_sites",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build26-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "rasterize_and_record_micro.key_mobile_sites",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "rasterize_and_record_micro.key_mobile_sites.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build26-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "rasterize_and_record_micro.key_silk_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "rasterize_and_record_micro.key_silk_cases",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "rasterize_and_record_micro.key_silk_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "rasterize_and_record_micro.key_silk_cases.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "rasterize_and_record_micro.partial_invalidation",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "rasterize_and_record_micro.partial_invalidation",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build24-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "rasterize_and_record_micro.partial_invalidation",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "rasterize_and_record_micro.partial_invalidation.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build24-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "rasterize_and_record_micro.polymer",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "rasterize_and_record_micro.polymer",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "rasterize_and_record_micro.polymer",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "rasterize_and_record_micro.polymer.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "rasterize_and_record_micro.top_25",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "rasterize_and_record_micro.top_25",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "rasterize_and_record_micro.top_25",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "rasterize_and_record_micro.top_25.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "repaint.gpu_rasterization.key_mobile_sites_repaint",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "repaint.gpu_rasterization.key_mobile_sites_repaint",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "repaint.gpu_rasterization.key_mobile_sites_repaint",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "repaint.gpu_rasterization.key_mobile_sites_repaint.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "repaint.key_mobile_sites_repaint",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "repaint.key_mobile_sites_repaint",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build24-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "repaint.key_mobile_sites_repaint",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "repaint.key_mobile_sites_repaint.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build24-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "robohornet_pro",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "robohornet_pro",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build24-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "robohornet_pro",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "robohornet_pro.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build24-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "scheduler.tough_scheduling_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "scheduler.tough_scheduling_cases",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "scheduler.tough_scheduling_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "scheduler.tough_scheduling_cases.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "service_worker.service_worker",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "service_worker.service_worker",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "service_worker.service_worker",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "service_worker.service_worker.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "service_worker.service_worker_micro_benchmark",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "service_worker.service_worker_micro_benchmark",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "service_worker.service_worker_micro_benchmark",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "service_worker.service_worker_micro_benchmark.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "smoothness.desktop_tough_pinch_zoom_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.desktop_tough_pinch_zoom_cases",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "smoothness.desktop_tough_pinch_zoom_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.desktop_tough_pinch_zoom_cases.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "smoothness.gpu_rasterization.polymer",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.gpu_rasterization.polymer",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build26-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "smoothness.gpu_rasterization.polymer",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.gpu_rasterization.polymer.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build26-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "smoothness.gpu_rasterization.top_25_smooth",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.gpu_rasterization.top_25_smooth",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build26-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "smoothness.gpu_rasterization.top_25_smooth",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.gpu_rasterization.top_25_smooth.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build26-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "smoothness.gpu_rasterization.tough_filters_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.gpu_rasterization.tough_filters_cases",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build24-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "smoothness.gpu_rasterization.tough_filters_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.gpu_rasterization.tough_filters_cases.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build24-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "smoothness.gpu_rasterization.tough_path_rendering_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.gpu_rasterization.tough_path_rendering_cases",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "smoothness.gpu_rasterization.tough_path_rendering_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.gpu_rasterization.tough_path_rendering_cases.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "smoothness.gpu_rasterization.tough_pinch_zoom_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.gpu_rasterization.tough_pinch_zoom_cases",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "smoothness.gpu_rasterization.tough_pinch_zoom_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.gpu_rasterization.tough_pinch_zoom_cases.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "smoothness.gpu_rasterization.tough_scrolling_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.gpu_rasterization.tough_scrolling_cases",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "smoothness.gpu_rasterization.tough_scrolling_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.gpu_rasterization.tough_scrolling_cases.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "smoothness.gpu_rasterization_and_decoding.image_decoding_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.gpu_rasterization_and_decoding.image_decoding_cases",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "smoothness.gpu_rasterization_and_decoding.image_decoding_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.gpu_rasterization_and_decoding.image_decoding_cases.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "smoothness.image_decoding_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.image_decoding_cases",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build26-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "smoothness.image_decoding_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.image_decoding_cases.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build26-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "smoothness.key_desktop_move_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.key_desktop_move_cases",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "smoothness.key_desktop_move_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.key_desktop_move_cases.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "smoothness.key_mobile_sites_smooth",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.key_mobile_sites_smooth",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build24-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "smoothness.key_mobile_sites_smooth",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.key_mobile_sites_smooth.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build24-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "smoothness.key_silk_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.key_silk_cases",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "smoothness.key_silk_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.key_silk_cases.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "smoothness.maps",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.maps",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "smoothness.maps",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.maps.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "smoothness.pathological_mobile_sites",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.pathological_mobile_sites",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "smoothness.pathological_mobile_sites",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.pathological_mobile_sites.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "smoothness.scrolling_tough_ad_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.scrolling_tough_ad_cases",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build24-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "smoothness.scrolling_tough_ad_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.scrolling_tough_ad_cases.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build24-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "smoothness.simple_mobile_sites",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.simple_mobile_sites",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build26-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "smoothness.simple_mobile_sites",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.simple_mobile_sites.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build26-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "smoothness.sync_scroll.key_mobile_sites_smooth",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.sync_scroll.key_mobile_sites_smooth",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "smoothness.sync_scroll.key_mobile_sites_smooth",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.sync_scroll.key_mobile_sites_smooth.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "smoothness.top_25_smooth",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.top_25_smooth",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "smoothness.top_25_smooth",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.top_25_smooth.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "smoothness.tough_ad_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.tough_ad_cases",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build24-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "smoothness.tough_ad_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.tough_ad_cases.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build24-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "smoothness.tough_animation_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.tough_animation_cases",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "smoothness.tough_animation_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.tough_animation_cases.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "smoothness.tough_canvas_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.tough_canvas_cases",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "smoothness.tough_canvas_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.tough_canvas_cases.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "smoothness.tough_filters_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.tough_filters_cases",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "smoothness.tough_filters_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.tough_filters_cases.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "smoothness.tough_image_decode_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.tough_image_decode_cases",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "smoothness.tough_image_decode_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.tough_image_decode_cases.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "smoothness.tough_path_rendering_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.tough_path_rendering_cases",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "smoothness.tough_path_rendering_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.tough_path_rendering_cases.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "smoothness.tough_pinch_zoom_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.tough_pinch_zoom_cases",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "smoothness.tough_pinch_zoom_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.tough_pinch_zoom_cases.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "smoothness.tough_scrolling_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.tough_scrolling_cases",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "smoothness.tough_scrolling_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.tough_scrolling_cases.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "smoothness.tough_texture_upload_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.tough_texture_upload_cases",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "smoothness.tough_texture_upload_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.tough_texture_upload_cases.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "smoothness.tough_webgl_ad_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.tough_webgl_ad_cases",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "smoothness.tough_webgl_ad_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.tough_webgl_ad_cases.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "smoothness.tough_webgl_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.tough_webgl_cases",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build26-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "smoothness.tough_webgl_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.tough_webgl_cases.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build26-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "spaceport",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "spaceport",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "spaceport",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "spaceport.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "speedometer",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "speedometer",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "speedometer-ignition",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "speedometer-ignition",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build24-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "speedometer-ignition",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "speedometer-ignition.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build24-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "speedometer-turbo",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "speedometer-turbo",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build26-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "speedometer-turbo",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "speedometer-turbo.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build26-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "speedometer",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "speedometer.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "start_with_ext.cold.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_ext.cold.blank_page",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "start_with_ext.cold.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_ext.cold.blank_page.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "start_with_ext.warm.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_ext.warm.blank_page",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "start_with_ext.warm.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_ext.warm.blank_page.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "start_with_url.cold.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.cold.startup_pages",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "start_with_url.cold.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.cold.startup_pages.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "start_with_url.warm.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.warm.startup_pages",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "start_with_url.warm.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.warm.startup_pages.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "startup.cold.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "startup.cold.blank_page",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "startup.cold.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "startup.cold.blank_page.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "startup.large_profile.cold.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "startup.large_profile.cold.blank_page",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "startup.large_profile.cold.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "startup.large_profile.cold.blank_page.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "startup.large_profile.warm.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "startup.large_profile.warm.blank_page",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "startup.large_profile.warm.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "startup.large_profile.warm.blank_page.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "startup.warm.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "startup.warm.blank_page",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build26-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "startup.warm.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "startup.warm.blank_page.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build26-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "startup.warm.chrome_signin",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "startup.warm.chrome_signin",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "startup.warm.chrome_signin",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "startup.warm.chrome_signin.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "storage.indexeddb_endure",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "storage.indexeddb_endure",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "storage.indexeddb_endure",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "storage.indexeddb_endure.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "storage.indexeddb_endure_tracing",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "storage.indexeddb_endure_tracing",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "storage.indexeddb_endure_tracing",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "storage.indexeddb_endure_tracing.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "sunspider",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "sunspider",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "sunspider",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "sunspider.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "system_health.common_desktop",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "system_health.common_desktop",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "system_health.common_desktop",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "system_health.common_desktop.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "system_health.common_mobile",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "system_health.common_mobile",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "system_health.common_mobile",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "system_health.common_mobile.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "system_health.memory_desktop",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "system_health.memory_desktop",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build24-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "system_health.memory_desktop",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "system_health.memory_desktop.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build24-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "system_health.memory_mobile",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "system_health.memory_mobile",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "system_health.memory_mobile",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "system_health.memory_mobile.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "system_health.webview_startup",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "system_health.webview_startup",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "system_health.webview_startup",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "system_health.webview_startup.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "system_health.webview_startup_multiprocess",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "system_health.webview_startup_multiprocess",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "system_health.webview_startup_multiprocess",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "system_health.webview_startup_multiprocess.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "tab_switching.five_blank_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "tab_switching.five_blank_pages",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "tab_switching.five_blank_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "tab_switching.five_blank_pages.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "tab_switching.top_10",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "tab_switching.top_10",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "tab_switching.top_10",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "tab_switching.top_10.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "tab_switching.tough_energy_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "tab_switching.tough_energy_cases",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "tab_switching.tough_energy_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "tab_switching.tough_energy_cases.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "tab_switching.tough_image_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "tab_switching.tough_image_cases",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build26-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "tab_switching.tough_image_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "tab_switching.tough_image_cases.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build26-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "tab_switching.typical_25",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "tab_switching.typical_25",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "tab_switching.typical_25",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "tab_switching.typical_25.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "text_selection.character",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "text_selection.character",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "text_selection.character",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "text_selection.character.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "text_selection.direction",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "text_selection.direction",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "text_selection.direction",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "text_selection.direction.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "thread_times.key_hit_test_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "thread_times.key_hit_test_cases",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build24-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "thread_times.key_hit_test_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "thread_times.key_hit_test_cases.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build24-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "thread_times.key_idle_power_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "thread_times.key_idle_power_cases",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "thread_times.key_idle_power_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "thread_times.key_idle_power_cases.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "thread_times.key_mobile_sites_smooth",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "thread_times.key_mobile_sites_smooth",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build24-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "thread_times.key_mobile_sites_smooth",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "thread_times.key_mobile_sites_smooth.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build24-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "thread_times.key_noop_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "thread_times.key_noop_cases",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "thread_times.key_noop_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "thread_times.key_noop_cases.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "thread_times.key_silk_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "thread_times.key_silk_cases",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build24-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "thread_times.key_silk_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "thread_times.key_silk_cases.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build24-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "thread_times.polymer",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "thread_times.polymer",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "thread_times.polymer",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "thread_times.polymer.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "thread_times.simple_mobile_sites",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "thread_times.simple_mobile_sites",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "thread_times.simple_mobile_sites",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "thread_times.simple_mobile_sites.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "thread_times.tough_compositor_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "thread_times.tough_compositor_cases",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "thread_times.tough_compositor_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "thread_times.tough_compositor_cases.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "thread_times.tough_scrolling_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "thread_times.tough_scrolling_cases",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build26-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "thread_times.tough_scrolling_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "thread_times.tough_scrolling_cases.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build26-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "tracing.tracing_with_background_memory_infra",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "tracing.tracing_with_background_memory_infra",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build24-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "tracing.tracing_with_background_memory_infra",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "tracing.tracing_with_background_memory_infra.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build24-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "tracing.tracing_with_debug_overhead",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "tracing.tracing_with_debug_overhead",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "tracing.tracing_with_debug_overhead",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "tracing.tracing_with_debug_overhead.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "v8.browsing_desktop",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "v8.browsing_desktop",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build24-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "v8.browsing_desktop",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "v8.browsing_desktop.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build24-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "v8.browsing_desktop_ignition",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "v8.browsing_desktop_ignition",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "v8.browsing_desktop_ignition",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "v8.browsing_desktop_ignition.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "v8.browsing_desktop_turbo",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "v8.browsing_desktop_turbo",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build26-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "v8.browsing_desktop_turbo",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "v8.browsing_desktop_turbo.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build26-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "v8.browsing_mobile",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "v8.browsing_mobile",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "v8.browsing_mobile",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "v8.browsing_mobile.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "v8.browsing_mobile_ignition",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "v8.browsing_mobile_ignition",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "v8.browsing_mobile_ignition",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "v8.browsing_mobile_ignition.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "v8.browsing_mobile_turbo",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "v8.browsing_mobile_turbo",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "v8.browsing_mobile_turbo",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "v8.browsing_mobile_turbo.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "v8.detached_context_age_in_gc",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "v8.detached_context_age_in_gc",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build26-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "v8.detached_context_age_in_gc",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "v8.detached_context_age_in_gc.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build26-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "v8.google",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "v8.google",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "v8.google",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "v8.google.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "v8.infinite_scroll-ignition_tbmv2",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "v8.infinite_scroll-ignition_tbmv2",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build26-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "v8.infinite_scroll-ignition_tbmv2",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "v8.infinite_scroll-ignition_tbmv2.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build26-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "v8.infinite_scroll-turbo_tbmv2",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "v8.infinite_scroll-turbo_tbmv2",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build26-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "v8.infinite_scroll-turbo_tbmv2",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "v8.infinite_scroll-turbo_tbmv2.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build26-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "v8.infinite_scroll_tbmv2",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "v8.infinite_scroll_tbmv2",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "v8.infinite_scroll_tbmv2",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "v8.infinite_scroll_tbmv2.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "v8.key_mobile_sites_smooth",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "v8.key_mobile_sites_smooth",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "v8.key_mobile_sites_smooth",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "v8.key_mobile_sites_smooth.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "v8.mobile_infinite_scroll_tbmv2",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "v8.mobile_infinite_scroll_tbmv2",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "v8.mobile_infinite_scroll_tbmv2",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "v8.mobile_infinite_scroll_tbmv2.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "v8.runtime_stats.top_25",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "v8.runtime_stats.top_25",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build24-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "v8.runtime_stats.top_25",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "v8.runtime_stats.top_25.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build24-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "v8.todomvc",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "v8.todomvc",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "v8.todomvc-ignition",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "v8.todomvc-ignition",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "v8.todomvc-ignition",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "v8.todomvc-ignition.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "v8.todomvc-turbo",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "v8.todomvc-turbo",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "v8.todomvc-turbo",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "v8.todomvc-turbo.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "v8.todomvc",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "v8.todomvc.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "v8.top_25_smooth",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "v8.top_25_smooth",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build26-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "v8.top_25_smooth",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "v8.top_25_smooth.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build26-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "webrtc.datachannel",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "webrtc.datachannel",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "webrtc.datachannel",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "webrtc.datachannel.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "webrtc.getusermedia",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "webrtc.getusermedia",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "webrtc.getusermedia",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "webrtc.getusermedia.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "webrtc.peerconnection",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "webrtc.peerconnection",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build26-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "webrtc.peerconnection",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "webrtc.peerconnection.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build26-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "webrtc.stress",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "webrtc.stress",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "webrtc.stress",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "webrtc.stress.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "webrtc.webrtc_smoothness",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "webrtc.webrtc_smoothness",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "webrtc.webrtc_smoothness",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "webrtc.webrtc_smoothness.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build25-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 7200,
+          "io_timeout": 3600
+        }
+      }
+    ]
+  },
   "Mac Pro 10.11 Perf": {
     "isolated_scripts": [
       {
diff --git a/third_party/WebKit/LayoutTests/fast/css-grid-layout/crash-large-positions.html b/third_party/WebKit/LayoutTests/fast/css-grid-layout/crash-large-positions.html
new file mode 100644
index 0000000..b4925165
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css-grid-layout/crash-large-positions.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<title>Test using huge values for grid-column-* and grid-row-*</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="resources/grid-definitions-parsing-utils.js"></script>
+
+<div style="display: grid;">
+    <div id="item" style="grid-column-start: 5000000000; grid-column-end: -5000000000; grid-row-start: 5000000000; grid-row-end: -5000000000;"></div>
+</div>
+
+<script>
+ test(function() {
+     testGridPositionDefinitionsValues(document.getElementById("item"), "1000", "-1000", "1000", "-1000");
+ }, "Test that setting and getting grid-column|row-start|end to huge values is properly clamped and does not make the renderer crash.");
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/css-grid-layout/resources/grid-definitions-parsing-utils.js b/third_party/WebKit/LayoutTests/fast/css-grid-layout/resources/grid-definitions-parsing-utils.js
index 4273fbe5..0c1b97c4 100644
--- a/third_party/WebKit/LayoutTests/fast/css-grid-layout/resources/grid-definitions-parsing-utils.js
+++ b/third_party/WebKit/LayoutTests/fast/css-grid-layout/resources/grid-definitions-parsing-utils.js
@@ -77,3 +77,21 @@
     shouldBeEqualToString("window.getComputedStyle(" + element + ", '').getPropertyValue('grid-row-gap')", computedRowGap);
     shouldBeEqualToString("window.getComputedStyle(" + element + ", '').getPropertyValue('grid-column-gap')", computedColumnGap);
 }
+
+function testGridPositionDefinitionsValues(
+    element, computedRowStart, computedRowEnd, computedColumnStart,
+    computedColumnEnd) {
+  assert_equals(
+      window.getComputedStyle(element, '').getPropertyValue('grid-row-start'),
+      computedRowStart, 'row-start');
+  assert_equals(
+      window.getComputedStyle(element, '').getPropertyValue('grid-row-end'),
+      computedRowEnd, 'row-end');
+  assert_equals(
+      window.getComputedStyle(element, '')
+          .getPropertyValue('grid-column-start'),
+      computedColumnStart, 'column-start');
+  assert_equals(
+      window.getComputedStyle(element, '').getPropertyValue('grid-column-end'),
+      computedColumnEnd, 'column-end');
+}
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/frameNavigation/sandbox-DENIED-top-navigation-without-user-gesture-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/frameNavigation/sandbox-DENIED-top-navigation-without-user-gesture-expected.txt
index 530cfaad..4c0508c 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/frameNavigation/sandbox-DENIED-top-navigation-without-user-gesture-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/security/frameNavigation/sandbox-DENIED-top-navigation-without-user-gesture-expected.txt
@@ -1,5 +1,3 @@
-CONSOLE ERROR: line 8: Unsafe JavaScript attempt to initiate navigation for frame with URL 'http://127.0.0.1:8000/security/frameNavigation/sandbox-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-failed.html'. The frame attempting navigation of the top-level window is sandboxed with the 'allow-top-navigation-with-user-activation' flag, but has no user activation (aka gesture). See https://www.chromestatus.com/feature/5629582019395584.
-
 This tests that an iframe in sandbox with 'allow-top-navigation-with-user-activation' cannot navigate its top level page, if it is not trigged by a user gesture.
 
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/frameNavigation/sandbox-DENIED-top-navigation-without-user-gesture.html b/third_party/WebKit/LayoutTests/http/tests/security/frameNavigation/sandbox-DENIED-top-navigation-without-user-gesture.html
index 071fdc71..44035a2 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/frameNavigation/sandbox-DENIED-top-navigation-without-user-gesture.html
+++ b/third_party/WebKit/LayoutTests/http/tests/security/frameNavigation/sandbox-DENIED-top-navigation-without-user-gesture.html
@@ -4,7 +4,7 @@
 if (window.testRunner) {
     testRunner.dumpAsText();
     testRunner.dumpChildFramesAsText();
-    testRunner.setDumpConsoleMessages(true);
+    testRunner.setDumpConsoleMessages(false);
     testRunner.waitUntilDone();
 }
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioNode/audionode-connect-method-chaining-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioNode/audionode-connect-method-chaining-expected.txt
index 03be975..50688c0a 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioNode/audionode-connect-method-chaining-expected.txt
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioNode/audionode-connect-method-chaining-expected.txt
@@ -55,7 +55,7 @@
 PASS The return value of MediaStreamAudioSourceNode.connect(BiquadFilterNode, 0) matches the destination BiquadFilterNode.
 PASS The return value of MediaStreamAudioSourceNode.connect(ChannelMergerNode, 0, 1) matches the destination ChannelMergerNode.
 PASS Connecting with an invalid output threw IndexSizeError: Failed to execute 'connect' on 'AudioNode': output index (1) exceeds number of outputs (1)..
-PASS Connecting to a node from the different context threw SyntaxError: Failed to execute 'connect' on 'AudioNode': cannot connect to a destination belonging to a different audio context..
+PASS Connecting to a node from the different context threw InvalidAccessError: Failed to execute 'connect' on 'AudioNode': cannot connect to a destination belonging to a different audio context..
 PASS The output of chained connection of gain nodes contains only the constant 0.125.
 PASS successfullyParsed is true
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioNode/audionode-connect-method-chaining.html b/third_party/WebKit/LayoutTests/webaudio/AudioNode/audionode-connect-method-chaining.html
index 5b27e30..b555bfd9 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioNode/audionode-connect-method-chaining.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioNode/audionode-connect-method-chaining.html
@@ -125,7 +125,7 @@
       // first connection succeeds but the second one should throw.
       Should('Connecting to a node from the different context', function () {
         gain1.connect(gain2).connect(contextB.destination);
-      }).throw('SyntaxError');
+      }).throw('InvalidAccessError');
 
       done();
     });
diff --git a/third_party/WebKit/LayoutTests/webaudio/dom-exceptions-expected.txt b/third_party/WebKit/LayoutTests/webaudio/dom-exceptions-expected.txt
index 0924a86..87c61261 100644
--- a/third_party/WebKit/LayoutTests/webaudio/dom-exceptions-expected.txt
+++ b/third_party/WebKit/LayoutTests/webaudio/dom-exceptions-expected.txt
@@ -64,7 +64,7 @@
 PASS node.connect(context.destination, 0, 100) threw exception IndexSizeError: Failed to execute 'connect' on 'AudioNode': input index (100) exceeds number of inputs (1)..
 PASS node.connect(node2.gain, 100) threw exception IndexSizeError: Failed to execute 'connect' on 'AudioNode': output index (100) exceeds number of outputs (1)..
 PASS node.disconnect(99) threw exception IndexSizeError: Failed to execute 'disconnect' on 'AudioNode': The output index provided (99) is outside the range [0, 0]..
-PASS node.connect(otherContext.destination) threw exception SyntaxError: Failed to execute 'connect' on 'AudioNode': cannot connect to a destination belonging to a different audio context..
+PASS node.connect(otherContext.destination) threw exception InvalidAccessError: Failed to execute 'connect' on 'AudioNode': cannot connect to a destination belonging to a different audio context..
 PASS node.channelCount = 99 threw exception NotSupportedError: Failed to set the 'channelCount' property on 'AudioNode': The channel count provided (99) is outside the range [1, 32]..
 PASS node.channelCount is not 99
 PASS node.channelCountMode = 'fancy' did not throw exception.
diff --git a/third_party/WebKit/Source/core/css/BUILD.gn b/third_party/WebKit/Source/core/css/BUILD.gn
index 9bc7288..a9be2f2 100644
--- a/third_party/WebKit/Source/core/css/BUILD.gn
+++ b/third_party/WebKit/Source/core/css/BUILD.gn
@@ -356,6 +356,7 @@
     "properties/CSSPropertyAPIFontVariantCaps.cpp",
     "properties/CSSPropertyAPIFontVariantLigatures.cpp",
     "properties/CSSPropertyAPIFontVariationSettings.cpp",
+    "properties/CSSPropertyAPIGridAutoFlow.cpp",
     "properties/CSSPropertyAPILetterAndWordSpacing.cpp",
     "properties/CSSPropertyAPIOffsetPosition.cpp",
     "properties/CSSPropertyAPIOutlineColor.cpp",
@@ -365,6 +366,7 @@
     "properties/CSSPropertyAPIPaintStroke.cpp",
     "properties/CSSPropertyAPIQuotes.cpp",
     "properties/CSSPropertyAPIRotate.cpp",
+    "properties/CSSPropertyAPIScale.cpp",
     "properties/CSSPropertyAPIScrollSnapCoordinate.cpp",
     "properties/CSSPropertyAPIShapeMargin.cpp",
     "properties/CSSPropertyAPISize.cpp",
diff --git a/third_party/WebKit/Source/core/css/CSSProperties.in b/third_party/WebKit/Source/core/css/CSSProperties.in
index e60f292..aca95d02 100644
--- a/third_party/WebKit/Source/core/css/CSSProperties.in
+++ b/third_party/WebKit/Source/core/css/CSSProperties.in
@@ -270,7 +270,7 @@
 flood-color interpolable, svg, converter=convertColor
 flood-opacity interpolable, svg, converter=convertNumberOrPercentage
 grid-auto-columns runtime_flag=CSSGridLayout, converter=convertGridTrackSizeList
-grid-auto-flow runtime_flag=CSSGridLayout, converter=convertGridAutoFlow, type_name=GridAutoFlow
+grid-auto-flow runtime_flag=CSSGridLayout, converter=convertGridAutoFlow, type_name=GridAutoFlow, api_class
 grid-auto-rows runtime_flag=CSSGridLayout, converter=convertGridTrackSizeList
 grid-column-end runtime_flag=CSSGridLayout, converter=convertGridPosition
 grid-column-gap runtime_flag=CSSGridLayout, converter=convertLength
@@ -397,7 +397,7 @@
 transform-style name_for_methods=TransformStyle3D
 translate runtime_flag=CSSIndependentTransformProperties, converter=convertTranslate, interpolable, api_class
 rotate runtime_flag=CSSIndependentTransformProperties, converter=convertRotate, interpolable, api_class
-scale runtime_flag=CSSIndependentTransformProperties, converter=convertScale, interpolable
+scale runtime_flag=CSSIndependentTransformProperties, converter=convertScale, interpolable, api_class
 unicode-bidi type_name=UnicodeBidi, keyword_only, keywords=[normal|embed|bidi-override|isolate|plaintext|isolate-override], initial_keyword=normal, field_storage_type=platform/text/UnicodeBidi
 vector-effect svg
 vertical-align interpolable, custom_inherit, custom_value, api_class
diff --git a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
index 84588d20..a3a7a79 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
+++ b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
@@ -531,29 +531,6 @@
   return consumeLengthOrPercent(range, cssParserMode, ValueRangeNonNegative);
 }
 
-static CSSValue* consumeScale(CSSParserTokenRange& range) {
-  ASSERT(RuntimeEnabledFeatures::cssIndependentTransformPropertiesEnabled());
-
-  CSSValueID id = range.peek().id();
-  if (id == CSSValueNone)
-    return consumeIdent(range);
-
-  CSSValue* scale = consumeNumber(range, ValueRangeAll);
-  if (!scale)
-    return nullptr;
-  CSSValueList* list = CSSValueList::createSpaceSeparated();
-  list->append(*scale);
-  scale = consumeNumber(range, ValueRangeAll);
-  if (scale) {
-    list->append(*scale);
-    scale = consumeNumber(range, ValueRangeAll);
-    if (scale)
-      list->append(*scale);
-  }
-
-  return list;
-}
-
 static CSSValue* consumeCounter(CSSParserTokenRange& range, int defaultValue) {
   if (range.peek().id() == CSSValueNone)
     return consumeIdent(range);
@@ -2048,23 +2025,6 @@
                               CSSValuePair::KeepIdenticalValues);
 }
 
-static CSSValueList* consumeGridAutoFlow(CSSParserTokenRange& range) {
-  CSSIdentifierValue* rowOrColumnValue =
-      consumeIdent<CSSValueRow, CSSValueColumn>(range);
-  CSSIdentifierValue* denseAlgorithm = consumeIdent<CSSValueDense>(range);
-  if (!rowOrColumnValue) {
-    rowOrColumnValue = consumeIdent<CSSValueRow, CSSValueColumn>(range);
-    if (!rowOrColumnValue && !denseAlgorithm)
-      return nullptr;
-  }
-  CSSValueList* parsedValues = CSSValueList::createSpaceSeparated();
-  if (rowOrColumnValue)
-    parsedValues->append(*rowOrColumnValue);
-  if (denseAlgorithm)
-    parsedValues->append(*denseAlgorithm);
-  return parsedValues;
-}
-
 static CSSValue* consumeBackgroundComponent(CSSPropertyID unresolvedProperty,
                                             CSSParserTokenRange& range,
                                             const CSSParserContext* context) {
@@ -2655,8 +2615,6 @@
       return consumeFontSize(m_range, m_context->mode(), UnitlessQuirk::Allow);
     case CSSPropertyLineHeight:
       return consumeLineHeight(m_range, m_context->mode());
-    case CSSPropertyScale:
-      return consumeScale(m_range);
     case CSSPropertyWebkitBorderHorizontalSpacing:
     case CSSPropertyWebkitBorderVerticalSpacing:
       return consumeLength(m_range, m_context->mode(), ValueRangeNonNegative);
@@ -2960,9 +2918,6 @@
     case CSSPropertyGridTemplateAreas:
       ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
       return consumeGridTemplateAreas(m_range);
-    case CSSPropertyGridAutoFlow:
-      ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
-      return consumeGridAutoFlow(m_range);
     default:
       return nullptr;
   }
diff --git a/third_party/WebKit/Source/core/css/parser/CSSPropertyParserTest.cpp b/third_party/WebKit/Source/core/css/parser/CSSPropertyParserTest.cpp
index e485e30..c5eb170b 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSPropertyParserTest.cpp
+++ b/third_party/WebKit/Source/core/css/parser/CSSPropertyParserTest.cpp
@@ -22,18 +22,18 @@
 
 TEST(CSSPropertyParserTest, GridTrackLimit1) {
   const CSSValue* value = CSSParser::parseSingleValue(
-      CSSPropertyGridTemplateColumns, "repeat(999999, 20px)");
+      CSSPropertyGridTemplateColumns, "repeat(999, 20px)");
   ASSERT_TRUE(value);
   ASSERT_TRUE(value->isValueList());
-  EXPECT_EQ(computeNumberOfTracks(toCSSValueList(value)), 999999);
+  EXPECT_EQ(computeNumberOfTracks(toCSSValueList(value)), 999);
 }
 
 TEST(CSSPropertyParserTest, GridTrackLimit2) {
   const CSSValue* value = CSSParser::parseSingleValue(
-      CSSPropertyGridTemplateRows, "repeat(999999, 20px)");
+      CSSPropertyGridTemplateRows, "repeat(999, 20px)");
   ASSERT_TRUE(value);
   ASSERT_TRUE(value->isValueList());
-  EXPECT_EQ(computeNumberOfTracks(toCSSValueList(value)), 999999);
+  EXPECT_EQ(computeNumberOfTracks(toCSSValueList(value)), 999);
 }
 
 TEST(CSSPropertyParserTest, GridTrackLimit3) {
@@ -41,7 +41,7 @@
       CSSPropertyGridTemplateColumns, "repeat(1000000, 10%)");
   ASSERT_TRUE(value);
   ASSERT_TRUE(value->isValueList());
-  EXPECT_EQ(computeNumberOfTracks(toCSSValueList(value)), 1000000);
+  EXPECT_EQ(computeNumberOfTracks(toCSSValueList(value)), 1000);
 }
 
 TEST(CSSPropertyParserTest, GridTrackLimit4) {
@@ -49,7 +49,7 @@
       CSSPropertyGridTemplateRows, "repeat(1000000, 10%)");
   ASSERT_TRUE(value);
   ASSERT_TRUE(value->isValueList());
-  EXPECT_EQ(computeNumberOfTracks(toCSSValueList(value)), 1000000);
+  EXPECT_EQ(computeNumberOfTracks(toCSSValueList(value)), 1000);
 }
 
 TEST(CSSPropertyParserTest, GridTrackLimit5) {
@@ -58,7 +58,7 @@
       "repeat(1000000, [first] min-content [last])");
   ASSERT_TRUE(value);
   ASSERT_TRUE(value->isValueList());
-  EXPECT_EQ(computeNumberOfTracks(toCSSValueList(value)), 1000000);
+  EXPECT_EQ(computeNumberOfTracks(toCSSValueList(value)), 1000);
 }
 
 TEST(CSSPropertyParserTest, GridTrackLimit6) {
@@ -67,7 +67,7 @@
       "repeat(1000000, [first] min-content [last])");
   ASSERT_TRUE(value);
   ASSERT_TRUE(value->isValueList());
-  EXPECT_EQ(computeNumberOfTracks(toCSSValueList(value)), 1000000);
+  EXPECT_EQ(computeNumberOfTracks(toCSSValueList(value)), 1000);
 }
 
 TEST(CSSPropertyParserTest, GridTrackLimit7) {
@@ -75,7 +75,7 @@
       CSSPropertyGridTemplateColumns, "repeat(1000001, auto)");
   ASSERT_TRUE(value);
   ASSERT_TRUE(value->isValueList());
-  EXPECT_EQ(computeNumberOfTracks(toCSSValueList(value)), 1000000);
+  EXPECT_EQ(computeNumberOfTracks(toCSSValueList(value)), 1000);
 }
 
 TEST(CSSPropertyParserTest, GridTrackLimit8) {
@@ -83,7 +83,7 @@
       CSSPropertyGridTemplateRows, "repeat(1000001, auto)");
   ASSERT_TRUE(value);
   ASSERT_TRUE(value->isValueList());
-  EXPECT_EQ(computeNumberOfTracks(toCSSValueList(value)), 1000000);
+  EXPECT_EQ(computeNumberOfTracks(toCSSValueList(value)), 1000);
 }
 
 TEST(CSSPropertyParserTest, GridTrackLimit9) {
@@ -92,7 +92,7 @@
       "repeat(400000, 2em minmax(10px, max-content) 0.5fr)");
   ASSERT_TRUE(value);
   ASSERT_TRUE(value->isValueList());
-  EXPECT_EQ(computeNumberOfTracks(toCSSValueList(value)), 999999);
+  EXPECT_EQ(computeNumberOfTracks(toCSSValueList(value)), 999);
 }
 
 TEST(CSSPropertyParserTest, GridTrackLimit10) {
@@ -101,7 +101,7 @@
       "repeat(400000, 2em minmax(10px, max-content) 0.5fr)");
   ASSERT_TRUE(value);
   ASSERT_TRUE(value->isValueList());
-  EXPECT_EQ(computeNumberOfTracks(toCSSValueList(value)), 999999);
+  EXPECT_EQ(computeNumberOfTracks(toCSSValueList(value)), 999);
 }
 
 TEST(CSSPropertyParserTest, GridTrackLimit11) {
@@ -110,7 +110,7 @@
       "repeat(600000, [first] 3vh 10% 2fr [nav] 10px auto 1fr 6em [last])");
   ASSERT_TRUE(value);
   ASSERT_TRUE(value->isValueList());
-  EXPECT_EQ(computeNumberOfTracks(toCSSValueList(value)), 999999);
+  EXPECT_EQ(computeNumberOfTracks(toCSSValueList(value)), 994);
 }
 
 TEST(CSSPropertyParserTest, GridTrackLimit12) {
@@ -119,7 +119,7 @@
       "repeat(600000, [first] 3vh 10% 2fr [nav] 10px auto 1fr 6em [last])");
   ASSERT_TRUE(value);
   ASSERT_TRUE(value->isValueList());
-  EXPECT_EQ(computeNumberOfTracks(toCSSValueList(value)), 999999);
+  EXPECT_EQ(computeNumberOfTracks(toCSSValueList(value)), 994);
 }
 
 TEST(CSSPropertyParserTest, GridTrackLimit13) {
@@ -127,7 +127,7 @@
       CSSPropertyGridTemplateColumns, "repeat(100000000000000000000, 10% 1fr)");
   ASSERT_TRUE(value);
   ASSERT_TRUE(value->isValueList());
-  EXPECT_EQ(computeNumberOfTracks(toCSSValueList(value)), 1000000);
+  EXPECT_EQ(computeNumberOfTracks(toCSSValueList(value)), 1000);
 }
 
 TEST(CSSPropertyParserTest, GridTrackLimit14) {
@@ -135,7 +135,7 @@
       CSSPropertyGridTemplateRows, "repeat(100000000000000000000, 10% 1fr)");
   ASSERT_TRUE(value);
   ASSERT_TRUE(value->isValueList());
-  EXPECT_EQ(computeNumberOfTracks(toCSSValueList(value)), 1000000);
+  EXPECT_EQ(computeNumberOfTracks(toCSSValueList(value)), 1000);
 }
 
 TEST(CSSPropertyParserTest, GridTrackLimit15) {
@@ -144,7 +144,7 @@
       "repeat(100000000000000000000, 10% 5em 1fr auto auto 15px min-content)");
   ASSERT_TRUE(value);
   ASSERT_TRUE(value->isValueList());
-  EXPECT_EQ(computeNumberOfTracks(toCSSValueList(value)), 999999);
+  EXPECT_EQ(computeNumberOfTracks(toCSSValueList(value)), 994);
 }
 
 TEST(CSSPropertyParserTest, GridTrackLimit16) {
@@ -153,7 +153,7 @@
       "repeat(100000000000000000000, 10% 5em 1fr auto auto 15px min-content)");
   ASSERT_TRUE(value);
   ASSERT_TRUE(value->isValueList());
-  EXPECT_EQ(computeNumberOfTracks(toCSSValueList(value)), 999999);
+  EXPECT_EQ(computeNumberOfTracks(toCSSValueList(value)), 994);
 }
 
 static int getGridPositionInteger(const CSSValue& value) {
@@ -167,58 +167,58 @@
 
 TEST(CSSPropertyParserTest, GridPositionLimit1) {
   const CSSValue* value =
-      CSSParser::parseSingleValue(CSSPropertyGridColumnStart, "999999");
+      CSSParser::parseSingleValue(CSSPropertyGridColumnStart, "999");
   DCHECK(value);
-  EXPECT_EQ(getGridPositionInteger(*value), 999999);
+  EXPECT_EQ(getGridPositionInteger(*value), 999);
 }
 
 TEST(CSSPropertyParserTest, GridPositionLimit2) {
   const CSSValue* value =
       CSSParser::parseSingleValue(CSSPropertyGridColumnEnd, "1000000");
   DCHECK(value);
-  EXPECT_EQ(getGridPositionInteger(*value), 1000000);
+  EXPECT_EQ(getGridPositionInteger(*value), 1000);
 }
 
 TEST(CSSPropertyParserTest, GridPositionLimit3) {
   const CSSValue* value =
       CSSParser::parseSingleValue(CSSPropertyGridRowStart, "1000001");
   DCHECK(value);
-  EXPECT_EQ(getGridPositionInteger(*value), 1000000);
+  EXPECT_EQ(getGridPositionInteger(*value), 1000);
 }
 
 TEST(CSSPropertyParserTest, GridPositionLimit4) {
   const CSSValue* value =
       CSSParser::parseSingleValue(CSSPropertyGridRowEnd, "5000000000");
   DCHECK(value);
-  EXPECT_EQ(getGridPositionInteger(*value), 1000000);
+  EXPECT_EQ(getGridPositionInteger(*value), 1000);
 }
 
 TEST(CSSPropertyParserTest, GridPositionLimit5) {
   const CSSValue* value =
-      CSSParser::parseSingleValue(CSSPropertyGridColumnStart, "-999999");
+      CSSParser::parseSingleValue(CSSPropertyGridColumnStart, "-999");
   DCHECK(value);
-  EXPECT_EQ(getGridPositionInteger(*value), -999999);
+  EXPECT_EQ(getGridPositionInteger(*value), -999);
 }
 
 TEST(CSSPropertyParserTest, GridPositionLimit6) {
   const CSSValue* value =
       CSSParser::parseSingleValue(CSSPropertyGridColumnEnd, "-1000000");
   DCHECK(value);
-  EXPECT_EQ(getGridPositionInteger(*value), -1000000);
+  EXPECT_EQ(getGridPositionInteger(*value), -1000);
 }
 
 TEST(CSSPropertyParserTest, GridPositionLimit7) {
   const CSSValue* value =
       CSSParser::parseSingleValue(CSSPropertyGridRowStart, "-1000001");
   DCHECK(value);
-  EXPECT_EQ(getGridPositionInteger(*value), -1000000);
+  EXPECT_EQ(getGridPositionInteger(*value), -1000);
 }
 
 TEST(CSSPropertyParserTest, GridPositionLimit8) {
   const CSSValue* value =
       CSSParser::parseSingleValue(CSSPropertyGridRowEnd, "-5000000000");
   DCHECK(value);
-  EXPECT_EQ(getGridPositionInteger(*value), -1000000);
+  EXPECT_EQ(getGridPositionInteger(*value), -1000);
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIGridAutoFlow.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIGridAutoFlow.cpp
new file mode 100644
index 0000000..af14523
--- /dev/null
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIGridAutoFlow.cpp
@@ -0,0 +1,38 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "core/css/properties/CSSPropertyAPIGridAutoFlow.h"
+
+#include "core/css/CSSIdentifierValue.h"
+#include "core/css/CSSValueList.h"
+#include "core/css/parser/CSSPropertyParserHelpers.h"
+#include "platform/RuntimeEnabledFeatures.h"
+
+namespace blink {
+
+const CSSValue* CSSPropertyAPIGridAutoFlow::parseSingleValue(
+    CSSParserTokenRange& range,
+    const CSSParserContext* context) {
+  DCHECK(RuntimeEnabledFeatures::cssGridLayoutEnabled());
+  CSSIdentifierValue* rowOrColumnValue =
+      CSSPropertyParserHelpers::consumeIdent<CSSValueRow, CSSValueColumn>(
+          range);
+  CSSIdentifierValue* denseAlgorithm =
+      CSSPropertyParserHelpers::consumeIdent<CSSValueDense>(range);
+  if (!rowOrColumnValue) {
+    rowOrColumnValue =
+        CSSPropertyParserHelpers::consumeIdent<CSSValueRow, CSSValueColumn>(
+            range);
+    if (!rowOrColumnValue && !denseAlgorithm)
+      return nullptr;
+  }
+  CSSValueList* parsedValues = CSSValueList::createSpaceSeparated();
+  if (rowOrColumnValue)
+    parsedValues->append(*rowOrColumnValue);
+  if (denseAlgorithm)
+    parsedValues->append(*denseAlgorithm);
+  return parsedValues;
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIScale.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIScale.cpp
new file mode 100644
index 0000000..7ee7f66
--- /dev/null
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIScale.cpp
@@ -0,0 +1,39 @@
+// 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 "core/css/properties/CSSPropertyAPIScale.h"
+
+#include "core/css/CSSValueList.h"
+#include "core/css/parser/CSSPropertyParserHelpers.h"
+#include "platform/RuntimeEnabledFeatures.h"
+
+namespace blink {
+
+const CSSValue* CSSPropertyAPIScale::parseSingleValue(
+    CSSParserTokenRange& range,
+    const CSSParserContext* context) {
+  DCHECK(RuntimeEnabledFeatures::cssIndependentTransformPropertiesEnabled());
+
+  CSSValueID id = range.peek().id();
+  if (id == CSSValueNone)
+    return CSSPropertyParserHelpers::consumeIdent(range);
+
+  CSSValue* scale =
+      CSSPropertyParserHelpers::consumeNumber(range, ValueRangeAll);
+  if (!scale)
+    return nullptr;
+  CSSValueList* list = CSSValueList::createSpaceSeparated();
+  list->append(*scale);
+  scale = CSSPropertyParserHelpers::consumeNumber(range, ValueRangeAll);
+  if (scale) {
+    list->append(*scale);
+    scale = CSSPropertyParserHelpers::consumeNumber(range, ValueRangeAll);
+    if (scale)
+      list->append(*scale);
+  }
+
+  return list;
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/core/frame/FrameView.cpp b/third_party/WebKit/Source/core/frame/FrameView.cpp
index 440e4e3..e9af56f 100644
--- a/third_party/WebKit/Source/core/frame/FrameView.cpp
+++ b/third_party/WebKit/Source/core/frame/FrameView.cpp
@@ -1354,37 +1354,32 @@
 FloatSize FrameView::viewportSizeForViewportUnits() const {
   float zoom = frame().pageZoomFactor();
 
-  if (m_frame->settings() &&
-      !RuntimeEnabledFeatures::inertTopControlsEnabled()) {
-    FloatSize viewportSize;
+  FloatSize layoutSize;
 
-    LayoutViewItem layoutViewItem = this->layoutViewItem();
-    if (layoutViewItem.isNull())
-      return viewportSize;
+  LayoutViewItem layoutViewItem = this->layoutViewItem();
+  if (layoutViewItem.isNull())
+    return layoutSize;
 
-    viewportSize.setWidth(layoutViewItem.viewWidth(IncludeScrollbars) / zoom);
-    viewportSize.setHeight(layoutViewItem.viewHeight(IncludeScrollbars) / zoom);
-    return viewportSize;
+  layoutSize.setWidth(layoutViewItem.viewWidth(IncludeScrollbars) / zoom);
+  layoutSize.setHeight(layoutViewItem.viewHeight(IncludeScrollbars) / zoom);
+
+  if (RuntimeEnabledFeatures::inertTopControlsEnabled()) {
+    // We use the layoutSize rather than frameRect to calculate viewport units
+    // so that we get correct results on mobile where the page is laid out into
+    // a rect that may be larger than the viewport (e.g. the 980px fallback
+    // width for desktop pages). Since the layout height is statically set to
+    // be the viewport with browser controls showing, we add the browser
+    // controls height, compensating for page scale as well, since we want to
+    // use the viewport with browser controls hidden for vh (to match Safari).
+    BrowserControls& browserControls = m_frame->host()->browserControls();
+    int viewportWidth = m_frame->host()->visualViewport().size().width();
+    if (m_frame->isMainFrame() && layoutSize.width() && viewportWidth) {
+      float pageScaleAtLayoutWidth = viewportWidth / layoutSize.width();
+      layoutSize.expand(0, browserControls.height() / pageScaleAtLayoutWidth);
+    }
   }
 
-  FloatSize size(layoutSize(IncludeScrollbars));
-
-  // We use the layoutSize rather than frameRect to calculate viewport units
-  // so that we get correct results on mobile where the page is laid out into
-  // a rect that may be larger than the viewport (e.g. the 980px fallback
-  // width for desktop pages). Since the layout height is statically set to
-  // be the viewport with browser controls showing, we add the browser controls
-  // height, compensating for page scale as well, since we want to use the
-  // viewport with browser controls hidden for vh (to match Safari).
-  BrowserControls& browserControls = m_frame->host()->browserControls();
-  int viewportWidth = m_frame->host()->visualViewport().size().width();
-  if (m_frame->isMainFrame() && size.width() && viewportWidth) {
-    float pageScaleAtLayoutWidth = viewportWidth / size.width();
-    size.expand(0, browserControls.height() / pageScaleAtLayoutWidth);
-  }
-
-  size.scale(1 / zoom);
-  return size;
+  return layoutSize;
 }
 
 DocumentLifecycle& FrameView::lifecycle() const {
diff --git a/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp b/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp
index 68d1351..363c577f 100644
--- a/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp
@@ -832,27 +832,27 @@
   }
 
   // Do not use acceleration for small canvas.
-  if (criteria != IgnoreCanvasSizeAccelerationCriteria) {
+  if (criteria != IgnoreResourceLimitCriteria) {
     Settings* settings = document().settings();
     if (!settings ||
         canvasPixelCount < settings->getMinimumAccelerated2dCanvasSize())
       return false;
+
+    // When GPU allocated memory runs low (due to having created too many
+    // accelerated canvases), the compositor starves and browser becomes laggy.
+    // Thus, we should stop allocating more GPU memory to new canvases created
+    // when the current memory usage exceeds the threshold.
+    if (ImageBuffer::getGlobalGPUMemoryUsage() >= MaxGlobalGPUMemoryUsage)
+      return false;
+
+    // Allocating too many GPU resources can makes us run into the driver's
+    // resource limits. So we need to keep the number of texture resources
+    // under tight control
+    if (ImageBuffer::getGlobalAcceleratedImageBufferCount() >=
+        MaxGlobalAcceleratedImageBufferCount)
+      return false;
   }
 
-  // When GPU allocated memory runs low (due to having created too many
-  // accelerated canvases), the compositor starves and browser becomes laggy.
-  // Thus, we should stop allocating more GPU memory to new canvases created
-  // when the current memory usage exceeds the threshold.
-  if (ImageBuffer::getGlobalGPUMemoryUsage() >= MaxGlobalGPUMemoryUsage)
-    return false;
-
-  // Allocating too many GPU resources can makes us run into the driver's
-  // resource limits. So we need to keep the number of texture resources
-  // under tight control
-  if (ImageBuffer::getGlobalAcceleratedImageBufferCount() >=
-      MaxGlobalAcceleratedImageBufferCount)
-    return false;
-
   return true;
 }
 
@@ -1213,7 +1213,7 @@
 void HTMLCanvasElement::willDrawImageTo2DContext(CanvasImageSource* source) {
   if (ExpensiveCanvasHeuristicParameters::EnableAccelerationToAvoidReadbacks &&
       source->isAccelerated() && !buffer()->isAccelerated() &&
-      shouldAccelerate(IgnoreCanvasSizeAccelerationCriteria)) {
+      shouldAccelerate(IgnoreResourceLimitCriteria)) {
     OpacityMode opacityMode =
         m_context->creationAttributes().alpha() ? NonOpaque : Opaque;
     int msaaSampleCount = 0;
diff --git a/third_party/WebKit/Source/core/html/HTMLCanvasElement.h b/third_party/WebKit/Source/core/html/HTMLCanvasElement.h
index 4025122..f7a7ff5d 100644
--- a/third_party/WebKit/Source/core/html/HTMLCanvasElement.h
+++ b/third_party/WebKit/Source/core/html/HTMLCanvasElement.h
@@ -254,7 +254,7 @@
 
   enum AccelerationCriteria {
     NormalAccelerationCriteria,
-    IgnoreCanvasSizeAccelerationCriteria,
+    IgnoreResourceLimitCriteria,
   };
   bool shouldAccelerate(AccelerationCriteria) const;
 
diff --git a/third_party/WebKit/Source/core/html/HTMLLinkElement.cpp b/third_party/WebKit/Source/core/html/HTMLLinkElement.cpp
index 0895da43..d564e57 100644
--- a/third_party/WebKit/Source/core/html/HTMLLinkElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLLinkElement.cpp
@@ -289,9 +289,7 @@
 }
 
 void HTMLLinkElement::scheduleEvent() {
-  // TODO(hiroshige): Use DOMManipulation task runner. Unthrottled
-  // is temporarily used for fixing https://crbug.com/649942 only on M-56.
-  TaskRunnerHelper::get(TaskType::Unthrottled, &document())
+  TaskRunnerHelper::get(TaskType::DOMManipulation, &document())
       ->postTask(
           BLINK_FROM_HERE,
           WTF::bind(
diff --git a/third_party/WebKit/Source/core/html/HTMLStyleElement.cpp b/third_party/WebKit/Source/core/html/HTMLStyleElement.cpp
index 2dfd1d4..8b7d3d5 100644
--- a/third_party/WebKit/Source/core/html/HTMLStyleElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLStyleElement.cpp
@@ -117,9 +117,7 @@
   if (m_firedLoad && isLoadEvent)
     return;
   m_loadedSheet = isLoadEvent;
-  // TODO(hiroshige): Use DOMManipulation task runner. Unthrottled
-  // is temporarily used for fixing https://crbug.com/649942 only on M-56.
-  TaskRunnerHelper::get(TaskType::Unthrottled, &document())
+  TaskRunnerHelper::get(TaskType::DOMManipulation, &document())
       ->postTask(
           BLINK_FROM_HERE,
           WTF::bind(
diff --git a/third_party/WebKit/Source/core/html/ImageDocument.cpp b/third_party/WebKit/Source/core/html/ImageDocument.cpp
index 5a716aa9..06ee1ef 100644
--- a/third_party/WebKit/Source/core/html/ImageDocument.cpp
+++ b/third_party/WebKit/Source/core/html/ImageDocument.cpp
@@ -48,6 +48,7 @@
 #include "core/loader/FrameLoader.h"
 #include "core/loader/FrameLoaderClient.h"
 #include "core/loader/resource/ImageResource.h"
+#include "core/page/Page.h"
 #include "platform/HostWindow.h"
 #include "wtf/text/StringBuilder.h"
 #include <limits>
@@ -594,7 +595,12 @@
 }
 
 bool ImageDocument::shouldShrinkToFit() const {
-  return frame()->isMainFrame();
+  // WebView automatically resizes to match the contents, causing an infinite
+  // loop as the contents then resize to match the window. To prevent this,
+  // disallow images from shrinking to fit for WebViews.
+  bool isWrapContentWebView =
+      page() ? page()->settings().getForceZeroLayoutHeight() : false;
+  return frame()->isMainFrame() && !isWrapContentWebView;
 }
 
 DEFINE_TRACE(ImageDocument) {
diff --git a/third_party/WebKit/Source/core/html/ImageDocument.h b/third_party/WebKit/Source/core/html/ImageDocument.h
index c391bdc..8a1575ec 100644
--- a/third_party/WebKit/Source/core/html/ImageDocument.h
+++ b/third_party/WebKit/Source/core/html/ImageDocument.h
@@ -53,6 +53,7 @@
   void imageClicked(int x, int y);
   void imageLoaded();
   void updateImageStyle();
+  bool shouldShrinkToFit() const;
 
   DECLARE_VIRTUAL_TRACE();
 
@@ -70,7 +71,6 @@
   void resizeImageToFit();
   void restoreImageSize();
   bool imageFitsInWindow() const;
-  bool shouldShrinkToFit() const;
   // Calculates the image size multiplier that's needed to fit the image to
   // the window, taking into account page zoom and device scale.
   float scale() const;
diff --git a/third_party/WebKit/Source/core/html/ImageDocumentTest.cpp b/third_party/WebKit/Source/core/html/ImageDocumentTest.cpp
index 28b344e..e7a752d 100644
--- a/third_party/WebKit/Source/core/html/ImageDocumentTest.cpp
+++ b/third_party/WebKit/Source/core/html/ImageDocumentTest.cpp
@@ -6,6 +6,7 @@
 
 #include "core/dom/Document.h"
 #include "core/dom/DocumentParser.h"
+#include "core/frame/Settings.h"
 #include "core/loader/EmptyClients.h"
 #include "core/testing/DummyPageHolder.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -182,4 +183,26 @@
   EXPECT_EQ(10, imageHeight());
 }
 
+TEST_F(ImageDocumentTest, ImageNotCenteredWithForceZeroLayoutHeight) {
+  createDocumentWithoutLoadingImage(80, 70);
+  document().page()->settings().setForceZeroLayoutHeight(true);
+  loadImage();
+  EXPECT_FALSE(document().shouldShrinkToFit());
+  EXPECT_EQ(0, document().imageElement()->offsetLeft());
+  EXPECT_EQ(0, document().imageElement()->offsetTop());
+  EXPECT_EQ(50, imageWidth());
+  EXPECT_EQ(50, imageHeight());
+}
+
+TEST_F(ImageDocumentTest, ImageCenteredWithoutForceZeroLayoutHeight) {
+  createDocumentWithoutLoadingImage(80, 70);
+  document().page()->settings().setForceZeroLayoutHeight(false);
+  loadImage();
+  EXPECT_TRUE(document().shouldShrinkToFit());
+  EXPECT_EQ(15, document().imageElement()->offsetLeft());
+  EXPECT_EQ(10, document().imageElement()->offsetTop());
+  EXPECT_EQ(50, imageWidth());
+  EXPECT_EQ(50, imageHeight());
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/LayoutGrid.cpp b/third_party/WebKit/Source/core/layout/LayoutGrid.cpp
index 7a9dd5b0..049e1e20 100644
--- a/third_party/WebKit/Source/core/layout/LayoutGrid.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutGrid.cpp
@@ -51,6 +51,8 @@
 
 void LayoutGrid::Grid::ensureGridSize(size_t maximumRowSize,
                                       size_t maximumColumnSize) {
+  DCHECK(maximumRowSize <= kGridMaxTracks * 2);
+  DCHECK(maximumColumnSize <= kGridMaxTracks * 2);
   const size_t oldRowSize = numTracks(ForRows);
   if (maximumRowSize > oldRowSize) {
     m_grid.grow(maximumRowSize);
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc
index c2c7571..238c3b0 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc
@@ -184,7 +184,6 @@
     NGConstraintSpace* constraint_space,
     NGBreakToken* break_token)
     : NGLayoutAlgorithm(kBlockLayoutAlgorithm),
-      layout_state_(kStateInit),
       style_(style),
       first_child_(first_child),
       constraint_space_(constraint_space),
@@ -224,136 +223,113 @@
     NGPhysicalFragment* child_fragment,
     NGPhysicalFragment** fragment_out,
     NGLayoutAlgorithm** algorithm_out) {
-  switch (layout_state_) {
-    case kStateInit: {
-      WTF::Optional<MinAndMaxContentSizes> sizes;
-      if (NeedMinAndMaxContentSizes(ConstraintSpace(), Style())) {
-        sizes = MinAndMaxContentSizes();
-        ComputeMinAndMaxContentSizes(&*sizes);
-      }
+  WTF::Optional<MinAndMaxContentSizes> sizes;
+  if (NeedMinAndMaxContentSizes(ConstraintSpace(), Style())) {
+    // TODO(ikilpatrick): Change ComputeMinAndMaxContentSizes to return
+    // MinAndMaxContentSizes.
+    sizes = MinAndMaxContentSizes();
+    ComputeMinAndMaxContentSizes(&*sizes);
+  }
 
-      border_and_padding_ =
-          ComputeBorders(Style()) + ComputePadding(ConstraintSpace(), Style());
+  border_and_padding_ =
+      ComputeBorders(Style()) + ComputePadding(ConstraintSpace(), Style());
 
-      LayoutUnit inline_size =
-          ComputeInlineSizeForFragment(ConstraintSpace(), Style(), sizes);
-      LayoutUnit adjusted_inline_size =
-          inline_size - border_and_padding_.InlineSum();
-      // TODO(layout-ng): For quirks mode, should we pass blockSize instead of
-      // -1?
-      LayoutUnit block_size = ComputeBlockSizeForFragment(
-          ConstraintSpace(), Style(), NGSizeIndefinite);
-      LayoutUnit adjusted_block_size(block_size);
-      // Our calculated block-axis size may be indefinite at this point.
-      // If so, just leave the size as NGSizeIndefinite instead of subtracting
-      // borders and padding.
-      if (adjusted_block_size != NGSizeIndefinite)
-        adjusted_block_size -= border_and_padding_.BlockSum();
+  LayoutUnit inline_size =
+      ComputeInlineSizeForFragment(ConstraintSpace(), Style(), sizes);
+  LayoutUnit adjusted_inline_size =
+      inline_size - border_and_padding_.InlineSum();
+  // TODO(layout-ng): For quirks mode, should we pass blockSize instead of
+  // -1?
+  LayoutUnit block_size =
+      ComputeBlockSizeForFragment(ConstraintSpace(), Style(), NGSizeIndefinite);
+  LayoutUnit adjusted_block_size(block_size);
+  // Our calculated block-axis size may be indefinite at this point.
+  // If so, just leave the size as NGSizeIndefinite instead of subtracting
+  // borders and padding.
+  if (adjusted_block_size != NGSizeIndefinite)
+    adjusted_block_size -= border_and_padding_.BlockSum();
 
-      space_builder_ = new NGConstraintSpaceBuilder(constraint_space_);
-      if (Style().specifiesColumns()) {
-        space_builder_->SetFragmentationType(kFragmentColumn);
-        adjusted_inline_size =
-            ResolveUsedColumnInlineSize(adjusted_inline_size, Style());
-        LayoutUnit inline_progression =
-            adjusted_inline_size + ResolveUsedColumnGap(Style());
-        fragmentainer_mapper_ =
-            new NGColumnMapper(inline_progression, adjusted_block_size);
-      }
-      space_builder_->SetAvailableSize(
-          NGLogicalSize(adjusted_inline_size, adjusted_block_size));
-      space_builder_->SetPercentageResolutionSize(
-          NGLogicalSize(adjusted_inline_size, adjusted_block_size));
+  space_builder_ = new NGConstraintSpaceBuilder(constraint_space_);
+  if (Style().specifiesColumns()) {
+    space_builder_->SetFragmentationType(kFragmentColumn);
+    adjusted_inline_size =
+        ResolveUsedColumnInlineSize(adjusted_inline_size, Style());
+    LayoutUnit inline_progression =
+        adjusted_inline_size + ResolveUsedColumnGap(Style());
+    fragmentainer_mapper_ =
+        new NGColumnMapper(inline_progression, adjusted_block_size);
+  }
+  space_builder_->SetAvailableSize(
+      NGLogicalSize(adjusted_inline_size, adjusted_block_size));
+  space_builder_->SetPercentageResolutionSize(
+      NGLogicalSize(adjusted_inline_size, adjusted_block_size));
 
-      builder_ = new NGFragmentBuilder(NGPhysicalFragment::kFragmentBox);
-      builder_->SetDirection(constraint_space_->Direction());
-      builder_->SetWritingMode(constraint_space_->WritingMode());
-      builder_->SetInlineSize(inline_size).SetBlockSize(block_size);
+  builder_ = new NGFragmentBuilder(NGPhysicalFragment::kFragmentBox);
+  builder_->SetDirection(constraint_space_->Direction());
+  builder_->SetWritingMode(constraint_space_->WritingMode());
+  builder_->SetInlineSize(inline_size).SetBlockSize(block_size);
 
-      if (NGBlockBreakToken* token = CurrentBlockBreakToken()) {
-        // Resume after a previous break.
-        content_size_ = token->BreakOffset();
-        current_child_ = token->InputNode();
-      } else {
-        content_size_ = border_and_padding_.block_start;
-        current_child_ = first_child_;
-      }
+  if (NGBlockBreakToken* token = CurrentBlockBreakToken()) {
+    // Resume after a previous break.
+    content_size_ = token->BreakOffset();
+    current_child_ = token->InputNode();
+  } else {
+    content_size_ = border_and_padding_.block_start;
+    current_child_ = first_child_;
+  }
 
-      layout_state_ = kStatePrepareForChildLayout;
-      return kNotFinished;
+  while (current_child_) {
+    EPosition position = current_child_->Style()->position();
+    if (position == AbsolutePosition || position == FixedPosition) {
+      builder_->AddOutOfFlowChildCandidate(current_child_,
+                                           GetChildSpaceOffset());
+      current_child_ = current_child_->NextSibling();
+      continue;
     }
-    case kStatePrepareForChildLayout: {
-      if (current_child_) {
-        EPosition position = current_child_->Style()->position();
-        if ((position == AbsolutePosition || position == FixedPosition)) {
-          builder_->AddOutOfFlowChildCandidate(current_child_,
-                                               GetChildSpaceOffset());
-          current_child_ = current_child_->NextSibling();
-          return kNotFinished;
-        }
-        DCHECK(!ConstraintSpace().HasBlockFragmentation() ||
-               SpaceAvailableForCurrentChild() > LayoutUnit());
-        space_for_current_child_ = CreateConstraintSpaceForCurrentChild();
-        *algorithm_out = NGLayoutInputNode::AlgorithmForInputNode(
-            current_child_, space_for_current_child_);
-        layout_state_ = kStateChildLayout;
-        return kChildAlgorithmRequired;
-      }
 
-      // Prepare for kStateOutOfFlowLayout
-      content_size_ += border_and_padding_.block_end;
+    DCHECK(!ConstraintSpace().HasBlockFragmentation() ||
+           SpaceAvailableForCurrentChild() > LayoutUnit());
+    space_for_current_child_ = CreateConstraintSpaceForCurrentChild();
 
-      // Recompute the block-axis size now that we know our content size.
-      LayoutUnit block_size = ComputeBlockSizeForFragment(
-          ConstraintSpace(), Style(), content_size_);
-      builder_->SetBlockSize(block_size);
+    NGFragment* fragment;
+    current_child_->LayoutSync(space_for_current_child_, &fragment);
+    NGPhysicalFragment* child_fragment = fragment->PhysicalFragment();
 
-      // Out of flow setup.
-      out_of_flow_layout_ =
-          new NGOutOfFlowLayoutPart(&Style(), builder_->Size());
-      builder_->GetAndClearOutOfFlowDescendantCandidates(
-          &out_of_flow_candidates_, &out_of_flow_candidate_positions_);
-      out_of_flow_candidate_positions_index_ = 0;
-      current_child_ = nullptr;
-      layout_state_ = kStateOutOfFlowLayout;
-      return kNotFinished;
-    }
-    case kStateChildLayout: {
-      DCHECK(current_child_);
-      DCHECK(child_fragment);
+    // TODO(layout_ng): Seems like a giant hack to call this here.
+    current_child_->UpdateLayoutBox(toNGPhysicalBoxFragment(child_fragment),
+                                    space_for_current_child_);
 
-      // TODO(layout_ng): Seems like a giant hack to call this here.
-      current_child_->UpdateLayoutBox(toNGPhysicalBoxFragment(child_fragment),
-                                      space_for_current_child_);
+    FinishCurrentChildLayout(new NGBoxFragment(
+        ConstraintSpace().WritingMode(), ConstraintSpace().Direction(),
+        toNGPhysicalBoxFragment(child_fragment)));
 
-      FinishCurrentChildLayout(new NGBoxFragment(
-          ConstraintSpace().WritingMode(), ConstraintSpace().Direction(),
-          toNGPhysicalBoxFragment(child_fragment)));
+    if (!ProceedToNextUnfinishedSibling(child_fragment))
+      break;
+  }
 
-      if (ProceedToNextUnfinishedSibling(child_fragment))
-        layout_state_ = kStatePrepareForChildLayout;
-      else
-        layout_state_ = kStateFinalize;
-      return kNotFinished;
-    }
-    case kStateOutOfFlowLayout:
-      if (LayoutOutOfFlowChild())
-        layout_state_ = kStateFinalize;
-      return kNotFinished;
-    case kStateFinalize: {
-      builder_->SetInlineOverflow(max_inline_size_)
-          .SetBlockOverflow(content_size_);
+  content_size_ += border_and_padding_.block_end;
 
-      if (ConstraintSpace().HasBlockFragmentation())
-        FinalizeForFragmentation();
+  // Recompute the block-axis size now that we know our content size.
+  block_size =
+      ComputeBlockSizeForFragment(ConstraintSpace(), Style(), content_size_);
+  builder_->SetBlockSize(block_size);
 
-      *fragment_out = builder_->ToBoxFragment();
-      layout_state_ = kStateInit;
-      return kNewFragment;
-    }
-  };
-  NOTREACHED();
-  *fragment_out = nullptr;
+  // Out of flow setup.
+  out_of_flow_layout_ = new NGOutOfFlowLayoutPart(&Style(), builder_->Size());
+  builder_->GetAndClearOutOfFlowDescendantCandidates(
+      &out_of_flow_candidates_, &out_of_flow_candidate_positions_);
+  out_of_flow_candidate_positions_index_ = 0;
+  current_child_ = nullptr;
+
+  while (!LayoutOutOfFlowChild())
+    continue;
+
+  builder_->SetInlineOverflow(max_inline_size_).SetBlockOverflow(content_size_);
+
+  if (ConstraintSpace().HasBlockFragmentation())
+    FinalizeForFragmentation();
+
+  *fragment_out = builder_->ToBoxFragment();
   return kNewFragment;
 }
 
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.h b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.h
index 17f33e9..78dc3510 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.h
+++ b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.h
@@ -146,15 +146,6 @@
 
   const ComputedStyle& Style() const { return *style_; }
 
-  enum LayoutState {
-    kStateInit,
-    kStatePrepareForChildLayout,
-    kStateChildLayout,
-    kStateOutOfFlowLayout,
-    kStateFinalize
-  };
-  LayoutState layout_state_;
-
   RefPtr<const ComputedStyle> style_;
 
   Member<NGBlockNode> first_child_;
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm_test.cc b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm_test.cc
index 905b8b4..f08222e7 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm_test.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm_test.cc
@@ -40,13 +40,11 @@
     NGBlockNode parent(style_.get());
     parent.SetFirstChild(first_child);
 
-    NGLayoutCoordinator coordinator(&parent, space);
+    NGBlockLayoutAlgorithm algorithm(style_.get(), first_child, space);
+
     NGPhysicalFragment* fragment;
-    coordinator.Tick(&fragment);
-    EXPECT_EQ(kBlockLayoutAlgorithm,
-              coordinator.GetAlgorithmStackForTesting()[0]->algorithmType());
-    while (!coordinator.Tick(&fragment))
-      ;
+    NGLayoutAlgorithm* not_used;
+    EXPECT_EQ(kNewFragment, algorithm.Layout(nullptr, &fragment, &not_used));
 
     return toNGPhysicalBoxFragment(fragment);
   }
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourceContainer.cpp b/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourceContainer.cpp
index 6bfb64b4..6cb6483 100644
--- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourceContainer.cpp
+++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourceContainer.cpp
@@ -19,10 +19,6 @@
 
 #include "core/layout/svg/LayoutSVGResourceContainer.h"
 
-#include "core/SVGElementTypeHelpers.h"
-#include "core/layout/svg/LayoutSVGResourceClipper.h"
-#include "core/layout/svg/LayoutSVGResourceFilter.h"
-#include "core/layout/svg/LayoutSVGResourceMasker.h"
 #include "core/layout/svg/SVGResources.h"
 #include "core/layout/svg/SVGResourcesCache.h"
 #include "core/svg/SVGElementProxy.h"
@@ -249,14 +245,7 @@
   ASSERT(object);
   if (SVGResources* resources =
           SVGResourcesCache::cachedResourcesForLayoutObject(object)) {
-    if (LayoutSVGResourceFilter* filter = resources->filter())
-      filter->removeClientFromCache(object);
-
-    if (LayoutSVGResourceMasker* masker = resources->masker())
-      masker->removeClientFromCache(object);
-
-    if (LayoutSVGResourceClipper* clipper = resources->clipper())
-      clipper->removeClientFromCache(object);
+    resources->removeClientFromCacheAffectingObjectBounds(object);
   }
 
   if (!object->node() || !object->node()->isSVGElement())
diff --git a/third_party/WebKit/Source/core/layout/svg/SVGResources.cpp b/third_party/WebKit/Source/core/layout/svg/SVGResources.cpp
index 0602e8ac..30ea7c3 100644
--- a/third_party/WebKit/Source/core/layout/svg/SVGResources.cpp
+++ b/third_party/WebKit/Source/core/layout/svg/SVGResources.cpp
@@ -323,6 +323,19 @@
     m_linkedResource->layoutIfNeeded();
 }
 
+void SVGResources::removeClientFromCacheAffectingObjectBounds(
+    LayoutObject* object,
+    bool markForInvalidation) const {
+  if (!m_clipperFilterMaskerData)
+    return;
+  if (LayoutSVGResourceClipper* clipper = m_clipperFilterMaskerData->clipper)
+    clipper->removeClientFromCache(object, markForInvalidation);
+  if (LayoutSVGResourceFilter* filter = m_clipperFilterMaskerData->filter)
+    filter->removeClientFromCache(object, markForInvalidation);
+  if (LayoutSVGResourceMasker* masker = m_clipperFilterMaskerData->masker)
+    masker->removeClientFromCache(object, markForInvalidation);
+}
+
 void SVGResources::removeClientFromCache(LayoutObject* object,
                                          bool markForInvalidation) const {
   if (!hasResourceData())
@@ -336,17 +349,7 @@
     return;
   }
 
-  if (m_clipperFilterMaskerData) {
-    if (m_clipperFilterMaskerData->clipper)
-      m_clipperFilterMaskerData->clipper->removeClientFromCache(
-          object, markForInvalidation);
-    if (m_clipperFilterMaskerData->filter)
-      m_clipperFilterMaskerData->filter->removeClientFromCache(
-          object, markForInvalidation);
-    if (m_clipperFilterMaskerData->masker)
-      m_clipperFilterMaskerData->masker->removeClientFromCache(
-          object, markForInvalidation);
-  }
+  removeClientFromCacheAffectingObjectBounds(object, markForInvalidation);
 
   if (m_markerData) {
     if (m_markerData->markerStart)
diff --git a/third_party/WebKit/Source/core/layout/svg/SVGResources.h b/third_party/WebKit/Source/core/layout/svg/SVGResources.h
index 62a88c68..07cfa56 100644
--- a/third_party/WebKit/Source/core/layout/svg/SVGResources.h
+++ b/third_party/WebKit/Source/core/layout/svg/SVGResources.h
@@ -93,6 +93,9 @@
   // Methods operating on all cached resources
   void removeClientFromCache(LayoutObject*,
                              bool markForInvalidation = true) const;
+  void removeClientFromCacheAffectingObjectBounds(
+      LayoutObject*,
+      bool markForInvalidation = true) const;
   void resourceDestroyed(LayoutSVGResourceContainer*);
 
 #ifndef NDEBUG
diff --git a/third_party/WebKit/Source/core/paint/PrePaintTreeWalk.cpp b/third_party/WebKit/Source/core/paint/PrePaintTreeWalk.cpp
index ef1fcb2..426de330 100644
--- a/third_party/WebKit/Source/core/paint/PrePaintTreeWalk.cpp
+++ b/third_party/WebKit/Source/core/paint/PrePaintTreeWalk.cpp
@@ -53,6 +53,8 @@
   }
 
   PrePaintTreeWalkContext context(parentContext);
+  // ancestorOverflowLayer does not cross frame boundaries.
+  context.ancestorOverflowPaintLayer = nullptr;
   m_propertyTreeBuilder.updateProperties(frameView, context.treeBuilderContext);
   m_paintInvalidator.invalidatePaintIfNeeded(frameView,
                                              context.paintInvalidatorContext);
diff --git a/third_party/WebKit/Source/core/style/GridArea.h b/third_party/WebKit/Source/core/style/GridArea.h
index bbc1f97e..daa3a00 100644
--- a/third_party/WebKit/Source/core/style/GridArea.h
+++ b/third_party/WebKit/Source/core/style/GridArea.h
@@ -34,13 +34,18 @@
 #include "core/style/GridPositionsResolver.h"
 #include "wtf/Allocator.h"
 #include "wtf/HashMap.h"
+#include "wtf/MathExtras.h"
 #include "wtf/text/WTFString.h"
 #include <algorithm>
 
 namespace blink {
 
-// Recommended maximum size for both explicit and implicit grids.
-const int kGridMaxTracks = 1000000;
+// Recommended maximum size for both explicit and implicit grids. Note that this
+// actually allows a [-9999,9999] range. The limit is low on purpouse because
+// higher values easly trigger OOM situations. That will definitely improve once
+// we switch from a vector of vectors based grid representation to a more
+// efficient one memory-wise.
+const int kGridMaxTracks = 1000;
 
 // A span in a single direction (either rows or columns). Note that |startLine|
 // and |endLine| are grid lines' indexes.
@@ -141,15 +146,8 @@
     }
 #endif
 
-    if (startLine >= 0)
-      m_startLine = std::min(startLine, kGridMaxTracks - 1);
-    else
-      m_startLine = std::max(startLine, -kGridMaxTracks);
-
-    if (endLine >= 0)
-      m_endLine = std::min(endLine, kGridMaxTracks);
-    else
-      m_endLine = std::max(endLine, -kGridMaxTracks + 1);
+    m_startLine = clampTo<int>(startLine, -kGridMaxTracks, kGridMaxTracks - 1);
+    m_endLine = clampTo<int>(endLine, -kGridMaxTracks + 1, kGridMaxTracks);
   }
 
   int m_startLine;
diff --git a/third_party/WebKit/Source/modules/geolocation/GeoNotifier.cpp b/third_party/WebKit/Source/modules/geolocation/GeoNotifier.cpp
index 9d1027e..0d78f5b 100644
--- a/third_party/WebKit/Source/modules/geolocation/GeoNotifier.cpp
+++ b/third_party/WebKit/Source/modules/geolocation/GeoNotifier.cpp
@@ -4,7 +4,6 @@
 
 #include "modules/geolocation/GeoNotifier.h"
 
-#include "core/dom/TaskRunnerHelper.h"
 #include "modules/geolocation/Geolocation.h"
 #include "modules/geolocation/PositionError.h"
 #include "modules/geolocation/PositionOptions.h"
@@ -21,10 +20,7 @@
       m_successCallback(successCallback),
       m_errorCallback(errorCallback),
       m_options(options),
-      m_timer(TaskRunnerHelper::get(TaskType::MiscPlatformAPI,
-                                    geolocation->frame()),
-              this,
-              &GeoNotifier::timerFired),
+      m_timer(this, &GeoNotifier::timerFired),
       m_useCachedPosition(false) {
   DCHECK(m_geolocation);
   DCHECK(m_successCallback);
diff --git a/third_party/WebKit/Source/modules/geolocation/GeoNotifier.h b/third_party/WebKit/Source/modules/geolocation/GeoNotifier.h
index ee91c10..e254fe1e 100644
--- a/third_party/WebKit/Source/modules/geolocation/GeoNotifier.h
+++ b/third_party/WebKit/Source/modules/geolocation/GeoNotifier.h
@@ -61,7 +61,7 @@
   Member<PositionCallback> m_successCallback;
   Member<PositionErrorCallback> m_errorCallback;
   const PositionOptions m_options;
-  TaskRunnerTimer<GeoNotifier> m_timer;
+  Timer<GeoNotifier> m_timer;
   Member<PositionError> m_fatalError;
   bool m_useCachedPosition;
 };
diff --git a/third_party/WebKit/Source/modules/webaudio/AudioNode.cpp b/third_party/WebKit/Source/modules/webaudio/AudioNode.cpp
index f13bc61..5474f282 100644
--- a/third_party/WebKit/Source/modules/webaudio/AudioNode.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/AudioNode.cpp
@@ -621,7 +621,7 @@
   }
 
   if (context() != destination->context()) {
-    exceptionState.throwDOMException(SyntaxError,
+    exceptionState.throwDOMException(InvalidAccessError,
                                      "cannot connect to a destination "
                                      "belonging to a different audio context.");
     return nullptr;
diff --git a/third_party/WebKit/Source/web/WebFrameSerializer.cpp b/third_party/WebKit/Source/web/WebFrameSerializer.cpp
index 9a266f1d..35eb693 100644
--- a/third_party/WebKit/Source/web/WebFrameSerializer.cpp
+++ b/third_party/WebKit/Source/web/WebFrameSerializer.cpp
@@ -110,11 +110,12 @@
   // be excluded:
   // 1) All elements that are head or part of head, including head, meta, style,
   //    link and etc.
-  // 2) Some specific elements in body: meta, datalist, option and etc.
+  // 2) Some specific elements in body: meta, style, datalist, option and etc.
   if (element.layoutObject())
     return false;
   if (isHTMLHeadElement(element) || isHTMLMetaElement(element) ||
-      isHTMLDataListElement(element) || isHTMLOptionElement(element)) {
+      isHTMLStyleElement(element) || isHTMLDataListElement(element) ||
+      isHTMLOptionElement(element)) {
     return false;
   }
   Element* parent = element.parentElement();
diff --git a/third_party/WebKit/Source/web/tests/WebFrameSerializerTest.cpp b/third_party/WebKit/Source/web/tests/WebFrameSerializerTest.cpp
index 41abdf2..23af6aca 100644
--- a/third_party/WebKit/Source/web/tests/WebFrameSerializerTest.cpp
+++ b/third_party/WebKit/Source/web/tests/WebFrameSerializerTest.cpp
@@ -266,6 +266,8 @@
   EXPECT_NE(WTF::kNotFound, mhtml.find("<option"));
   // One for meta in head and another for meta in body.
   EXPECT_EQ(2, matchSubstring(mhtml, "<meta", 5));
+  // One for style in head and another for style in body.
+  EXPECT_EQ(2, matchSubstring(mhtml, "<style", 6));
 
   // These hidden elements that affect layout should remain intact.
   EXPECT_NE(WTF::kNotFound, mhtml.find("<h2"));
diff --git a/third_party/WebKit/Source/web/tests/WebViewTest.cpp b/third_party/WebKit/Source/web/tests/WebViewTest.cpp
index 7929d8fa..5ceb8a0a 100644
--- a/third_party/WebKit/Source/web/tests/WebViewTest.cpp
+++ b/third_party/WebKit/Source/web/tests/WebViewTest.cpp
@@ -4335,7 +4335,10 @@
 
   WebURL baseURL = URLTestHelpers::toKURL("http://example.com/");
   FrameTestHelpers::loadHTMLString(webView->mainFrame(),
-                                   "<style>#vw { width: 100vw }</style>"
+                                   "<style>"
+                                   "  body { margin: 0px; }"
+                                   "  #vw { width: 100vw; height: 100vh; }"
+                                   "</style>"
                                    "<div id=vw></div>",
                                    baseURL);
 
@@ -4345,16 +4348,36 @@
 
   EXPECT_EQ(800, vwElement->offsetWidth());
 
+  FloatSize pageSize(300, 360);
+
   WebPrintParams printParams;
-  printParams.printContentArea.width = 500;
-  printParams.printContentArea.height = 500;
+  printParams.printContentArea.width = pageSize.width();
+  printParams.printContentArea.height = pageSize.height();
+
+  // This needs to match printingMinimumShrinkFactor in PrintContext.cpp. The
+  // layout is scaled by this factor for printing.
+  constexpr float minimumShrinkFactor = 1.333f;
+
+  // The expected layout size comes from the calculation done in
+  // resizePageRectsKeepingRatio which is used from PrintContext::begin to
+  // scale the page size.
+  const float ratio = pageSize.height() / (float)pageSize.width();
+  const int expectedWidth = floor(pageSize.width() * minimumShrinkFactor);
+  const int expectedHeight = floor(expectedWidth * ratio);
 
   frame->printBegin(printParams, WebNode());
-  webView->resize(WebSize(500, 500));
-  EXPECT_EQ(500, vwElement->offsetWidth());
+
+  EXPECT_EQ(expectedWidth, vwElement->offsetWidth());
+  EXPECT_EQ(expectedHeight, vwElement->offsetHeight());
+
+  webView->resize(flooredIntSize(pageSize));
+
+  EXPECT_EQ(expectedWidth, vwElement->offsetWidth());
+  EXPECT_EQ(expectedHeight, vwElement->offsetHeight());
 
   webView->resize(WebSize(800, 600));
   frame->printEnd();
+
   EXPECT_EQ(800, vwElement->offsetWidth());
 }
 
diff --git a/third_party/WebKit/Source/web/tests/data/frameserialization/hidden_elements.html b/third_party/WebKit/Source/web/tests/data/frameserialization/hidden_elements.html
index 7dfe41d..465fc7a 100644
--- a/third_party/WebKit/Source/web/tests/data/frameserialization/hidden_elements.html
+++ b/third_party/WebKit/Source/web/tests/data/frameserialization/hidden_elements.html
@@ -22,6 +22,9 @@
   </datalist>
 </form>
 <div itemscope>
+  <style>
+  #foo { display: block;}
+  </style>
   <meta itemprop="name" content="value">
 </div>
 </body>
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/common/net/git_cl.py b/third_party/WebKit/Tools/Scripts/webkitpy/common/net/git_cl.py
index 9e5f9f8..a47a9381 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/common/net/git_cl.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/common/net/git_cl.py
@@ -46,19 +46,16 @@
             A list of try job result dicts, or None if a timeout occurred.
         """
         start = self._host.time()
-        self._host.print_('Waiting for try jobs (timeout: %d s, poll interval %d s).' %
-                          (timeout_seconds, poll_delay_seconds))
+        self._host.print_('Waiting for try jobs (timeout: %d seconds).' % timeout_seconds)
         while self._host.time() - start < timeout_seconds:
             self._host.sleep(poll_delay_seconds)
             try_results = self.fetch_try_results()
             _log.debug('Fetched try results: %s', try_results)
             if self.all_jobs_finished(try_results):
-                self._host.print_()
                 self._host.print_('All jobs finished.')
                 return try_results
-            self._host.print_('.', end='')
+            self._host.print_('Waiting. %d seconds passed.' % (self._host.time() - start))
             self._host.sleep(poll_delay_seconds)
-        self._host.print_()
         self._host.print_('Timed out waiting for try results.')
         return None
 
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/common/net/git_cl_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/common/net/git_cl_unittest.py
index ee9c1db4..7c47ebc 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/common/net/git_cl_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/common/net/git_cl_unittest.py
@@ -63,8 +63,14 @@
         git_cl.wait_for_try_jobs()
         self.assertEqual(
             host.stdout.getvalue(),
-            'Waiting for try jobs (timeout: 7200 s, poll interval 600 s).\n'
-            '......\nTimed out waiting for try results.\n')
+            'Waiting for try jobs (timeout: 7200 seconds).\n'
+            'Waiting. 600 seconds passed.\n'
+            'Waiting. 1800 seconds passed.\n'
+            'Waiting. 3000 seconds passed.\n'
+            'Waiting. 4200 seconds passed.\n'
+            'Waiting. 5400 seconds passed.\n'
+            'Waiting. 6600 seconds passed.\n'
+            'Timed out waiting for try results.\n')
 
     def test_wait_for_try_jobs_done(self):
         host = MockHost()
@@ -79,7 +85,7 @@
         git_cl.wait_for_try_jobs()
         self.assertEqual(
             host.stdout.getvalue(),
-            'Waiting for try jobs (timeout: 7200 s, poll interval 600 s).\n\n'
+            'Waiting for try jobs (timeout: 7200 seconds).\n'
             'All jobs finished.\n')
 
     def test_all_jobs_finished_with_started_jobs(self):
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/deps_updater.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/deps_updater.py
index 1264ec2..e1745e3 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/deps_updater.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/deps_updater.py
@@ -58,18 +58,26 @@
 
         _log.info('Noting the current Chromium commit.')
         _, show_ref_output = self.run(['git', 'show-ref', 'HEAD'])
-        chromium_commitish = show_ref_output.split()[0]
+        chromium_commit = show_ref_output.split()[0]
 
         if options.target == 'wpt':
-            import_commitish = self.update(WPT_DEST_NAME, WPT_REPO_URL, options.keep_w3c_repos_around, options.revision)
+            import_commit = self.update(WPT_DEST_NAME, WPT_REPO_URL, options.keep_w3c_repos_around, options.revision)
             self._copy_resources()
         elif options.target == 'css':
-            import_commitish = self.update(CSS_DEST_NAME, CSS_REPO_URL, options.keep_w3c_repos_around, options.revision)
+            import_commit = self.update(CSS_DEST_NAME, CSS_REPO_URL, options.keep_w3c_repos_around, options.revision)
         else:
             raise AssertionError("Unsupported target %s" % options.target)
 
-        has_changes = self.commit_changes_if_needed(chromium_commitish, import_commitish)
-        if options.auto_update and has_changes:
+        has_changes = self._has_changes()
+        if not has_changes:
+            _log.info('Done: no changes to import.')
+            return 0
+
+        commit_message = self._commit_message(chromium_commit, import_commit)
+        self._commit_changes(commit_message)
+        _log.info('Done: changes imported and committed.')
+
+        if options.auto_update:
             commit_successful = self.do_auto_update()
             if not commit_successful:
                 return 1
@@ -229,36 +237,28 @@
 
         return '%s@%s' % (dest_dir_name, master_commitish)
 
-    def commit_changes_if_needed(self, chromium_commitish, import_commitish):
-        if self.run(['git', 'diff', '--quiet', 'HEAD'], exit_on_failure=False)[0]:
-            _log.info('Committing changes.')
-            commit_msg = ('Import %s\n'
-                          '\n'
-                          'Using update-w3c-deps in Chromium %s.\n'
-                          % (import_commitish, chromium_commitish))
-            path_to_commit_msg = self.path_from_webkit_base('commit_msg')
-            _log.debug('cat > %s <<EOF', path_to_commit_msg)
-            _log.debug(commit_msg)
-            _log.debug('EOF')
-            self.fs.write_text_file(path_to_commit_msg, commit_msg)
-            self.run(['git', 'commit', '-a', '-F', path_to_commit_msg])
-            self.remove(path_to_commit_msg)
-            _log.info('Done: changes imported and committed.')
-            return True
-        else:
-            _log.info('Done: no changes to import.')
-            return False
+    def _commit_changes(self, commit_message):
+        _log.info('Committing changes.')
+        self.run(['git', 'commit', '--all', '-F', '-'], stdin=commit_message)
+
+    def _has_changes(self):
+        return_code, _ = self.run(['git', 'diff', '--quiet', 'HEAD'], exit_on_failure=False)
+        return return_code == 1
+
+    def _commit_message(self, chromium_commit, import_commit):
+        return ('Import %s\n\nUsing update-w3c-deps in Chromium %s.\n\n' %
+                (import_commit, chromium_commit))
 
     @staticmethod
     def is_baseline(basename):
         return basename.endswith('-expected.txt')
 
-    def run(self, cmd, exit_on_failure=True, cwd=None):
+    def run(self, cmd, exit_on_failure=True, cwd=None, stdin=''):
         _log.debug('Running command: %s', ' '.join(cmd))
 
         cwd = cwd or self.finder.webkit_base()
-        proc = self.executive.popen(cmd, stdout=self.executive.PIPE, stderr=self.executive.PIPE, cwd=cwd)
-        out, err = proc.communicate()
+        proc = self.executive.popen(cmd, stdout=self.executive.PIPE, stderr=self.executive.PIPE, stdin=self.executive.PIPE)
+        out, err = proc.communicate(stdin)
         if proc.returncode or self.verbose:
             _log.info('# ret> %d', proc.returncode)
             if out:
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/deps_updater_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/deps_updater_unittest.py
index 8b0c9ea7..f5524fe 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/deps_updater_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/deps_updater_unittest.py
@@ -62,6 +62,21 @@
 
     # Tests for protected methods - pylint: disable=protected-access
 
+    def test_commit_changes(self):
+        host = MockHost()
+        updater = DepsUpdater(host)
+        updater._has_changes = lambda: True
+        updater._commit_changes('dummy message')
+        self.assertEqual(
+            host.executive.calls,
+            [['git', 'commit', '--all', '-F', '-']])
+
+    def test_commit_message(self):
+        updater = DepsUpdater(MockHost())
+        self.assertEqual(
+            updater._commit_message('aaaa', '1111'),
+            'Import 1111\n\nUsing update-w3c-deps in Chromium aaaa.\n\n')
+
     def test_cl_description_with_empty_environ(self):
         host = MockHost()
         host.executive = MockExecutive(output='Last commit message\n')
diff --git a/tools/clang/rewrite_to_chrome_style/RewriteToChromeStyle.cpp b/tools/clang/rewrite_to_chrome_style/RewriteToChromeStyle.cpp
index 44383523..5a0d644 100644
--- a/tools/clang/rewrite_to_chrome_style/RewriteToChromeStyle.cpp
+++ b/tools/clang/rewrite_to_chrome_style/RewriteToChromeStyle.cpp
@@ -470,7 +470,7 @@
   // from gen/, which is problematic, but DevTools folks don't want to rename
   // it or split this up. So don't rename it at all.
   if (name.equals("disable") &&
-      IsMethodOverrideOf(decl, "blink::InspectorAgent"))
+      IsMethodOverrideOf(decl, "blink::InspectorBaseAgent"))
     return true;
 
   return false;
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index fddeff3a..25b765f 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -20398,6 +20398,15 @@
   </summary>
 </histogram>
 
+<histogram name="GPU.ShaderLoadPrefixOK" enum="BooleanMatched">
+  <owner>ericrk@chromium.org</owner>
+  <summary>
+    Whether or not the shader prefix loaded from disk matched the expected
+    prefix for the data and system configuration. False indicates either disk
+    corruption or a system configuration change, and should be rare.
+  </summary>
+</histogram>
+
 <histogram name="GPU.TextureRG" enum="BooleanAvailable">
   <owner>reveman@chromium.org</owner>
   <summary>
@@ -26205,6 +26214,11 @@
 </histogram>
 
 <histogram name="Media.Video.TimeFromForegroundToFirstFrame" units="ms">
+  <obsolete>
+    Deprecated as of 01/18/2017 in issue 670150. Replaced by
+    Media.Video.TimeFromForegroundToFirstFrame.DisabledTrack and
+    Media.Video.TimeFromForegroundToFirstFrame.Paused.
+  </obsolete>
   <owner>avayvod@chromium.org</owner>
   <owner>dalecurtis@chromium.org</owner>
   <summary>
@@ -26213,6 +26227,30 @@
   </summary>
 </histogram>
 
+<histogram name="Media.Video.TimeFromForegroundToFirstFrame.DisabledTrack"
+    units="ms">
+  <owner>avayvod@chromium.org</owner>
+  <owner>dalecurtis@chromium.org</owner>
+  <summary>
+    Records the time between the moment when the video element that had video
+    track disabled in the background is brought to the foreground and when the
+    video frame compositor outputs the next frame. Recorded even if disabling
+    video track in the background is turned off to collect data for the control
+    group.
+  </summary>
+</histogram>
+
+<histogram name="Media.Video.TimeFromForegroundToFirstFrame.Paused" units="ms">
+  <owner>avayvod@chromium.org</owner>
+  <owner>dalecurtis@chromium.org</owner>
+  <summary>
+    Records the time between the moment when the video element that was paused
+    in the background is brought to the foreground and when the video frame
+    compositor outputs the next frame. Recorded even if disabling pausing video
+    in the background is turned off to collect data for the control group.
+  </summary>
+</histogram>
+
 <histogram name="Media.VideoCapture.AspectRatio" units="%">
   <owner>mcasas@chromium.org</owner>
   <summary>
diff --git a/tools/perf/generate_perf_json.py b/tools/perf/generate_perf_json.py
index 2da1808..348ba22d 100755
--- a/tools/perf/generate_perf_json.py
+++ b/tools/perf/generate_perf_json.py
@@ -412,6 +412,19 @@
           ]
       }
     ])
+  waterfall = add_tester(
+    waterfall, 'Mac Mini 8GB 10.12 Perf',
+    'chromium-rel-mac12-mini-8gb', 'mac',
+    swarming=[
+      {
+       'gpu': '8086:0a26',
+       'os': 'Mac-10.12',
+       'device_ids': [
+           'build24-b1', 'build25-b1',
+           'build26-b1', 'build27-b1', 'build28-b1'
+          ]
+      }
+    ])
 
   waterfall = add_tester(
     waterfall, 'Linux Perf', 'linux-release', 'linux',
diff --git a/ui/events/ozone/evdev/scoped_input_device.h b/ui/events/ozone/evdev/scoped_input_device.h
index 24d8aa58..5278dd0 100644
--- a/ui/events/ozone/evdev/scoped_input_device.h
+++ b/ui/events/ozone/evdev/scoped_input_device.h
@@ -6,11 +6,12 @@
 #define UI_EVENTS_OZONE_EVDEV_SCOPED_INPUT_DEVICE_H_
 
 #include "base/scoped_generic.h"
+#include "ui/events/ozone/evdev/events_ozone_evdev_export.h"
 
 namespace ui {
 namespace internal {
 
-struct ScopedInputDeviceCloseTraits {
+struct EVENTS_OZONE_EVDEV_EXPORT ScopedInputDeviceCloseTraits {
   static int InvalidValue() { return -1; }
   static void Free(int fd);
 };
diff --git a/ui/login/account_picker/user_pod_row.js b/ui/login/account_picker/user_pod_row.js
index 85e8297f..37746d0 100644
--- a/ui/login/account_picker/user_pod_row.js
+++ b/ui/login/account_picker/user_pod_row.js
@@ -89,11 +89,13 @@
    * @const
    */
   var UserPodTabOrder = {
-    POD_INPUT: 1,        // Password input field, Action box menu button, and
-                         // the pod itself.
-    POD_CUSTOM_ICON: 2,  // Pod custom icon next to password input field.
-    HEADER_BAR: 3,       // Buttons on the header bar (Shutdown, Add User).
-    POD_MENU_ITEM: 4     // User pad menu items (User info, Remove user).
+    POD_INPUT: 1,        // Password input field, Action box menu button, submit
+                         // button next to password input field and the pod
+                         // itself.
+    PIN_KEYBOARD: 2,     // Pin keyboard below the password input field.
+    POD_CUSTOM_ICON: 3,  // Pod custom icon next to password input field.
+    HEADER_BAR: 4,       // Buttons on the header bar (Shutdown, Add User).
+    POD_MENU_ITEM: 5     // User pad menu items (User info, Remove user).
   };
 
   /**
@@ -722,6 +724,7 @@
         this.pinKeyboard.passwordElement = this.passwordElement;
         this.pinKeyboard.addEventListener('pin-change',
             this.handleInputChanged_.bind(this));
+        this.pinKeyboard.tabIndex = UserPodTabOrder.PIN_KEYBOARD;
       }
 
       this.actionBoxAreaElement.addEventListener('mousedown',
@@ -767,6 +770,7 @@
       if (this.submitButton) {
         this.submitButton.addEventListener('click',
             this.handleSubmitButtonClick_.bind(this));
+        this.submitButton.tabIndex = UserPodTabOrder.POD_INPUT;
       }
 
       this.imageElement.addEventListener('load',