diff --git a/DEPS b/DEPS
index 5ebf3a0..c1cba3b 100644
--- a/DEPS
+++ b/DEPS
@@ -39,11 +39,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '84a80652752976c9abe42d28e467c362baff3e39',
+  'skia_revision': '0b2a18922146c6134515d42baf5935b71bba03c3',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': '12a032e6a657cbaba85b9df70bbea89dd561daf1',
+  'v8_revision': '10449d46aa20f10f39598627bf07f70def597029',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -193,7 +193,7 @@
    Var('chromium_git') + '/chromium/third_party/ffmpeg.git' + '@' + 'b1b22ffc6a5c809c41cc27910e3e8b479c15d3a2',
 
   'src/third_party/libjingle/source/talk':
-    Var('chromium_git') + '/external/webrtc/trunk/talk.git' + '@' + '38c50da122a671f174cb4f1f41ec7ed4c9af048c', # commit position 10588
+    Var('chromium_git') + '/external/webrtc/trunk/talk.git' + '@' + '024b75ea420658818878983392c0245acb65d4fc', # commit position 10603
 
   'src/third_party/usrsctp/usrsctplib':
     Var('chromium_git') + '/external/usrsctplib.git' + '@' + '36444a999739e9e408f8f587cb4c3ffeef2e50ac', # from svn revision 9215
@@ -217,7 +217,7 @@
    Var('chromium_git') + '/native_client/src/third_party/scons-2.0.1.git' + '@' + '1c1550e17fc26355d08627fbdec13d8291227067',
 
   'src/third_party/webrtc':
-    Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + 'ca8da3c95807a2fffb3eb3acde59ff095e89516f', # commit position 10588
+    Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + 'c3834e3a15751fd0135525531b94730b9ab206d6', # commit position 10602
 
   'src/third_party/openmax_dl':
     Var('chromium_git') + '/external/webrtc/deps/third_party/openmax.git' + '@' +  Var('openmax_dl_revision'),
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AndroidScrollIntegrationTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AndroidScrollIntegrationTest.java
index 79cc1d06..8c3cbf6 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AndroidScrollIntegrationTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AndroidScrollIntegrationTest.java
@@ -33,8 +33,6 @@
  * Integration tests for synchronous scrolling.
  */
 @SuppressFBWarnings("DLS_DEAD_LOCAL_STORE")
-// Run in single-process mode only. Blocked by rendering support crbug.com/526842.
-@ParameterizedTest.Set
 public class AndroidScrollIntegrationTest extends AwTestBase {
     private TestWebServer mWebServer;
 
@@ -377,6 +375,8 @@
 
     @SmallTest
     @Feature({"AndroidWebView"})
+    // Run in single-process mode only. Flaky with sandboxed renderer crbug.com/554529.
+    @ParameterizedTest.Set
     public void testJsScrollFromBody() throws Throwable {
         final TestAwContentsClient contentsClient = new TestAwContentsClient();
         final ScrollTestContainerView testContainerView =
@@ -522,6 +522,8 @@
 
     @SmallTest
     @Feature({"AndroidWebView"})
+    // Run in single-process mode only. Blocked by software draws support crbug.com/545611.
+    @ParameterizedTest.Set
     public void testOverScrollX() throws Throwable {
         final TestAwContentsClient contentsClient = new TestAwContentsClient();
         final ScrollTestContainerView testContainerView =
@@ -555,6 +557,8 @@
 
     @SmallTest
     @Feature({"AndroidWebView"})
+    // Run in single-process mode only. Blocked by software draws support crbug.com/545611.
+    @ParameterizedTest.Set
     public void testOverScrollY() throws Throwable {
         final TestAwContentsClient contentsClient = new TestAwContentsClient();
         final ScrollTestContainerView testContainerView =
@@ -617,6 +621,8 @@
 
     @SmallTest
     @Feature({"AndroidWebView"})
+    // Run in single-process mode only. Blocked by multiple RVHs crbug.com/533516.
+    @ParameterizedTest.Set
     public void testFlingScrollOnPopup() throws Throwable {
         final TestAwContentsClient parentContentsClient = new TestAwContentsClient();
         final ScrollTestContainerView parentContainerView =
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AndroidViewIntegrationTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AndroidViewIntegrationTest.java
index 865d064d..3766041d 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AndroidViewIntegrationTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AndroidViewIntegrationTest.java
@@ -300,7 +300,7 @@
 
     @SmallTest
     @Feature({"AndroidWebView"})
-    // Run in single-process mode only. Blocked by rendering support crbug.com/526842.
+    // Run in single-process mode only. Blocked by software draws support crbug.com/545611.
     @ParameterizedTest.Set
     public void testViewIsNotBlankInWrapContentsMode() throws Throwable {
         final TestAwContentsClient contentsClient = new TestAwContentsClient();
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientFullScreenTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientFullScreenTest.java
index 77e6322..4eb1279 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientFullScreenTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientFullScreenTest.java
@@ -31,8 +31,6 @@
  * we pick a div containing a video and custom html controls since this is a
  * very common use case.
  */
-// Run in single-process mode only. Blocked by rendering support crbug.com/526842.
-@ParameterizedTest.Set
 public class AwContentsClientFullScreenTest extends AwTestBase {
     private static final String VIDEO_TEST_URL =
             "file:///android_asset/full_screen_video_test.html";
@@ -83,6 +81,8 @@
     @MediumTest
     @Feature({"AndroidWebView"})
     @DisableHardwareAccelerationForTest
+    // Run in single-process mode only. Blocked by software draws support crbug.com/545611.
+    @ParameterizedTest.Set
     public void testFullscreenForNonVideoElementIsSupportedInSoftwareMode() throws Throwable {
         // Fullscreen for non-video elements is supported and works as expected. Note that
         // this test is the same as testOnShowAndHideCustomViewWithCallback_videoInsideDiv below.
@@ -198,6 +198,8 @@
 
     @MediumTest
     @Feature({"AndroidWebView"})
+    // Run in single-process mode only. Blocked by software draws support crbug.com/545611.
+    @ParameterizedTest.Set
     public void testHolePunchingSurfaceNotCreatedForClearVideo()
             throws Throwable {
         loadTestPage(VIDEO_TEST_URL);
@@ -316,6 +318,8 @@
 
     @MediumTest
     @Feature({"AndroidWebView"})
+    // Run in single-process mode only. Blocked by software draws support crbug.com/545611.
+    @ParameterizedTest.Set
     public void testPowerSaveBlockerIsEnabledDuringFullscreenPlayback_videoInsideDiv()
             throws Throwable {
         doTestPowerSaveBlockerIsEnabledDuringFullscreenPlayback(VIDEO_INSIDE_DIV_TEST_URL);
@@ -341,6 +345,8 @@
 
     @MediumTest
     @Feature({"AndroidWebView"})
+    // Run in single-process mode only. Blocked by software draws support crbug.com/545611.
+    @ParameterizedTest.Set
     public void testPowerSaveBlockerIsEnabledDuringEmbeddedPlayback()
             throws Throwable {
         assertFalse(DOMUtils.isFullscreen(getWebContentsOnUiThread()));
@@ -360,6 +366,8 @@
 
     @MediumTest
     @Feature({"AndroidWebView"})
+    // Run in single-process mode only. Blocked by software draws support crbug.com/545611.
+    @ParameterizedTest.Set
     public void testPowerSaveBlockerIsTransferredToFullscreen()
             throws Throwable {
         assertFalse(DOMUtils.isFullscreen(getWebContentsOnUiThread()));
@@ -388,6 +396,8 @@
 
     @MediumTest
     @Feature({"AndroidWebView"})
+    // Run in single-process mode only. Blocked by software draws support crbug.com/545611.
+    @ParameterizedTest.Set
     public void testPowerSaveBlockerIsTransferredToEmbedded()
             throws Throwable {
         // Enter fullscreen.
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientGetVideoLoadingProgressViewTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientGetVideoLoadingProgressViewTest.java
index 68e10d63..6275682 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientGetVideoLoadingProgressViewTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientGetVideoLoadingProgressViewTest.java
@@ -9,7 +9,6 @@
 
 import org.chromium.android_webview.AwContents;
 import org.chromium.base.test.util.Feature;
-import org.chromium.base.test.util.parameter.ParameterizedTest;
 import org.chromium.content.browser.test.util.CallbackHelper;
 import org.chromium.content.browser.test.util.DOMUtils;
 
@@ -26,8 +25,6 @@
  * used to trigger switch occupies almost the whole WebView so the simulated click event
  * can't miss it.
  */
-// Run in single-process mode only. Blocked by rendering support crbug.com/526842.
-@ParameterizedTest.Set
 public class AwContentsClientGetVideoLoadingProgressViewTest extends AwTestBase
         implements View.OnAttachStateChangeListener {
     private static final String VIDEO_TEST_URL =
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientOnScaleChangedTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientOnScaleChangedTest.java
index c8a779d3..338216a1 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientOnScaleChangedTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientOnScaleChangedTest.java
@@ -9,15 +9,12 @@
 import org.chromium.android_webview.AwContents;
 import org.chromium.android_webview.test.util.CommonResources;
 import org.chromium.base.ThreadUtils;
-import org.chromium.base.test.util.parameter.ParameterizedTest;
 import org.chromium.content.browser.test.util.Criteria;
 import org.chromium.content.browser.test.util.CriteriaHelper;
 
 /**
  * Tests for the WebViewClient.onScaleChanged.
  */
-// Run in single-process mode only. Blocked by rendering support crbug.com/526842.
-@ParameterizedTest.Set
 public class AwContentsClientOnScaleChangedTest extends AwTestBase {
     private TestAwContentsClient mContentsClient;
     private AwContents mAwContents;
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsTest.java
index 6d536bb..83c51bd 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsTest.java
@@ -80,8 +80,6 @@
 
     @LargeTest
     @Feature({"AndroidWebView"})
-    // Run in single-process mode only. Blocked by rendering support crbug.com/526842.
-    @ParameterizedTest.Set
     public void testCreateLoadDestroyManyTimes() throws Throwable {
         for (int i = 0; i < 10; ++i) {
             AwTestContainerView testView = createAwTestContainerViewOnMainSync(mContentsClient);
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwLegacyQuirksTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwLegacyQuirksTest.java
index 6334e3e..9565638a 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AwLegacyQuirksTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwLegacyQuirksTest.java
@@ -11,7 +11,6 @@
 import org.chromium.android_webview.AwSettings;
 import org.chromium.base.annotations.SuppressFBWarnings;
 import org.chromium.base.test.util.Feature;
-import org.chromium.base.test.util.parameter.ParameterizedTest;
 import org.chromium.content.browser.test.util.CallbackHelper;
 import org.chromium.ui.gfx.DeviceDisplayInfo;
 
@@ -243,8 +242,6 @@
 
     @MediumTest
     @Feature({"AndroidWebView"})
-    // Run in single-process mode only. Blocked by rendering support crbug.com/526842.
-    @ParameterizedTest.Set
     public void testInitialScaleClobberQuirk() throws Throwable {
         final TestAwContentsClient contentClient = new TestAwContentsClient();
         final AwTestContainerView testContainerView =
@@ -279,8 +276,6 @@
 
     @MediumTest
     @Feature({"AndroidWebView"})
-    // Run in single-process mode only. Blocked by rendering support crbug.com/526842.
-    @ParameterizedTest.Set
     public void testNoUserScalableQuirk() throws Throwable {
         final TestAwContentsClient contentClient = new TestAwContentsClient();
         final AwTestContainerView testContainerView =
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwSettingsTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwSettingsTest.java
index bf3969d..431c2a2 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AwSettingsTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwSettingsTest.java
@@ -32,7 +32,6 @@
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.TestFileUtil;
 import org.chromium.base.test.util.UrlUtils;
-import org.chromium.base.test.util.parameter.ParameterizedTest;
 import org.chromium.content.browser.test.util.CallbackHelper;
 import org.chromium.content.browser.test.util.HistoryUtils;
 import org.chromium.content.browser.test.util.TestCallbackHelperContainer;
@@ -2193,8 +2192,6 @@
 
     @SmallTest
     @Feature({"AndroidWebView", "Preferences"})
-    // Run in single-process mode only. Blocked by rendering support crbug.com/526842.
-    @ParameterizedTest.Set
     public void testLayoutAlgorithmWithTwoViews() throws Throwable {
         ViewPair views = createViews();
         runPerViewSettingsTest(
@@ -2213,8 +2210,6 @@
 
     @SmallTest
     @Feature({"AndroidWebView", "Preferences"})
-    // Run in single-process mode only. Blocked by rendering support crbug.com/526842.
-    @ParameterizedTest.Set
     public void testTextZoomAutosizingWithTwoViews() throws Throwable {
         ViewPair views = createViews();
         runPerViewSettingsTest(
@@ -2583,8 +2578,6 @@
 
     @MediumTest
     @Feature({"AndroidWebView", "Preferences"})
-    // Run in single-process mode only. Blocked by rendering support crbug.com/526842.
-    @ParameterizedTest.Set
     public void testUseWideViewportControlsDoubleTabToZoom() throws Throwable {
         final TestAwContentsClient contentClient = new TestAwContentsClient();
         final AwTestContainerView testContainerView =
@@ -2657,8 +2650,6 @@
 
     @SmallTest
     @Feature({"AndroidWebView", "Preferences"})
-    // Run in single-process mode only. Blocked by rendering support crbug.com/526842.
-    @ParameterizedTest.Set
     public void testLoadWithOverviewModeWithTwoViews() throws Throwable {
         ViewPair views = createViews();
         runPerViewSettingsTest(
@@ -2670,8 +2661,6 @@
 
     @SmallTest
     @Feature({"AndroidWebView", "Preferences"})
-    // Run in single-process mode only. Blocked by rendering support crbug.com/526842.
-    @ParameterizedTest.Set
     public void testLoadWithOverviewModeViewportTagWithTwoViews() throws Throwable {
         ViewPair views = createViews();
         runPerViewSettingsTest(
@@ -2683,8 +2672,6 @@
 
     @SmallTest
     @Feature({"AndroidWebView", "Preferences"})
-    // Run in single-process mode only. Blocked by rendering support crbug.com/526842.
-    @ParameterizedTest.Set
     public void testSetInitialScale() throws Throwable {
         final TestAwContentsClient contentClient = new TestAwContentsClient();
         final AwTestContainerView testContainerView =
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwTestBase.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwTestBase.java
index 22b041d..4cc375d 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AwTestBase.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwTestBase.java
@@ -31,6 +31,7 @@
 import org.chromium.content.browser.test.util.Criteria;
 import org.chromium.content.browser.test.util.CriteriaHelper;
 import org.chromium.content.browser.test.util.TestCallbackHelperContainer.OnPageFinishedHelper;
+import org.chromium.content.common.ContentSwitches;
 import org.chromium.content_public.browser.LoadUrlParams;
 import org.chromium.net.test.util.TestWebServer;
 
@@ -62,7 +63,8 @@
                                 arguments = {
                                     @Parameter.Argument(
                                         name = CommandLineFlags.Parameter.ADD_ARG,
-                                        stringArray = {AwSwitches.WEBVIEW_SANDBOXED_RENDERER})
+                                        stringArray = {AwSwitches.WEBVIEW_SANDBOXED_RENDERER,
+                                                ContentSwitches.IPC_SYNC_COMPOSITING})
             })})})
 public class AwTestBase
         extends BaseActivityInstrumentationTestCase<AwTestRunnerActivity> {
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwZoomTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwZoomTest.java
index ebd0b0e..9056c7f 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AwZoomTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwZoomTest.java
@@ -14,7 +14,6 @@
 import org.chromium.android_webview.AwSettings;
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.test.util.Feature;
-import org.chromium.base.test.util.parameter.ParameterizedTest;
 
 import java.util.Locale;
 import java.util.concurrent.Callable;
@@ -22,8 +21,6 @@
 /**
  * A test suite for zooming-related methods and settings.
  */
-// Run in single-process mode only. Blocked by rendering support crbug.com/526842.
-@ParameterizedTest.Set
 public class AwZoomTest extends AwTestBase {
     private TestAwContentsClient mContentsClient;
     private AwContents mAwContents;
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/ExternalVideoSurfaceContainerTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/ExternalVideoSurfaceContainerTest.java
index 71109c9..cadac0e 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/ExternalVideoSurfaceContainerTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/ExternalVideoSurfaceContainerTest.java
@@ -9,7 +9,6 @@
 
 import org.chromium.android_webview.test.util.VideoTestUtil;
 import org.chromium.base.test.util.Feature;
-import org.chromium.base.test.util.parameter.ParameterizedTest;
 import org.chromium.components.external_video_surface.ExternalVideoSurfaceContainer;
 import org.chromium.content.browser.ContentViewCore;
 import org.chromium.content.browser.test.util.CallbackHelper;
@@ -17,8 +16,6 @@
 /**
  * A test suite for ExternalVideoSurfaceContainerTest.
  */
-// Run in single-process mode only. Blocked by rendering support crbug.com/526842.
-@ParameterizedTest.Set
 public class ExternalVideoSurfaceContainerTest extends AwTestBase {
 
     // Callback helper to track the position/size of the external surface.
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/VisualStateTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/VisualStateTest.java
index bd18553..4dd877d 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/VisualStateTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/VisualStateTest.java
@@ -40,8 +40,6 @@
 /**
  * Visual state related tests.
  */
-// Run in single-process mode only. Blocked by rendering support crbug.com/526842.
-@ParameterizedTest.Set
 public class VisualStateTest extends AwTestBase {
     private static final String WAIT_FOR_JS_TEST_URL =
             "file:///android_asset/visual_state_waits_for_js_test.html";
@@ -193,6 +191,8 @@
 
     @Feature({"AndroidWebView"})
     @SmallTest
+    // Run in single-process mode only. Blocked by software draws support crbug.com/545611.
+    @ParameterizedTest.Set
     public void testOnPageCommitVisible() throws Throwable {
         // This test loads a page with a blue background color. It then waits for the DOM tree
         // in blink to contain the contents of the blue page (which happens when the onPageFinished
@@ -268,6 +268,8 @@
 
     @Feature({"AndroidWebView"})
     @SmallTest
+    // Run in single-process mode only. Blocked by software draws support crbug.com/545611.
+    @ParameterizedTest.Set
     public void testVisualStateCallbackWaitsForJs() throws Throwable {
         // This test checks that when a VisualStateCallback completes the results of executing
         // any block of JS prior to the time at which the callback was inserted will be visible
@@ -339,6 +341,8 @@
 
     @Feature({"AndroidWebView"})
     @SmallTest
+    // Run in single-process mode only. Blocked by software draws support crbug.com/545611.
+    @ParameterizedTest.Set
     public void testVisualStateCallbackFromJsDuringFullscreenTransitions() throws Throwable {
         // This test checks that VisualStateCallbacks are delivered correctly during
         // fullscreen transitions. It loads a page, clicks a button to enter fullscreen,
@@ -425,6 +429,8 @@
 
     @Feature({"AndroidWebView"})
     @SmallTest
+    // Run in single-process mode only. Blocked by software draws support crbug.com/545611.
+    @ParameterizedTest.Set
     public void testVisualStateCallbackWhenContainerViewDetached() throws Throwable {
         final CountDownLatch testFinishedSignal = new CountDownLatch(1);
 
diff --git a/build/android/lint_action.gypi b/build/android/lint_action.gypi
index e1adf1f8..f38e5c9b 100644
--- a/build/android/lint_action.gypi
+++ b/build/android/lint_action.gypi
@@ -18,17 +18,18 @@
     ],
     'android_manifest_path%': '<(DEPTH)/build/android/AndroidManifest.xml',
     'resource_dir%': '<(DEPTH)/build/android/ant/empty/res',
+    'suppressions_file%': '<(DEPTH)/build/android/lint/suppressions.xml',
   },
   'inputs': [
     '<(DEPTH)/build/android/gyp/util/build_utils.py',
     '<(DEPTH)/build/android/gyp/lint.py',
-    '<(DEPTH)/build/android/lint/suppressions.xml',
+    '<(suppressions_file)',
     '<(lint_jar_path)',
   ],
   'action': [
     'python', '<(DEPTH)/build/android/gyp/lint.py',
     '--lint-path=<(android_sdk_root)/tools/lint',
-    '--config-path=<(DEPTH)/build/android/lint/suppressions.xml',
+    '--config-path=<(suppressions_file)',
     '--processed-config-path=<(config_path)',
     '--manifest-path=<(android_manifest_path)',
     '--result-path=<(result_path)',
diff --git a/build/android/pylib/chrome_test_server_spawner.py b/build/android/pylib/chrome_test_server_spawner.py
index 99f4b5dc..a77a0c9 100644
--- a/build/android/pylib/chrome_test_server_spawner.py
+++ b/build/android/pylib/chrome_test_server_spawner.py
@@ -224,11 +224,18 @@
       command = [os.path.join(command, 'net', 'tools', 'testserver',
                               'testserver.py')] + self.command_line
     logging.info('Running: %s', command)
+
+    # Disable PYTHONUNBUFFERED because it has a bad interaction with the
+    # testserver. Remove once this interaction is fixed.
+    unbuf = os.environ.pop('PYTHONUNBUFFERED', None)
+
     # Pass DIR_SOURCE_ROOT as the child's working directory so that relative
     # paths in the arguments are resolved correctly.
     self.process = subprocess.Popen(
         command, preexec_fn=self._CloseUnnecessaryFDsForTestServerProcess,
         cwd=constants.DIR_SOURCE_ROOT)
+    if unbuf:
+      os.environ['PYTHONUNBUFFERED'] = unbuf
     if self.process:
       if self.pipe_out:
         self.is_ready = self._WaitToStartAndGetPortFromTestServer()
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni
index 39dab60b..d28d5a7d 100644
--- a/build/config/android/rules.gni
+++ b/build/config/android/rules.gni
@@ -1813,6 +1813,8 @@
 #     support executables.
 #   apk_name: The name of the produced apk. If unspecified, it uses the name
 #             of the unittests_dep target postfixed with "_apk"
+#   use_default_launcher: Whether the default activity (NativeUnitTestActivity)
+#     should be used for launching tests.
 #
 # Example
 #   unittest_apk("foo_unittests_apk") {
@@ -1850,12 +1852,15 @@
                              "android_manifest",
                            ])
     final_apk_path = "$root_build_dir/${apk_name}_apk/${apk_name}-debug.apk"
-    java_files = [
-      "//testing/android/native_test/java/src/org/chromium/native_test/NativeBrowserTestActivity.java",
-      "//testing/android/native_test/java/src/org/chromium/native_test/NativeTestActivity.java",
-      "//testing/android/native_test/java/src/org/chromium/native_test/NativeUnitTestActivity.java",
-      "//testing/android/native_test/java/src/org/chromium/native_test/NativeTestInstrumentationTestRunner.java",
-    ]
+
+    if (!defined(invoker.use_default_launcher) || invoker.use_default_launcher) {
+      java_files = [
+        "//testing/android/native_test/java/src/org/chromium/native_test/NativeBrowserTestActivity.java",
+        "//testing/android/native_test/java/src/org/chromium/native_test/NativeTestActivity.java",
+        "//testing/android/native_test/java/src/org/chromium/native_test/NativeUnitTestActivity.java",
+        "//testing/android/native_test/java/src/org/chromium/native_test/NativeTestInstrumentationTestRunner.java",
+      ]
+    }
     if (!defined(invoker.android_manifest)) {
       android_manifest =
           "//testing/android/native_test/java/AndroidManifest.xml"
diff --git a/build/config/features.gni b/build/config/features.gni
index e06daca..669ad5d 100644
--- a/build/config/features.gni
+++ b/build/config/features.gni
@@ -16,6 +16,7 @@
 
 import("//build/config/chrome_build.gni")
 import("//build/config/chromecast_build.gni")
+import("//build/config/headless_build.gni")
 if (is_android) {
   import("//build/config/android/config.gni")
 }
@@ -86,7 +87,7 @@
 
   enable_one_click_signin = is_win || is_mac || (is_linux && !is_chromeos)
 
-  enable_remoting = !is_ios && !is_android && !is_chromecast
+  enable_remoting = !is_ios && !is_android && !is_chromecast && !is_headless
 
   # Enable hole punching for the protected video.
   enable_video_hole = is_android
@@ -116,7 +117,7 @@
   # Note: this setting is ignored if is_chrome_branded.
   fieldtrial_testing_like_official_build = is_chrome_branded
 
-  use_cups = (is_desktop_linux || is_mac) && !is_chromecast
+  use_cups = (is_desktop_linux || is_mac) && !is_chromecast && !is_headless
 }
 
 # Additional dependent variables -----------------------------------------------
@@ -127,7 +128,7 @@
 cld_version = 2
 
 # libudev usage. This currently only affects the content layer.
-use_udev = is_linux && !is_chromecast
+use_udev = is_linux && !is_chromecast && !is_headless
 
 # Enable the spell checker.
 enable_spellcheck = !is_ios
@@ -136,11 +137,12 @@
 use_browser_spellchecker = is_android || is_mac
 
 # Enable basic printing support and UI.
-enable_basic_printing = !is_chromeos && !is_chromecast && !is_ios
+enable_basic_printing =
+    !is_chromeos && !is_chromecast && !is_ios && !is_headless
 
 # Enable printing with print preview. It does not imply
 # enable_basic_printing. It's possible to build Chrome with preview only.
-enable_print_preview = !is_android && !is_chromecast && !is_ios
+enable_print_preview = !is_android && !is_chromecast && !is_ios && !is_headless
 
 # Enables the use of CDMs in pepper plugins.
 enable_pepper_cdms =
@@ -159,7 +161,7 @@
 
 enable_web_speech = !is_android && !is_ios
 
-use_dbus = is_linux && !is_chromecast
+use_dbus = is_linux && !is_chromecast && !is_headless
 
 enable_extensions = !is_android && !is_ios
 
@@ -191,7 +193,7 @@
 
 # Option controlling the use of GConf (the classic GNOME configuration
 # system).
-use_gconf = is_linux && !is_chromeos && !is_chromecast
+use_gconf = is_linux && !is_chromeos && !is_chromecast && !is_headless
 
 # Whether to back up data before sync.
 enable_pre_sync_backup = is_win || is_mac || (is_linux && !is_chromeos)
@@ -199,3 +201,5 @@
 # Enable WebVR support by default on Android
 # Still requires command line flag to access API
 enable_webvr = is_android
+
+use_gio = is_desktop_linux && !is_headless
diff --git a/build/config/headless_build.gni b/build/config/headless_build.gni
new file mode 100644
index 0000000..1788b25a
--- /dev/null
+++ b/build/config/headless_build.gni
@@ -0,0 +1,8 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+declare_args() {
+  # Configure the build for headless mode. See crbug.com/546953.
+  is_headless = false
+}
diff --git a/build/config/ui.gni b/build/config/ui.gni
index e534366b..3acf6556 100644
--- a/build/config/ui.gni
+++ b/build/config/ui.gni
@@ -15,16 +15,17 @@
 # to set up feature flags.
 
 import("//build/config/chromecast_build.gni")
+import("//build/config/headless_build.gni")
 
 declare_args() {
   # Indicates if Ash is enabled. Ash is the Aura Shell which provides a
   # desktop-like environment for Aura. Requires use_aura = true
-  use_ash = (is_win || is_linux) && !is_chromecast
+  use_ash = (is_win || is_linux) && !is_chromecast && !is_headless
 
   # Indicates if Ozone is enabled. Ozone is a low-level library layer for Linux
   # that does not require X11. Enabling this feature disables use of glib, x11,
   # Pango, and Cairo. Default to false on non-Chromecast builds.
-  use_ozone = is_chromecast && !is_android
+  use_ozone = (is_chromecast || is_headless) && !is_android
 
   # Indicates if Aura is enabled. Aura is a low-level windowing library, sort
   # of a replacement for GDI or GTK.
diff --git a/build/linux/BUILD.gn b/build/linux/BUILD.gn
index 754859a..a66d86c 100644
--- a/build/linux/BUILD.gn
+++ b/build/linux/BUILD.gn
@@ -30,7 +30,7 @@
     functions = gypi_values.libbrlapi_functions
   }
 }
-if (is_desktop_linux) {
+if (use_gio) {
   pkg_config("gio_config") {
     packages = [ "gio-2.0" ]
 
diff --git a/build/toolchain/gcc_toolchain.gni b/build/toolchain/gcc_toolchain.gni
index eb343a1..8cffd491 100644
--- a/build/toolchain/gcc_toolchain.gni
+++ b/build/toolchain/gcc_toolchain.gni
@@ -60,7 +60,7 @@
 #  - strip
 #      Location of the strip executable. When specified, strip will be run on
 #      all shared libraries and executables as they are built. The pre-stripped
-#      artifacts will be put in lib.stripped/ and exe.stripped/.
+#      artifacts will be put in lib.unstripped/ and exe.unstripped/.
 #
 # Optional build argument contols.
 #
diff --git a/chrome/OWNERS b/chrome/OWNERS
index 5685f44..cf4468e 100644
--- a/chrome/OWNERS
+++ b/chrome/OWNERS
@@ -3,7 +3,6 @@
 
 # Reviewers:
 jochen@chromium.org
-jhawkins@chromium.org
 sky@chromium.org
 thakis@chromium.org
 thestig@chromium.org
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index 9c6dd33..f763781 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -411,7 +411,7 @@
   android_manifest = get_target_outputs(":chrome_public_apk_manifest")
   android_manifest = android_manifest[1]
   apk_name = "ChromePublic"
-  native_libs = [ "$root_build_dir/lib.stripped/libchrome_public.so" ]
+  native_libs = [ "libchrome_public.so" ]
   native_lib_version_rule = "//build/util:chrome_version_json"
 
   # Only attempt loading the library from the APK for 64 bit devices
@@ -419,7 +419,7 @@
   # approach falls to a minimal level -  http://crbug.com/390618.
   if (chromium_linker_supported &&
       (target_cpu == "arm64" || target_cpu == "x64")) {
-    load_library_from_apk = true
+    load_library_from_apk = chrome_public_apk_load_library_from_apk
   }
 
   deps = [
diff --git a/chrome/android/chrome_public_apk_tmpl.gni b/chrome/android/chrome_public_apk_tmpl.gni
index b068b39..2fa55576 100644
--- a/chrome/android/chrome_public_apk_tmpl.gni
+++ b/chrome/android/chrome_public_apk_tmpl.gni
@@ -4,6 +4,17 @@
 
 import("//build/config/android/rules.gni")
 
+declare_args() {
+  # Whether chrome_public_apk should use the crazy linker.
+  chrome_public_apk_use_chromium_linker = true
+
+  # Whether chrome_public_apk should use the relocation packer.
+  chrome_public_apk_use_relocation_packer = true
+
+  # Whether native libraries should be loaded from within the apk.
+  chrome_public_apk_load_library_from_apk = true
+}
+
 # GYP: //chrome/android/chrome_apk.gypi
 template("chrome_public_apk_tmpl") {
   forward_variables_from(invoker, "*")
@@ -20,11 +31,11 @@
     #]
 
     if (chromium_linker_supported) {
-      use_chromium_linker = true
+      use_chromium_linker = chrome_public_apk_use_chromium_linker
 
       # TODO: Enable packed relocations for x64. See: b/20532404
       if (current_cpu != "x64") {
-        enable_relocation_packing = true
+        enable_relocation_packing = chrome_public_apk_use_relocation_packer
       }
     }
   }
diff --git a/chrome/android/java/res/layout/web_notification.xml b/chrome/android/java/res/layout/web_notification.xml
index a0bb5a78..9036d2e 100644
--- a/chrome/android/java/res/layout/web_notification.xml
+++ b/chrome/android/java/res/layout/web_notification.xml
@@ -39,7 +39,6 @@
         android:layout_alignParentTop="true"
         android:layout_marginEnd="8dp"
         android:layout_marginStart="8dp"
-        android:layout_marginTop="8dp"
         android:singleLine="true"
         style="@style/WebNotificationTime"/>
 
@@ -50,7 +49,9 @@
         android:layout_toEndOf="@id/icon_frame"
         android:layout_alignParentEnd="true"
         android:layout_below="@id/title"
+        android:layout_marginBottom="-4dp"
         android:layout_marginEnd="8dp"
+        android:layout_marginTop="-4dp"
         android:singleLine="true"
         android:ellipsize="end"
         style="@style/WebNotificationBody"/>
diff --git a/chrome/android/java/res/layout/web_notification_big.xml b/chrome/android/java/res/layout/web_notification_big.xml
index d2ef2b9d..1d6b939 100644
--- a/chrome/android/java/res/layout/web_notification_big.xml
+++ b/chrome/android/java/res/layout/web_notification_big.xml
@@ -52,7 +52,7 @@
                 android:layout_alignParentTop="true"
                 android:singleLine="true"
                 android:ellipsize="end"
-                style="@style/WebNotificationTitleBig"/>
+                style="@style/WebNotificationTitle"/>
 
             <TextView
                 android:id="@+id/time"
@@ -63,7 +63,6 @@
                 android:layout_alignParentTop="true"
                 android:layout_marginEnd="8dp"
                 android:layout_marginStart="8dp"
-                android:layout_marginTop="8dp"
                 android:singleLine="true"
                 style="@style/WebNotificationTime"/>
 
@@ -73,9 +72,9 @@
             android:id="@+id/body"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
+            android:layout_marginBottom="5dp"
             android:layout_marginEnd="8dp"
-            android:layout_marginBottom="8dp"
-            android:maxLines="8"
+            android:layout_marginTop="-2dp"
             android:ellipsize="end"
             style="@style/WebNotificationBodyBig"/>
 
diff --git a/chrome/android/java/res/values-v17/styles.xml b/chrome/android/java/res/values-v17/styles.xml
index c2086d8..aedff9c 100644
--- a/chrome/android/java/res/values-v17/styles.xml
+++ b/chrome/android/java/res/values-v17/styles.xml
@@ -291,18 +291,10 @@
     <style name="WebNotificationTitle"
         parent="@style/TextAppearance.StatusBar.EventContent.Title">
         <item name="android:layout_marginStart">8dp</item>
-        <item name="android:layout_marginTop">2dp</item>
-    </style>
-    <style name="WebNotificationTitleBig"
-        parent="@style/TextAppearance.StatusBar.EventContent.Title">
-        <item name="android:layout_marginStart">8dp</item>
-        <item name="android:layout_marginTop">0dp</item>
     </style>
     <style name="WebNotificationBody"
         parent="@style/TextAppearance.StatusBar.EventContent.Line2">
-        <item name="android:layout_marginBottom">-2dp</item>
         <item name="android:layout_marginStart">8dp</item>
-        <item name="android:layout_marginTop">-2dp</item>
     </style>
     <style name="WebNotificationBodyBig"
         parent="@style/TextAppearance.StatusBar.EventContent">
diff --git a/chrome/android/java/res/values-v21/styles.xml b/chrome/android/java/res/values-v21/styles.xml
index 4dc93ed..37393d8 100644
--- a/chrome/android/java/res/values-v21/styles.xml
+++ b/chrome/android/java/res/values-v21/styles.xml
@@ -65,18 +65,10 @@
     <style name="WebNotificationTitle"
         parent="@android:style/TextAppearance.Material.Notification.Title">
         <item name="android:layout_marginStart">0dp</item>
-        <item name="android:layout_marginTop">4dp</item>
-    </style>
-    <style name="WebNotificationTitleBig"
-        parent="@android:style/TextAppearance.Material.Notification.Title">
-        <item name="android:layout_marginStart">0dp</item>
-        <item name="android:layout_marginTop">4dp</item>
     </style>
     <style name="WebNotificationBody"
         parent="@android:style/TextAppearance.Material.Notification.Line2">
-        <item name="android:layout_marginBottom">-1dp</item>
         <item name="android:layout_marginStart">0dp</item>
-        <item name="android:layout_marginTop">-1dp</item>
     </style>
     <style name="WebNotificationBodyBig"
         parent="@android:style/TextAppearance.Material.Notification">
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/CustomNotificationBuilder.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/CustomNotificationBuilder.java
index 6c4859c..56f0673 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/CustomNotificationBuilder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/CustomNotificationBuilder.java
@@ -12,6 +12,8 @@
 import android.support.v4.app.NotificationCompat;
 import android.support.v4.app.NotificationCompat.Action;
 import android.text.format.DateFormat;
+import android.util.DisplayMetrics;
+import android.util.TypedValue;
 import android.view.View;
 import android.widget.RemoteViews;
 
@@ -42,6 +44,24 @@
      */
     private static final int MAX_ACTION_BUTTONS = 3;
 
+    /**
+     * The maximum number of lines of body text for the expanded state. Fewer lines are used when
+     * the text is scaled up, with a minimum of one line.
+     */
+    private static final int MAX_BODY_LINES = 7;
+
+    /**
+     * The fontScale considered large for the purposes of layout.
+     */
+    private static final float FONT_SCALE_LARGE = 1.3f;
+
+    /**
+     * The maximum amount of padding (in dip units) that is applied around views that must have a
+     * flexible amount of padding. If the font size is scaled up the applied padding will be scaled
+     * down towards 0.
+     */
+    private static final int MAX_SCALABLE_PADDING_DIP = 3;
+
     private final Context mContext;
 
     private CharSequence mTitle;
@@ -67,6 +87,10 @@
         RemoteViews bigView =
                 new RemoteViews(mContext.getPackageName(), R.layout.web_notification_big);
 
+        float fontScale = mContext.getResources().getConfiguration().fontScale;
+        bigView.setInt(R.id.body, "setMaxLines", calculateMaxBodyLines(fontScale));
+        int scaledPadding =
+                calculateScaledPadding(fontScale, mContext.getResources().getDisplayMetrics());
         String time = DateFormat.getTimeFormat(mContext).format(new Date());
         for (RemoteViews view : new RemoteViews[] {compactView, bigView}) {
             view.setTextViewText(R.id.time, time);
@@ -74,6 +98,8 @@
             view.setTextViewText(R.id.body, mBody);
             view.setTextViewText(R.id.origin, mOrigin);
             view.setImageViewBitmap(R.id.icon, mLargeIcon);
+            view.setViewPadding(R.id.title, 0, scaledPadding, 0, 0);
+            view.setViewPadding(R.id.body, 0, scaledPadding, 0, scaledPadding);
         }
 
         if (!mActions.isEmpty()) {
@@ -191,4 +217,42 @@
         }
         return input;
     }
+
+    /**
+     * Scales down the maximum number of displayed lines in the body text if font scaling is greater
+     * than 1.0. Never scales up the number of lines, as on some devices the notification text is
+     * rendered in dp units (which do not scale) and additional lines could lead to cropping at the
+     * bottom of the notification.
+     *
+     * @param fontScale The current system font scaling factor.
+     * @return The number of lines to be displayed.
+     */
+    @VisibleForTesting
+    static int calculateMaxBodyLines(float fontScale) {
+        if (fontScale > 1.0f) {
+            return (int) Math.round(Math.ceil((1 / fontScale) * MAX_BODY_LINES));
+        }
+        return MAX_BODY_LINES;
+    }
+
+    /**
+     * Scales down the maximum amount of flexible padding to use if font scaling is over 1.0. Never
+     * scales up the amount of padding, as on some devices the notification text is rendered in dp
+     * units (which do not scale) and additional padding could lead to cropping at the bottom of the
+     * notification. Never scales the padding below zero.
+     *
+     * @param fontScale The current system font scaling factor.
+     * @param displayMetrics The display metrics for the current context.
+     * @return The amount of padding to be used, in pixels.
+     */
+    @VisibleForTesting
+    static int calculateScaledPadding(float fontScale, DisplayMetrics displayMetrics) {
+        float paddingScale = 1.0f;
+        if (fontScale > 1.0f) {
+            fontScale = Math.min(fontScale, FONT_SCALE_LARGE);
+            paddingScale = (FONT_SCALE_LARGE - fontScale) / (FONT_SCALE_LARGE - 1.0f);
+        }
+        return Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+                paddingScale * MAX_SCALABLE_PADDING_DIP, displayMetrics));
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/ToolbarProgressBar.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/ToolbarProgressBar.java
index e10e53f5..f7e600c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/ToolbarProgressBar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/ToolbarProgressBar.java
@@ -77,9 +77,7 @@
                         getWidth()));
 
                 if (getProgress() == mTargetProgress) {
-                    if (mTargetProgress == 1.0f && !mIsStarted) {
-                        postOnAnimationDelayed(mHideRunnable, mHidingDelayMs);
-                    }
+                    if (!mIsStarted) postOnAnimationDelayed(mHideRunnable, mHidingDelayMs);
                     mProgressAnimator.end();
                     return;
                 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/document/DocumentModeTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/document/DocumentModeTest.java
index d05933c..c596374 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/document/DocumentModeTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/document/DocumentModeTest.java
@@ -10,6 +10,7 @@
 import android.content.Intent;
 import android.net.Uri;
 import android.os.Build;
+import android.test.FlakyTest;
 import android.test.suitebuilder.annotation.MediumTest;
 import android.text.TextUtils;
 import android.view.View;
@@ -616,7 +617,11 @@
      * Tests that tabs opened via window.open() that have huge URLs load properly, even without the
      * URL in the Intent.
      */
-    @MediumTest
+    /*
+     * Bug: http://crbug/554487
+     * @MediumTest
+     */
+    @FlakyTest
     public void testBehemothUrlWindowOpen() throws Exception {
         Intent lastIntent = performNewWindowTest(
                 HUGE_URL_PAGE, "behemoth URL page", true, "behemoth result", true);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/feedback/ConnectivityTaskTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/feedback/ConnectivityTaskTest.java
index 4d67136..e4f6de0 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/feedback/ConnectivityTaskTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/feedback/ConnectivityTaskTest.java
@@ -18,6 +18,7 @@
 
 import java.util.HashMap;
 import java.util.Map;
+import java.util.concurrent.Callable;
 import java.util.concurrent.Semaphore;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicReference;
@@ -31,21 +32,23 @@
     @MediumTest
     @Feature({"Feedback"})
     public void testNormalCaseShouldWork() throws InterruptedException {
-        final AtomicReference<ConnectivityTask> task = new AtomicReference<>();
-        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
-            @Override
-            public void run() {
-                // Intentionally make HTTPS-connection fail which should result in NOT_CONNECTED.
-                ConnectivityChecker.overrideUrlsForTest(GENERATE_204_URL, GENERATE_404_URL);
-
-                task.set(ConnectivityTask.create(Profile.getLastUsedProfile(), TIMEOUT_MS, null));
-            }
-        });
+        final ConnectivityTask task = ThreadUtils.runOnUiThreadBlockingNoException(
+                new Callable<ConnectivityTask>() {
+                    @Override
+                    public ConnectivityTask call() {
+                        // Intentionally make HTTPS-connection fail which should result in
+                        // NOT_CONNECTED.
+                        ConnectivityChecker.overrideUrlsForTest(GENERATE_204_URL,
+                                GENERATE_404_URL);
+                        return ConnectivityTask.create(Profile.getLastUsedProfile(), TIMEOUT_MS,
+                                null);
+                    }
+                });
 
         boolean gotResult = CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
-                return task.get().isDone();
+                return task.isDone();
             }
         }, TIMEOUT_MS, RESULT_CHECK_INTERVAL_MS);
         assertTrue("Should be finished by now.", gotResult);
@@ -84,7 +87,6 @@
     @Feature({"Feedback"})
     public void testCallbackNormalCaseShouldWork() throws InterruptedException {
         final Semaphore semaphore = new Semaphore(0);
-        final AtomicReference<ConnectivityTask> task = new AtomicReference<>();
         final AtomicReference<FeedbackData> feedbackRef = new AtomicReference<>();
         final ConnectivityTask.ConnectivityResult callback =
                 new ConnectivityTask.ConnectivityResult() {
@@ -99,12 +101,9 @@
             public void run() {
                 // Intentionally make HTTPS-connection fail which should result in NOT_CONNECTED.
                 ConnectivityChecker.overrideUrlsForTest(GENERATE_204_URL, GENERATE_404_URL);
-
-                task.set(ConnectivityTask.create(
-                        Profile.getLastUsedProfile(), TIMEOUT_MS, callback));
+                ConnectivityTask.create(Profile.getLastUsedProfile(), TIMEOUT_MS, callback);
             }
         });
-
         if (!semaphore.tryAcquire(TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
             fail("Failed to acquire semaphore.");
         }
@@ -118,7 +117,6 @@
     public void testCallbackTwoTimeouts() throws InterruptedException {
         final int checkTimeoutMs = 100;
         final Semaphore semaphore = new Semaphore(0);
-        final AtomicReference<ConnectivityTask> task = new AtomicReference<>();
         final AtomicReference<FeedbackData> feedbackRef = new AtomicReference<>();
         final ConnectivityTask.ConnectivityResult callback =
                 new ConnectivityTask.ConnectivityResult() {
@@ -132,13 +130,11 @@
             @Override
             public void run() {
                 // Intentionally make HTTPS connections slow which should result in TIMEOUT.
-                ConnectivityChecker.overrideUrlsForTest(GENERATE_204_URL, GENERATE_204_SLOW_URL);
-
-                task.set(ConnectivityTask.create(
-                        Profile.getLastUsedProfile(), checkTimeoutMs, callback));
+                ConnectivityChecker.overrideUrlsForTest(GENERATE_204_URL,
+                        GENERATE_204_SLOW_URL);
+                ConnectivityTask.create(Profile.getLastUsedProfile(), checkTimeoutMs, callback);
             }
         });
-
         if (!semaphore.tryAcquire(TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
             fail("Failed to acquire semaphore.");
         }
@@ -152,21 +148,22 @@
     @MediumTest
     @Feature({"Feedback"})
     public void testTwoTimeoutsShouldFillInTheRest() throws InterruptedException {
-        final AtomicReference<ConnectivityTask> task = new AtomicReference<>();
-        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
-            @Override
-            public void run() {
-                // Intentionally make HTTPS connections slow which should result in UNKNOWN.
-                ConnectivityChecker.overrideUrlsForTest(GENERATE_204_URL, GENERATE_204_SLOW_URL);
-
-                task.set(ConnectivityTask.create(Profile.getLastUsedProfile(), TIMEOUT_MS, null));
-            }
-        });
-
+        final ConnectivityTask task = ThreadUtils.runOnUiThreadBlockingNoException(
+                new Callable<ConnectivityTask>() {
+                    @Override
+                    public ConnectivityTask call() {
+                        // Intentionally make HTTPS connections slow which should result in
+                        // UNKNOWN.
+                        ConnectivityChecker.overrideUrlsForTest(GENERATE_204_URL,
+                                GENERATE_204_SLOW_URL);
+                        return ConnectivityTask.create(Profile.getLastUsedProfile(), TIMEOUT_MS,
+                                null);
+                    }
+                });
         boolean gotResult = CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
-                return task.get().isDone();
+                return task.isDone();
             }
         }, TIMEOUT_MS / 5, RESULT_CHECK_INTERVAL_MS);
         assertFalse("Should not be finished by now.", gotResult);
@@ -203,14 +200,14 @@
         assertEquals("WiFi", map.get(ConnectivityTask.CONNECTION_TYPE_KEY));
     }
 
-    private static FeedbackData getResult(final AtomicReference<ConnectivityTask> task) {
-        final AtomicReference<FeedbackData> result = new AtomicReference<>();
-        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
-            @Override
-            public void run() {
-                result.set(task.get().get());
-            }
-        });
-        return result.get();
+    private static FeedbackData getResult(final ConnectivityTask task) {
+        final FeedbackData result = ThreadUtils.runOnUiThreadBlockingNoException(
+                new Callable<FeedbackData>() {
+                    @Override
+                    public FeedbackData call() {
+                        return task.get();
+                    }
+                });
+        return result;
     }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/CustomNotificationBuilderTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/CustomNotificationBuilderTest.java
index 069c1ee2..25f5254 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/CustomNotificationBuilderTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/CustomNotificationBuilderTest.java
@@ -12,6 +12,7 @@
 import android.graphics.Color;
 import android.test.InstrumentationTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
+import android.util.DisplayMetrics;
 import android.view.View;
 import android.widget.Button;
 import android.widget.ImageView;
@@ -147,6 +148,30 @@
         assertEquals(maxLength, ((Button) buttons.get(0)).getText().length());
     }
 
+    @SmallTest
+    @Feature({"Browser", "Notifications"})
+    public void testCalculateMaxBodyLines() {
+        assertEquals(7, CustomNotificationBuilder.calculateMaxBodyLines(-1000.0f));
+        assertEquals(7, CustomNotificationBuilder.calculateMaxBodyLines(0.5f));
+        assertEquals(7, CustomNotificationBuilder.calculateMaxBodyLines(1.0f));
+        assertEquals(4, CustomNotificationBuilder.calculateMaxBodyLines(2.0f));
+        assertEquals(1, CustomNotificationBuilder.calculateMaxBodyLines(1000.0f));
+    }
+
+    @SmallTest
+    @Feature({"Browser", "Notifications"})
+    public void testCalculateScaledPadding() {
+        DisplayMetrics metrics = new DisplayMetrics();
+        metrics.density = 10.0f;
+        assertEquals(30, CustomNotificationBuilder.calculateScaledPadding(-1000.0f, metrics));
+        assertEquals(30, CustomNotificationBuilder.calculateScaledPadding(0.5f, metrics));
+        assertEquals(30, CustomNotificationBuilder.calculateScaledPadding(1.0f, metrics));
+        assertEquals(20, CustomNotificationBuilder.calculateScaledPadding(1.1f, metrics));
+        assertEquals(10, CustomNotificationBuilder.calculateScaledPadding(1.2f, metrics));
+        assertEquals(0, CustomNotificationBuilder.calculateScaledPadding(1.3f, metrics));
+        assertEquals(0, CustomNotificationBuilder.calculateScaledPadding(1000.0f, metrics));
+    }
+
     /**
      * Finds a TextView with the given id in each of the given views, and checks that they all
      * contain the same text.
@@ -169,13 +194,13 @@
         return result;
     }
 
-    private PendingIntent createIntent(Context context, String action) {
+    private static PendingIntent createIntent(Context context, String action) {
         Intent intent = new Intent("CustomNotificationBuilderTest." + action);
         return PendingIntent.getBroadcast(
                 context, 0 /* requestCode */, intent, PendingIntent.FLAG_UPDATE_CURRENT);
     }
 
-    private String createString(char character, int length) {
+    private static String createString(char character, int length) {
         char[] chars = new char[length];
         Arrays.fill(chars, character);
         return new String(chars);
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index a1b51d01..e3aabdb 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -5489,11 +5489,11 @@
       <message name="IDS_FLAGS_ENABLE_FAST_UNLOAD_NAME" desc="Name of the 'Extensions on chrome:// URLs' lab">
         Enable fast tab/window close
       </message>
-      <message name="IDS_FLAGS_DISABLE_DISTILLER_IN_PRINT_PREVIEW_NAME" desc="Name of the 'disable simplify on print preview' lab">
-        Disable simplify page on print preview
+      <message name="IDS_FLAGS_ENABLE_DISTILLER_IN_PRINT_PREVIEW_NAME" desc="Name of the 'enable simplify on print preview' lab">
+        Enable simplify page on print preview
       </message>
-      <message name="IDS_FLAGS_DISABLE_DISTILLER_IN_PRINT_PREVIEW_DESCRIPTION" desc="Description of the 'disable simplify on print preview' lab">
-        Disable the simplify page check box on the print preview dialog
+      <message name="IDS_FLAGS_ENABLE_DISTILLER_IN_PRINT_PREVIEW_DESCRIPTION" desc="Description of the 'enable simplify on print preview' lab">
+        Enable the simplify page check box on the print preview dialog
       </message>
       <message name="IDS_FLAGS_ENABLE_APP_WINDOW_CONTROLS_NAME" desc="Name of the 'Enable 'window-controls' element' lab.">
         Enable 'window-controls' element
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp
index 2c1d566a..dae7ea8 100644
--- a/chrome/app/settings_strings.grdp
+++ b/chrome/app/settings_strings.grdp
@@ -131,6 +131,16 @@
     </message>
   </if>
 
+  <!-- Bluetooth Page -->
+  <if expr="chromeos">
+    <message name="IDS_SETTINGS_BLUETOOTH" desc="Name of the settings page which displays bluetooth device settings.">
+      Bluetooth
+    </message>
+    <message name="IDS_SETTINGS_BLUETOOTH_ENABLE" desc="Label for control to enable or disable bluetooth.">
+      Enable Bluetooth
+    </message>
+  </if>
+
   <!-- Certificate Manager Page -->
   <message name="IDS_SETTINGS_CERTIFICATE_MANAGER" desc="Name of the certificate manager page which allows users to modify SSL certificate settings.">
     Certificate manager
@@ -516,6 +526,18 @@
   <message name="IDS_SETTINGS_SITE_SETTINGS_RESET_MENU" desc="Label for the menu item to reset the permission for a particular site (make it ask you again next time).">
     Reset to ask
   </message>
+  <message name="IDS_SETTINGS_SITE_SETTINGS_USAGE" desc="The Usage header, used to group disk and battery usage information on the Site Details page.">
+    Usage
+  </message>
+  <message name="IDS_SETTINGS_SITE_SETTINGS_PERMISSIONS" desc="The Permissions header, used to group together permissions, such as Geolocation, on the Site Details page.">
+    Permissions
+  </message>
+  <message name="IDS_SETTINGS_SITE_SETTINGS_CLEAR_BUTTON" desc="The Clear and Reset button, used to clear all permissions and storage for a given site.">
+    Clear &amp; Reset
+  </message>
+  <message name="IDS_SETTINGS_SITE_SETTINGS_DELETE" desc="Label for the trashcan icon used to delete storage on the Site Details page.">
+    Delete
+  </message>
 
   <!-- Sign-in Page -->
   <message name="IDS_SETTINGS_SIGNIN" desc="Name of the settings page which manages Chrome's signed-in Google profile.">
diff --git a/chrome/browser/OWNERS b/chrome/browser/OWNERS
index bd753ac..31b80a8e 100644
--- a/chrome/browser/OWNERS
+++ b/chrome/browser/OWNERS
@@ -5,7 +5,6 @@
 per-file browser_resources.grd=bauerb@chromium.org
 per-file browser_resources.grd=dbeam@chromium.org
 per-file browser_resources.grd=estade@chromium.org
-per-file browser_resources.grd=jhawkins@chromium.org
 per-file browser_resources.grd=nkostylev@chromium.org
 per-file browser_resources.grd=pam@chromium.org
 per-file browser_resources.grd=xiyuan@chromium.org
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index c680e83..5cf72bf 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -78,6 +78,10 @@
 #include "extensions/common/switches.h"
 #endif
 
+#if defined(ENABLE_PRINT_PREVIEW)
+#include "chrome/browser/ui/webui/print_preview/print_preview_distiller.h"
+#endif
+
 #if defined(USE_OZONE)
 #include "ui/ozone/public/ozone_switches.h"
 #endif
@@ -108,7 +112,7 @@
       choices, arraysize(choices)
 #define FEATURE_VALUE_TYPE(feature)                                \
   FeatureEntry::FEATURE_VALUE, nullptr, nullptr, nullptr, nullptr, \
-      feature.name, nullptr, 3
+      &feature, nullptr, 3
 
 namespace {
 
@@ -1339,11 +1343,11 @@
      SINGLE_VALUE_TYPE(switches::kEnablePrivetV3)},
 #endif  // ENABLE_SERVICE_DISCOVERY
 #if defined(ENABLE_PRINT_PREVIEW)
-    {"disable-print-preview-simplify",
-     IDS_FLAGS_DISABLE_DISTILLER_IN_PRINT_PREVIEW_NAME,
-     IDS_FLAGS_DISABLE_DISTILLER_IN_PRINT_PREVIEW_DESCRIPTION,
+    {"enable-print-preview-simplify",
+     IDS_FLAGS_ENABLE_DISTILLER_IN_PRINT_PREVIEW_NAME,
+     IDS_FLAGS_ENABLE_DISTILLER_IN_PRINT_PREVIEW_DESCRIPTION,
      kOsDesktop,
-     SINGLE_VALUE_TYPE(switches::kDisablePrintPreviewSimplify)},
+     FEATURE_VALUE_TYPE(PrintPreviewDistiller::kFeature)},
 #endif
 #if defined(OS_WIN)
     {"enable-cloud-print-xps",
@@ -2288,7 +2292,7 @@
     case FeatureEntry::FEATURE_VALUE:
       DCHECK_EQ(3, e.num_choices);
       DCHECK(!e.choices);
-      DCHECK(e.feature_name);
+      DCHECK(e.feature);
       return true;
   }
   NOTREACHED();
@@ -2706,9 +2710,9 @@
       case FeatureEntry::FEATURE_VALUE:
         AddFeatureMapping(e.NameForChoice(0), std::string(), false,
                           &name_to_switch_map);
-        AddFeatureMapping(e.NameForChoice(1), e.feature_name, true,
+        AddFeatureMapping(e.NameForChoice(1), e.feature->name, true,
                           &name_to_switch_map);
-        AddFeatureMapping(e.NameForChoice(2), e.feature_name, false,
+        AddFeatureMapping(e.NameForChoice(2), e.feature->name, false,
                           &name_to_switch_map);
         break;
     }
diff --git a/chrome/browser/about_flags.h b/chrome/browser/about_flags.h
index dcc1d57..70fd6427 100644
--- a/chrome/browser/about_flags.h
+++ b/chrome/browser/about_flags.h
@@ -18,6 +18,7 @@
 class PrefService;
 
 namespace base {
+struct Feature;
 class ListValue;
 }
 
@@ -106,8 +107,8 @@
   const char* disable_command_line_switch;
   const char* disable_command_line_value;
 
-  // For FEATURE_VALUE, the name of the base::Feature this entry corresponds to.
-  const char* feature_name;
+  // For FEATURE_VALUE, the base::Feature this entry corresponds to.
+  const base::Feature* feature;
 
   // This is used if type is MULTI_VALUE.
   const Choice* choices;
diff --git a/chrome/browser/about_flags_unittest.cc b/chrome/browser/about_flags_unittest.cc
index e954497..8baff519 100644
--- a/chrome/browser/about_flags_unittest.cc
+++ b/chrome/browser/about_flags_unittest.cc
@@ -7,6 +7,7 @@
 #include <stdint.h>
 #include <utility>
 
+#include "base/feature_list.h"
 #include "base/files/file_path.h"
 #include "base/format_macros.h"
 #include "base/path_service.h"
@@ -230,6 +231,9 @@
   { IDS_PRODUCT_NAME, kMultiSwitch2, kValueForMultiSwitch2 },
 };
 
+const base::Feature kTestFeature{"FeatureName",
+                                 base::FEATURE_ENABLED_BY_DEFAULT};
+
 // The entries that are set for these tests. The 3rd entry is not supported on
 // the current platform, all others are.
 static FeatureEntry kEntries[] = {
@@ -259,7 +263,7 @@
     {kFlags7, IDS_PRODUCT_NAME, IDS_PRODUCT_NAME,
      0,  // Ends up being mapped to the current platform.
      FeatureEntry::FEATURE_VALUE, nullptr, nullptr, nullptr, nullptr,
-     "FeatureName", nullptr, 3},
+     &kTestFeature, nullptr, 3},
 };
 
 class AboutFlagsTest : public ::testing::Test {
diff --git a/chrome/browser/component_updater/chrome_component_updater_configurator.cc b/chrome/browser/component_updater/chrome_component_updater_configurator.cc
index 5b6cebf..eb0d7830 100644
--- a/chrome/browser/component_updater/chrome_component_updater_configurator.cc
+++ b/chrome/browser/component_updater/chrome_component_updater_configurator.cc
@@ -123,12 +123,16 @@
   return configurator_impl_.UseBackgroundDownloader();
 }
 
+// Returns a task runner to run blocking tasks. The task runner continues to run
+// after the browser shuts down, until the OS terminates the process. This
+// imposes certain requirements for the code using the task runner, such as
+// not accessing any global browser state while the code is running.
 scoped_refptr<base::SequencedTaskRunner>
 ChromeConfigurator::GetSequencedTaskRunner() const {
   return content::BrowserThread::GetBlockingPool()
       ->GetSequencedTaskRunnerWithShutdownBehavior(
           content::BrowserThread::GetBlockingPool()->GetSequenceToken(),
-          base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
+          base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN);
 }
 
 }  // namespace
diff --git a/chrome/browser/dom_distiller/profile_utils.cc b/chrome/browser/dom_distiller/profile_utils.cc
index b48fdfc..3eab2bb 100644
--- a/chrome/browser/dom_distiller/profile_utils.cc
+++ b/chrome/browser/dom_distiller/profile_utils.cc
@@ -17,15 +17,23 @@
 #include "components/dom_distiller/core/dom_distiller_switches.h"
 #include "components/dom_distiller/core/url_constants.h"
 
+#if defined(ENABLE_PRINT_PREVIEW)
+#include "chrome/browser/ui/webui/print_preview/print_preview_distiller.h"
+#endif  // defined(ENABLE_PRINT_PREVIEW)
+
 #if defined(OS_ANDROID)
 #include "chrome/browser/android/dom_distiller/distiller_ui_handle_android.h"
 #endif  // defined(OS_ANDROID)
 
 void RegisterDomDistillerViewerSource(Profile* profile) {
-  const base::CommandLine& command_line =
-      *base::CommandLine::ForCurrentProcess();
-  if (command_line.HasSwitch(switches::kEnableDomDistiller) ||
-      !command_line.HasSwitch(switches::kDisablePrintPreviewSimplify)) {
+  bool enabled_distiller = base::CommandLine::ForCurrentProcess()->HasSwitch(
+      switches::kEnableDomDistiller);
+#if defined(ENABLE_PRINT_PREVIEW)
+  if (PrintPreviewDistiller::IsEnabled())
+    enabled_distiller = true;
+#endif  // defined(ENABLE_PRINT_PREVIEW)
+
+  if (enabled_distiller) {
     dom_distiller::DomDistillerServiceFactory* dom_distiller_service_factory =
         dom_distiller::DomDistillerServiceFactory::GetInstance();
     // The LazyDomDistillerService deletes itself when the profile is destroyed.
diff --git a/chrome/browser/extensions/api/tabs/tabs_event_router.cc b/chrome/browser/extensions/api/tabs/tabs_event_router.cc
index 188e2e9c..5cc840f6 100644
--- a/chrome/browser/extensions/api/tabs/tabs_event_router.cc
+++ b/chrome/browser/extensions/api/tabs/tabs_event_router.cc
@@ -163,7 +163,7 @@
 
   int tab_id = ExtensionTabUtil::GetTabId(contents);
   DCHECK(tab_entries_.find(tab_id) == tab_entries_.end());
-  tab_entries_.set(tab_id, make_scoped_ptr(new TabEntry(this, contents)));
+  tab_entries_[tab_id] = make_scoped_ptr(new TabEntry(this, contents));
 }
 
 void TabsEventRouter::UnregisterForTabNotifications(WebContents* contents) {
@@ -474,7 +474,7 @@
 TabsEventRouter::TabEntry* TabsEventRouter::GetTabEntry(WebContents* contents) {
   const auto it = tab_entries_.find(ExtensionTabUtil::GetTabId(contents));
 
-  return it == tab_entries_.end() ? nullptr : it->second;
+  return it == tab_entries_.end() ? nullptr : it->second.get();
 }
 
 void TabsEventRouter::TabChangedAt(WebContents* contents,
diff --git a/chrome/browser/extensions/api/tabs/tabs_event_router.h b/chrome/browser/extensions/api/tabs/tabs_event_router.h
index f358193b..e285b31 100644
--- a/chrome/browser/extensions/api/tabs/tabs_event_router.h
+++ b/chrome/browser/extensions/api/tabs/tabs_event_router.h
@@ -5,9 +5,9 @@
 #ifndef CHROME_BROWSER_EXTENSIONS_API_TABS_TABS_EVENT_ROUTER_H_
 #define CHROME_BROWSER_EXTENSIONS_API_TABS_TABS_EVENT_ROUTER_H_
 
+#include <map>
 #include <string>
 
-#include "base/containers/scoped_ptr_map.h"
 #include "base/macros.h"
 #include "base/scoped_observer.h"
 #include "chrome/browser/extensions/api/tabs/tabs_api.h"
@@ -187,11 +187,11 @@
     DISALLOW_COPY_AND_ASSIGN(TabEntry);
   };
 
-  // Gets the TabEntry for the given |contents|. Returns linked_ptr<TabEntry>
-  // if found, NULL if not.
+  // Gets the TabEntry for the given |contents|. Returns TabEntry* if found,
+  // nullptr if not.
   TabEntry* GetTabEntry(content::WebContents* contents);
 
-  using TabEntryMap = base::ScopedPtrMap<int, scoped_ptr<TabEntry>>;
+  using TabEntryMap = std::map<int, scoped_ptr<TabEntry>>;
   TabEntryMap tab_entries_;
 
   // The main profile that owns this event router.
diff --git a/chrome/browser/extensions/api/tabs/windows_event_router.cc b/chrome/browser/extensions/api/tabs/windows_event_router.cc
index 8ef6ce4..0ccab14 100644
--- a/chrome/browser/extensions/api/tabs/windows_event_router.cc
+++ b/chrome/browser/extensions/api/tabs/windows_event_router.cc
@@ -173,15 +173,15 @@
           Profile::FromBrowserContext(app_window->browser_context())))
     return;
 
-  scoped_ptr<WindowController> controller =
-      app_windows_.take_and_erase(app_window->session_id().id());
+  app_windows_.erase(app_window->session_id().id());
 }
 
 void WindowsEventRouter::OnAppWindowActivated(
     extensions::AppWindow* app_window) {
   AppWindowMap::const_iterator iter =
       app_windows_.find(app_window->session_id().id());
-  OnActiveWindowChanged(iter != app_windows_.end() ? iter->second : nullptr);
+  OnActiveWindowChanged(iter != app_windows_.end() ? iter->second.get()
+                                                   : nullptr);
 }
 
 void WindowsEventRouter::OnWindowControllerAdded(
@@ -279,7 +279,7 @@
 void WindowsEventRouter::AddAppWindow(extensions::AppWindow* app_window) {
   scoped_ptr<AppWindowController> controller(new AppWindowController(
       app_window, make_scoped_ptr(new AppBaseWindow(app_window)), profile_));
-  app_windows_.set(app_window->session_id().id(), controller.Pass());
+  app_windows_[app_window->session_id().id()] = controller.Pass();
 }
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/tabs/windows_event_router.h b/chrome/browser/extensions/api/tabs/windows_event_router.h
index f02ca33..28f42351 100644
--- a/chrome/browser/extensions/api/tabs/windows_event_router.h
+++ b/chrome/browser/extensions/api/tabs/windows_event_router.h
@@ -5,10 +5,10 @@
 #ifndef CHROME_BROWSER_EXTENSIONS_API_TABS_WINDOWS_EVENT_ROUTER_H_
 #define CHROME_BROWSER_EXTENSIONS_API_TABS_WINDOWS_EVENT_ROUTER_H_
 
+#include <map>
 #include <string>
 
 #include "base/basictypes.h"
-#include "base/containers/scoped_ptr_map.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/scoped_observer.h"
 #include "chrome/browser/extensions/window_controller_list_observer.h"
@@ -90,7 +90,7 @@
   // windows.onFocusChanged events with the same windowId.
   int focused_window_id_;
 
-  typedef base::ScopedPtrMap<int, scoped_ptr<AppWindowController>> AppWindowMap;
+  using AppWindowMap = std::map<int, scoped_ptr<AppWindowController>>;
   // Map of application windows, the key to the session of the app window.
   AppWindowMap app_windows_;
 
diff --git a/chrome/browser/media/android/router/media_router_dialog_controller_android.cc b/chrome/browser/media/android/router/media_router_dialog_controller_android.cc
index 53ee2ea4..df69aee 100644
--- a/chrome/browser/media/android/router/media_router_dialog_controller_android.cc
+++ b/chrome/browser/media/android/router/media_router_dialog_controller_android.cc
@@ -10,6 +10,7 @@
 #include "chrome/browser/media/router/media_router.h"
 #include "chrome/browser/media/router/media_router_factory.h"
 #include "chrome/browser/media/router/media_source.h"
+#include "chrome/browser/media/router/presentation_request.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_delegate.h"
@@ -35,16 +36,17 @@
 
 void MediaRouterDialogControllerAndroid::OnSinkSelected(
     JNIEnv* env, jobject obj, jstring jsink_id) {
-  scoped_ptr<CreatePresentationSessionRequest>
-      request(TakePresentationRequest());
-
-  const std::string& source_id = request->media_source().id();
-  const GURL& origin = request->frame_url().GetOrigin();
+  scoped_ptr<CreatePresentationConnectionRequest> create_connection_request =
+      TakeCreateConnectionRequest();
+  const PresentationRequest& presentation_request =
+      create_connection_request->presentation_request();
+  const MediaSource::Id source_id = presentation_request.GetMediaSource().id();
+  const GURL origin = presentation_request.frame_url().GetOrigin();
 
   std::vector<MediaRouteResponseCallback> route_response_callbacks;
   route_response_callbacks.push_back(
-      base::Bind(&CreatePresentationSessionRequest::HandleRouteResponse,
-                 base::Passed(&request)));
+      base::Bind(&CreatePresentationConnectionRequest::HandleRouteResponse,
+                 base::Passed(&create_connection_request)));
 
   MediaRouter* router = MediaRouterFactory::GetApiForBrowserContext(
       initiator()->GetBrowserContext());
@@ -76,9 +78,8 @@
 }
 
 void MediaRouterDialogControllerAndroid::CancelPresentationRequest() {
-  scoped_ptr<CreatePresentationSessionRequest> request(
-      TakePresentationRequest());
-
+  scoped_ptr<CreatePresentationConnectionRequest> request =
+      TakeCreateConnectionRequest();
   DCHECK(request);
 
   request->InvokeErrorCallback(content::PresentationError(
@@ -109,10 +110,10 @@
 void MediaRouterDialogControllerAndroid::CreateMediaRouterDialog() {
   JNIEnv* env = base::android::AttachCurrentThread();
 
-  const MediaSource::Id& media_source_id =
-      presentation_request()->media_source().id();
+  const MediaSource::Id source_id =
+      create_connection_request()->presentation_request().GetMediaSource().id();
   ScopedJavaLocalRef<jstring> jsource_urn =
-      base::android::ConvertUTF8ToJavaString(env, media_source_id);
+      base::android::ConvertUTF8ToJavaString(env, source_id);
 
   // If it's a single route with the same source, show the controller dialog
   // instead of the device picker.
@@ -120,7 +121,7 @@
   // PresentationServiceDelegateImpl: if the route exists for the same frame
   // and tab, show the route controller dialog, if not, show the device picker.
   if (single_existing_route_.get() &&
-      single_existing_route_->media_source().id() == media_source_id) {
+      single_existing_route_->media_source().id() == source_id) {
     ScopedJavaLocalRef<jstring> jmedia_route_id =
         base::android::ConvertUTF8ToJavaString(
             env, single_existing_route_->media_route_id());
diff --git a/chrome/browser/media/router/create_presentation_session_request.cc b/chrome/browser/media/router/create_presentation_connection_request.cc
similarity index 69%
rename from chrome/browser/media/router/create_presentation_session_request.cc
rename to chrome/browser/media/router/create_presentation_connection_request.cc
index b3b4bc8..984f676 100644
--- a/chrome/browser/media/router/create_presentation_session_request.cc
+++ b/chrome/browser/media/router/create_presentation_connection_request.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/media/router/create_presentation_session_request.h"
+#include "chrome/browser/media/router/create_presentation_connection_request.h"
 
 #include "chrome/browser/media/router/media_source_helper.h"
 
@@ -11,13 +11,13 @@
 
 namespace media_router {
 
-CreatePresentationSessionRequest::CreatePresentationSessionRequest(
+CreatePresentationConnectionRequest::CreatePresentationConnectionRequest(
+    const RenderFrameHostId& render_frame_host_id,
     const std::string& presentation_url,
     const GURL& frame_url,
     const PresentationSessionSuccessCallback& success_cb,
     const PresentationSessionErrorCallback& error_cb)
-    : media_source_(MediaSourceForPresentationUrl(presentation_url)),
-      frame_url_(frame_url),
+    : presentation_request_(render_frame_host_id, presentation_url, frame_url),
       success_cb_(success_cb),
       error_cb_(error_cb),
       cb_invoked_(false) {
@@ -25,28 +25,27 @@
   DCHECK(!error_cb.is_null());
 }
 
-CreatePresentationSessionRequest::~CreatePresentationSessionRequest() {
+CreatePresentationConnectionRequest::~CreatePresentationConnectionRequest() {
   if (!cb_invoked_) {
     error_cb_.Run(content::PresentationError(
         content::PRESENTATION_ERROR_UNKNOWN, "Unknown error."));
   }
 }
 
-void CreatePresentationSessionRequest::InvokeSuccessCallback(
+void CreatePresentationConnectionRequest::InvokeSuccessCallback(
     const std::string& presentation_id,
     const MediaRoute::Id& route_id) {
   DCHECK(!cb_invoked_);
   if (!cb_invoked_) {
-    // Overwrite presentation ID.
     success_cb_.Run(
         content::PresentationSessionInfo(
-            PresentationUrlFromMediaSource(media_source_), presentation_id),
+            presentation_request_.presentation_url(), presentation_id),
         route_id);
     cb_invoked_ = true;
   }
 }
 
-void CreatePresentationSessionRequest::InvokeErrorCallback(
+void CreatePresentationConnectionRequest::InvokeErrorCallback(
     const content::PresentationError& error) {
   DCHECK(!cb_invoked_);
   if (!cb_invoked_) {
@@ -56,8 +55,8 @@
 }
 
 // static
-void CreatePresentationSessionRequest::HandleRouteResponse(
-    scoped_ptr<CreatePresentationSessionRequest> presentation_request,
+void CreatePresentationConnectionRequest::HandleRouteResponse(
+    scoped_ptr<CreatePresentationConnectionRequest> presentation_request,
     const MediaRoute* route,
     const std::string& presentation_id,
     const std::string& error) {
diff --git a/chrome/browser/media/router/create_presentation_session_request.h b/chrome/browser/media/router/create_presentation_connection_request.h
similarity index 72%
rename from chrome/browser/media/router/create_presentation_session_request.h
rename to chrome/browser/media/router/create_presentation_connection_request.h
index 9cebcb9..024dd1bc 100644
--- a/chrome/browser/media/router/create_presentation_session_request.h
+++ b/chrome/browser/media/router/create_presentation_connection_request.h
@@ -2,13 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_MEDIA_ROUTER_CREATE_PRESENTATION_SESSION_REQUEST_H_
-#define CHROME_BROWSER_MEDIA_ROUTER_CREATE_PRESENTATION_SESSION_REQUEST_H_
+#ifndef CHROME_BROWSER_MEDIA_ROUTER_CREATE_PRESENTATION_CONNECTION_REQUEST_H_
+#define CHROME_BROWSER_MEDIA_ROUTER_CREATE_PRESENTATION_CONNECTION_REQUEST_H_
 
 #include <string>
 
+#include "base/macros.h"
 #include "chrome/browser/media/router/media_route.h"
 #include "chrome/browser/media/router/media_source.h"
+#include "chrome/browser/media/router/presentation_request.h"
+#include "chrome/browser/media/router/render_frame_host_id.h"
 #include "content/public/browser/presentation_service_delegate.h"
 #include "url/gurl.h"
 
@@ -25,28 +28,29 @@
 // MediaRouterUI. |success_cb| will be invoked when create-session
 // succeeds, or |error_cb| will be invoked when create-session fails or
 // the UI closes.
-class CreatePresentationSessionRequest {
+class CreatePresentationConnectionRequest {
  public:
   using PresentationSessionSuccessCallback =
       base::Callback<void(const content::PresentationSessionInfo&,
                           const MediaRoute::Id&)>;
   using PresentationSessionErrorCallback =
-      content::PresentationServiceDelegate::PresentationSessionErrorCallback;
-
+      content::PresentationSessionErrorCallback;
   // |presentation_url|: The presentation URL of the request. Must be a valid
   //                     URL.
   // |frame_url|: The URL of the frame that initiated the presentation request.
   // |success_cb|: Callback to invoke when the request succeeds. Must be valid.
   // |erorr_cb|: Callback to invoke when the request fails. Must be valid.
-  CreatePresentationSessionRequest(
+  CreatePresentationConnectionRequest(
+      const RenderFrameHostId& render_frame_host_id,
       const std::string& presentation_url,
       const GURL& frame_url,
       const PresentationSessionSuccessCallback& success_cb,
       const PresentationSessionErrorCallback& error_cb);
-  ~CreatePresentationSessionRequest();
+  ~CreatePresentationConnectionRequest();
 
-  const MediaSource& media_source() const { return media_source_; }
-  const GURL& frame_url() const { return frame_url_; }
+  const PresentationRequest& presentation_request() const {
+    return presentation_request_;
+  }
 
   // Invokes |success_cb_| or |error_cb_| with the given arguments.
   // These functions can only be invoked once per instance. It is an error
@@ -57,21 +61,20 @@
 
   // Handle route creation/joining response by invoking the right callback.
   static void HandleRouteResponse(
-      scoped_ptr<CreatePresentationSessionRequest> presentation_request,
+      scoped_ptr<CreatePresentationConnectionRequest> presentation_request,
       const MediaRoute* route,
       const std::string& presentation_id,
       const std::string& error);
 
  private:
-  const MediaSource media_source_;
-  const GURL frame_url_;
+  const PresentationRequest presentation_request_;
   PresentationSessionSuccessCallback success_cb_;
   PresentationSessionErrorCallback error_cb_;
   bool cb_invoked_;
 
-  DISALLOW_COPY_AND_ASSIGN(CreatePresentationSessionRequest);
+  DISALLOW_COPY_AND_ASSIGN(CreatePresentationConnectionRequest);
 };
 
 }  // namespace media_router
 
-#endif  // CHROME_BROWSER_MEDIA_ROUTER_CREATE_PRESENTATION_SESSION_REQUEST_H_
+#endif  // CHROME_BROWSER_MEDIA_ROUTER_CREATE_PRESENTATION_CONNECTION_REQUEST_H_
diff --git a/chrome/browser/media/router/create_presentation_session_request_unittest.cc b/chrome/browser/media/router/create_presentation_connection_request_unittest.cc
similarity index 63%
rename from chrome/browser/media/router/create_presentation_session_request_unittest.cc
rename to chrome/browser/media/router/create_presentation_connection_request_unittest.cc
index 98614c67..7532529e 100644
--- a/chrome/browser/media/router/create_presentation_session_request_unittest.cc
+++ b/chrome/browser/media/router/create_presentation_connection_request_unittest.cc
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 #include "base/bind.h"
-#include "chrome/browser/media/router/create_presentation_session_request.h"
+#include "chrome/browser/media/router/create_presentation_connection_request.h"
 #include "chrome/browser/media/router/media_source_helper.h"
 #include "content/public/browser/presentation_service_delegate.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -13,16 +13,18 @@
 namespace {
 
 const char kPresentationUrl[] = "http://foo.com";
+const char kFrameUrl[] = "http://google.com";
 const char kPresentationId[] = "presentationId";
 const char kRouteId[] =
     "urn:x-org.chromium:media:route:presentationId/cast-sink1/http://foo.com";
 
 }  // namespace
 
-class CreatePresentationSessionRequestTest : public ::testing::Test {
+class CreatePresentationConnectionRequestTest : public ::testing::Test {
  public:
-  CreatePresentationSessionRequestTest() : cb_invoked_(false) {}
-  ~CreatePresentationSessionRequestTest() override {}
+  CreatePresentationConnectionRequestTest()
+      : cb_invoked_(false), render_frame_host_id_(1, 2) {}
+  ~CreatePresentationConnectionRequestTest() override {}
 
   void OnSuccess(const content::PresentationSessionInfo& expected_info,
                  const content::PresentationSessionInfo& actual_info,
@@ -49,52 +51,49 @@
   }
 
   bool cb_invoked_;
+  const RenderFrameHostId render_frame_host_id_;
 };
 
 // Test that the object's getters match the constructor parameters.
-TEST_F(CreatePresentationSessionRequestTest, Getters) {
-  GURL frame_url("http://frameUrl");
+TEST_F(CreatePresentationConnectionRequestTest, Getters) {
   content::PresentationError error(content::PRESENTATION_ERROR_UNKNOWN,
                                    "Unknown error.");
-  CreatePresentationSessionRequest request(
-      kPresentationUrl, frame_url,
-      base::Bind(&CreatePresentationSessionRequestTest::FailOnSuccess,
+  CreatePresentationConnectionRequest request(
+      render_frame_host_id_, kPresentationUrl, GURL(kFrameUrl),
+      base::Bind(&CreatePresentationConnectionRequestTest::FailOnSuccess,
                  base::Unretained(this)),
-      base::Bind(&CreatePresentationSessionRequestTest::OnError,
+      base::Bind(&CreatePresentationConnectionRequestTest::OnError,
                  base::Unretained(this), error));
-  EXPECT_EQ(frame_url, request.frame_url());
-  EXPECT_EQ(kPresentationUrl,
-            PresentationUrlFromMediaSource(request.media_source()));
+
+  PresentationRequest presentation_request(render_frame_host_id_,
+                                           kPresentationUrl, GURL(kFrameUrl));
+  EXPECT_TRUE(request.presentation_request().Equals(presentation_request));
   // Since we didn't explicitly call Invoke*, the error callback will be
   // invoked when |request| is destroyed.
 }
 
-TEST_F(CreatePresentationSessionRequestTest, SuccessCallback) {
-  GURL frame_url("http://frameUrl");
+TEST_F(CreatePresentationConnectionRequestTest, SuccessCallback) {
   content::PresentationSessionInfo session_info(kPresentationUrl,
                                                 kPresentationId);
-  CreatePresentationSessionRequest request(
-      kPresentationUrl, frame_url,
-      base::Bind(&CreatePresentationSessionRequestTest::OnSuccess,
+  CreatePresentationConnectionRequest request(
+      render_frame_host_id_, kPresentationUrl, GURL(kFrameUrl),
+      base::Bind(&CreatePresentationConnectionRequestTest::OnSuccess,
                  base::Unretained(this), session_info),
-      base::Bind(&CreatePresentationSessionRequestTest::FailOnError,
+      base::Bind(&CreatePresentationConnectionRequestTest::FailOnError,
                  base::Unretained(this)));
   request.InvokeSuccessCallback(kPresentationId, kRouteId);
   EXPECT_TRUE(cb_invoked_);
 }
 
-TEST_F(CreatePresentationSessionRequestTest, ErrorCallback) {
-  GURL frame_url("http://frameUrl");
-  content::PresentationSessionInfo session_info(kPresentationUrl,
-                                                kPresentationId);
+TEST_F(CreatePresentationConnectionRequestTest, ErrorCallback) {
   content::PresentationError error(
       content::PRESENTATION_ERROR_SESSION_REQUEST_CANCELLED,
       "This is an error message");
-  CreatePresentationSessionRequest request(
-      kPresentationUrl, frame_url,
-      base::Bind(&CreatePresentationSessionRequestTest::FailOnSuccess,
+  CreatePresentationConnectionRequest request(
+      render_frame_host_id_, kPresentationUrl, GURL(kFrameUrl),
+      base::Bind(&CreatePresentationConnectionRequestTest::FailOnSuccess,
                  base::Unretained(this)),
-      base::Bind(&CreatePresentationSessionRequestTest::OnError,
+      base::Bind(&CreatePresentationConnectionRequestTest::OnError,
                  base::Unretained(this), error));
   request.InvokeErrorCallback(error);
   EXPECT_TRUE(cb_invoked_);
diff --git a/chrome/browser/media/router/media_router.gypi b/chrome/browser/media/router/media_router.gypi
index 32089b1..5e27de5 100644
--- a/chrome/browser/media/router/media_router.gypi
+++ b/chrome/browser/media/router/media_router.gypi
@@ -6,8 +6,8 @@
   'variables': {
     # File lists shared with GN build.
     'media_router_sources': [
-      'create_presentation_session_request.cc',
-      'create_presentation_session_request.h',
+      'create_presentation_connection_request.cc',
+      'create_presentation_connection_request.h',
       'issue.cc',
       'issue.h',
       'issue_manager.cc',
@@ -39,12 +39,15 @@
       'presentation_connection_state_observer.h',
       'presentation_media_sinks_observer.cc',
       'presentation_media_sinks_observer.h',
+      'presentation_request.cc',
+      'presentation_request.h',
       'presentation_service_delegate_impl.cc',
       'presentation_service_delegate_impl.h',
       'presentation_session_messages_observer.cc',
       'presentation_session_messages_observer.h',
       'presentation_session_state_observer.cc',
       'presentation_session_state_observer.h',
+      'render_frame_host_id.h',
     ],
     # Files that are only needed on desktop builds
     'media_router_non_android_sources': [
diff --git a/chrome/browser/media/router/media_router_dialog_controller.cc b/chrome/browser/media/router/media_router_dialog_controller.cc
index f363730..2f0583d 100644
--- a/chrome/browser/media/router/media_router_dialog_controller.cc
+++ b/chrome/browser/media/router/media_router_dialog_controller.cc
@@ -73,14 +73,14 @@
 }
 
 bool MediaRouterDialogController::ShowMediaRouterDialogForPresentation(
-    scoped_ptr<CreatePresentationSessionRequest> request) {
+    scoped_ptr<CreatePresentationConnectionRequest> request) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
   // Check if the media router dialog exists for |initiator| and return if so.
   if (IsShowingMediaRouterDialog())
     return false;
 
-  presentation_request_ = request.Pass();
+  create_connection_request_ = request.Pass();
   CreateMediaRouterDialog();
 
   // Show the initiator holding the existing media router dialog.
@@ -114,14 +114,14 @@
   initiator_->GetDelegate()->ActivateContents(initiator_);
 }
 
-scoped_ptr<CreatePresentationSessionRequest>
-MediaRouterDialogController::TakePresentationRequest() {
-  return presentation_request_.Pass();
+scoped_ptr<CreatePresentationConnectionRequest>
+MediaRouterDialogController::TakeCreateConnectionRequest() {
+  return create_connection_request_.Pass();
 }
 
 void MediaRouterDialogController::Reset() {
   initiator_observer_.reset();
-  presentation_request_.reset();
+  create_connection_request_.reset();
 }
 
 }  // namespace media_router
diff --git a/chrome/browser/media/router/media_router_dialog_controller.h b/chrome/browser/media/router/media_router_dialog_controller.h
index 40dce80f..4c6b26c 100644
--- a/chrome/browser/media/router/media_router_dialog_controller.h
+++ b/chrome/browser/media/router/media_router_dialog_controller.h
@@ -10,7 +10,7 @@
 #include "base/macros.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/threading/thread_checker.h"
-#include "chrome/browser/media/router/create_presentation_session_request.h"
+#include "chrome/browser/media/router/create_presentation_connection_request.h"
 #include "content/public/browser/web_contents_observer.h"
 
 namespace content {
@@ -40,7 +40,7 @@
   // If the dialog already exists, brings it to the front but doesn't change the
   // dialog with |request|, returns false and |request| is deleted.
   bool ShowMediaRouterDialogForPresentation(
-      scoped_ptr<CreatePresentationSessionRequest> request);
+      scoped_ptr<CreatePresentationConnectionRequest> request);
 
   // Shows the media router dialog modal to |initiator_|.
   // Creates the dialog if it did not exist prior to this call, returns true.
@@ -62,13 +62,14 @@
   // Activates the WebContents that initiated the dialog, e.g. focuses the tab.
   void ActivateInitiatorWebContents();
 
-  // Passes the ownership of the CreatePresentationSessionRequest to the caller.
-  scoped_ptr<CreatePresentationSessionRequest> TakePresentationRequest();
+  // Passes the ownership of the CreatePresentationConnectionRequest to the
+  // caller.
+  scoped_ptr<CreatePresentationConnectionRequest> TakeCreateConnectionRequest();
 
-  // Returns the CreatePresentationSessionRequest to the caller but keeps the
+  // Returns the CreatePresentationConnectionRequest to the caller but keeps the
   // ownership with the MediaRouterDialogController.
-  const CreatePresentationSessionRequest* presentation_request() const {
-    return presentation_request_.get();
+  const CreatePresentationConnectionRequest* create_connection_request() const {
+    return create_connection_request_.get();
   }
 
   // Returns the WebContents that initiated showing the dialog.
@@ -94,7 +95,7 @@
   // Data for dialogs created at the request of the Presentation API.
   // Passed from the caller via ShowMediaRouterDialogForPresentation to the
   // dialog when it is initialized.
-  scoped_ptr<CreatePresentationSessionRequest> presentation_request_;
+  scoped_ptr<CreatePresentationConnectionRequest> create_connection_request_;
 
   DISALLOW_COPY_AND_ASSIGN(MediaRouterDialogController);
 };
diff --git a/chrome/browser/media/router/presentation_request.cc b/chrome/browser/media/router/presentation_request.cc
new file mode 100644
index 0000000..1c6df557
--- /dev/null
+++ b/chrome/browser/media/router/presentation_request.cc
@@ -0,0 +1,31 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/media/router/presentation_request.h"
+
+#include "chrome/browser/media/router/media_source_helper.h"
+
+namespace media_router {
+
+PresentationRequest::PresentationRequest(
+    const RenderFrameHostId& render_frame_host_id,
+    const std::string& presentation_url,
+    const GURL& frame_url)
+    : render_frame_host_id_(render_frame_host_id),
+      presentation_url_(presentation_url),
+      frame_url_(frame_url) {}
+
+PresentationRequest::~PresentationRequest() = default;
+
+bool PresentationRequest::Equals(const PresentationRequest& other) const {
+  return render_frame_host_id_ == other.render_frame_host_id_ &&
+         presentation_url_ == other.presentation_url_ &&
+         frame_url_ == other.frame_url_;
+}
+
+MediaSource PresentationRequest::GetMediaSource() const {
+  return MediaSourceForPresentationUrl(presentation_url_);
+}
+
+}  // namespace media_router
diff --git a/chrome/browser/media/router/presentation_request.h b/chrome/browser/media/router/presentation_request.h
new file mode 100644
index 0000000..a37189f
--- /dev/null
+++ b/chrome/browser/media/router/presentation_request.h
@@ -0,0 +1,49 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_MEDIA_ROUTER_PRESENTATION_REQUEST_H_
+#define CHROME_BROWSER_MEDIA_ROUTER_PRESENTATION_REQUEST_H_
+
+#include <string>
+
+#include "chrome/browser/media/router/media_source.h"
+#include "chrome/browser/media/router/render_frame_host_id.h"
+#include "url/gurl.h"
+
+namespace media_router {
+
+// Represents a presentation request made from a render frame. Contains the
+// presentation URL of the request, and information on the originating frame.
+class PresentationRequest {
+ public:
+  PresentationRequest(const RenderFrameHostId& render_frame_host_id,
+                      const std::string& presentation_url,
+                      const GURL& frame_url);
+  ~PresentationRequest();
+
+  bool Equals(const PresentationRequest& other) const;
+
+  // Helper method to get the MediaSource for |presentation_url_|.
+  MediaSource GetMediaSource() const;
+
+  const RenderFrameHostId& render_frame_host_id() const {
+    return render_frame_host_id_;
+  }
+  const std::string& presentation_url() const { return presentation_url_; }
+  const GURL& frame_url() const { return frame_url_; }
+
+ private:
+  // ID of RenderFrameHost that initiated the request.
+  const RenderFrameHostId render_frame_host_id_;
+
+  // URL of presentation.
+  const std::string presentation_url_;
+
+  // URL of frame from which the request was initiated.
+  const GURL frame_url_;
+};
+
+}  // namespace media_router
+
+#endif  // CHROME_BROWSER_MEDIA_ROUTER_PRESENTATION_REQUEST_H_
diff --git a/chrome/browser/media/router/presentation_request_unittest.cc b/chrome/browser/media/router/presentation_request_unittest.cc
new file mode 100644
index 0000000..7d21a5e
--- /dev/null
+++ b/chrome/browser/media/router/presentation_request_unittest.cc
@@ -0,0 +1,39 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/media/router/presentation_request.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace media_router {
+
+TEST(PresentationRequestTest, Equals) {
+  PresentationRequest request1(RenderFrameHostId(1, 2),
+                               "http://presentationUrl",
+                               GURL("http://frameUrl"));
+
+  // Frame IDs are different.
+  PresentationRequest request2(RenderFrameHostId(3, 4),
+                               "http://presentationUrl",
+                               GURL("http://frameUrl"));
+  EXPECT_FALSE(request1.Equals(request2));
+
+  // Presentation URLs are different.
+  PresentationRequest request3(RenderFrameHostId(1, 2),
+                               "http://anotherPresentationUrl",
+                               GURL("http://frameUrl"));
+  EXPECT_FALSE(request1.Equals(request3));
+
+  // Frame URLs are different.
+  PresentationRequest request4(RenderFrameHostId(1, 2),
+                               "http://presentationUrl",
+                               GURL("http://anotherFrameUrl"));
+  EXPECT_FALSE(request1.Equals(request4));
+
+  PresentationRequest request5(RenderFrameHostId(1, 2),
+                               "http://presentationUrl",
+                               GURL("http://frameUrl"));
+  EXPECT_TRUE(request1.Equals(request5));
+}
+
+}  // namespace media_router
diff --git a/chrome/browser/media/router/presentation_service_delegate_impl.cc b/chrome/browser/media/router/presentation_service_delegate_impl.cc
index e45b394..d2228e53 100644
--- a/chrome/browser/media/router/presentation_service_delegate_impl.cc
+++ b/chrome/browser/media/router/presentation_service_delegate_impl.cc
@@ -11,7 +11,7 @@
 #include "base/guid.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
-#include "chrome/browser/media/router/create_presentation_session_request.h"
+#include "chrome/browser/media/router/create_presentation_connection_request.h"
 #include "chrome/browser/media/router/media_route.h"
 #include "chrome/browser/media/router/media_router.h"
 #include "chrome/browser/media/router/media_router_dialog_controller.h"
@@ -37,10 +37,6 @@
 namespace {
 
 using DelegateObserver = content::PresentationServiceDelegate::Observer;
-using PresentationSessionErrorCallback =
-    content::PresentationServiceDelegate::PresentationSessionErrorCallback;
-using PresentationSessionSuccessCallback =
-    content::PresentationServiceDelegate::PresentationSessionSuccessCallback;
 
 // Returns the unique identifier for the supplied RenderFrameHost.
 RenderFrameHostId GetRenderFrameHostId(RenderFrameHost* render_frame_host) {
@@ -84,6 +80,7 @@
   void ListenForSessionMessages(
       const content::PresentationSessionInfo& session,
       const content::PresentationSessionMessageCallback& message_cb);
+
   void Reset();
 
   const MediaRoute::Id GetRouteId(const std::string& presentation_id) const;
@@ -91,7 +88,6 @@
   void OnPresentationSessionClosed(const std::string& presentation_id);
 
   void OnPresentationSessionStarted(
-      bool is_default_presentation,
       const content::PresentationSessionInfo& session,
       const MediaRoute::Id& route_id);
   void OnPresentationServiceDelegateDestroyed() const;
@@ -135,15 +131,12 @@
 }
 
 void PresentationFrame::OnPresentationSessionStarted(
-    bool is_default_presentation,
     const content::PresentationSessionInfo& session,
     const MediaRoute::Id& route_id) {
   presentation_id_to_route_id_[session.presentation_id] = route_id;
   route_id_to_presentation_.Add(route_id, session);
   if (session_state_observer_)
     session_state_observer_->OnPresentationSessionConnected(route_id);
-  if (is_default_presentation && delegate_observer_)
-    delegate_observer_->OnDefaultPresentationStarted(session);
 }
 
 void PresentationFrame::OnPresentationSessionClosed(
@@ -211,6 +204,7 @@
   sinks_observer_.reset();
   if (session_state_observer_)
     session_state_observer_->Reset();
+
   session_messages_observers_.clear();
 }
 
@@ -265,9 +259,23 @@
       const RenderFrameHostId& render_frame_host_id,
       const content::PresentationSessionInfo& session,
       const content::PresentationSessionMessageCallback& message_cb);
+
+  // Sets or clears the default presentation request and callback for the given
+  // frame. Also sets / clears the default presentation requests for the owning
+  // tab WebContents.
+  void SetDefaultPresentationUrl(
+      const RenderFrameHostId& render_frame_host_id,
+      const std::string& default_presentation_url,
+      const content::PresentationSessionStartedCallback& callback);
   void AddDelegateObserver(const RenderFrameHostId& render_frame_host_id,
                            DelegateObserver* observer);
   void RemoveDelegateObserver(const RenderFrameHostId& render_frame_host_id);
+  void AddDefaultPresentationRequestObserver(
+      PresentationServiceDelegateImpl::DefaultPresentationRequestObserver*
+          observer);
+  void RemoveDefaultPresentationRequestObserver(
+      PresentationServiceDelegateImpl::DefaultPresentationRequestObserver*
+          observer);
   void Reset(const RenderFrameHostId& render_frame_host_id);
   bool HasScreenAvailabilityListenerForTest(
       const RenderFrameHostId& render_frame_host_id,
@@ -276,7 +284,10 @@
 
   void OnPresentationSessionStarted(
       const RenderFrameHostId& render_frame_host_id,
-      bool is_default_presentation,
+      const content::PresentationSessionInfo& session,
+      const MediaRoute::Id& route_id);
+  void OnDefaultPresentationSessionStarted(
+      const PresentationRequest& request,
       const content::PresentationSessionInfo& session,
       const MediaRoute::Id& route_id);
 
@@ -288,15 +299,44 @@
   const std::vector<MediaRoute::Id> GetRouteIds(
       const RenderFrameHostId& render_frame_host_id) const;
 
+  const PresentationRequest* default_presentation_request() const {
+    return default_presentation_request_.get();
+  }
+
  private:
   PresentationFrame* GetOrAddPresentationFrame(
       const RenderFrameHostId& render_frame_host_id);
 
+  // Sets the default presentation request for the owning WebContents and
+  // notifies observers of changes.
+  void SetDefaultPresentationRequest(
+      const PresentationRequest& default_presentation_request);
+
+  // Clears the default presentation request for the owning WebContents and
+  // notifies observers of changes. Also resets
+  // |default_presentation_started_callback_|.
+  void ClearDefaultPresentationRequest();
+
+  bool IsMainFrame(const RenderFrameHostId& render_frame_host_id) const;
+
   // Maps a frame identifier to a PresentationFrame object for frames
   // that are using presentation API.
   base::ScopedPtrHashMap<RenderFrameHostId, scoped_ptr<PresentationFrame>>
       presentation_frames_;
 
+  // Default presentation request for the owning tab WebContents.
+  scoped_ptr<PresentationRequest> default_presentation_request_;
+
+  // Callback to invoke when default presentation has started.
+  content::PresentationSessionStartedCallback
+      default_presentation_started_callback_;
+
+  // References to the observers listening for changes to this tab WebContent's
+  // default presentation.
+  base::ObserverList<
+      PresentationServiceDelegateImpl::DefaultPresentationRequestObserver>
+      default_presentation_request_observers_;
+
   // References to the owning WebContents, and the corresponding MediaRouter.
   MediaRouter* router_;
   content::WebContents* web_contents_;
@@ -317,13 +357,26 @@
 
 void PresentationFrameManager::OnPresentationSessionStarted(
     const RenderFrameHostId& render_frame_host_id,
-    bool is_default_presentation,
     const content::PresentationSessionInfo& session,
     const MediaRoute::Id& route_id) {
   auto presentation_frame = presentation_frames_.get(render_frame_host_id);
   if (presentation_frame)
-    presentation_frame->OnPresentationSessionStarted(is_default_presentation,
-                                                     session, route_id);
+    presentation_frame->OnPresentationSessionStarted(session, route_id);
+}
+
+void PresentationFrameManager::OnDefaultPresentationSessionStarted(
+    const PresentationRequest& request,
+    const content::PresentationSessionInfo& session,
+    const MediaRoute::Id& route_id) {
+  auto presentation_frame =
+      presentation_frames_.get(request.render_frame_host_id());
+  if (presentation_frame)
+    presentation_frame->OnPresentationSessionStarted(session, route_id);
+
+  if (default_presentation_request_ &&
+      default_presentation_request_->Equals(request)) {
+    default_presentation_started_callback_.Run(session);
+  }
 }
 
 void PresentationFrameManager::OnPresentationSessionClosed(
@@ -397,6 +450,25 @@
   presentation_frame->ListenForSessionMessages(session, message_cb);
 }
 
+void PresentationFrameManager::SetDefaultPresentationUrl(
+    const RenderFrameHostId& render_frame_host_id,
+    const std::string& default_presentation_url,
+    const content::PresentationSessionStartedCallback& callback) {
+  if (!IsMainFrame(render_frame_host_id))
+    return;
+
+  if (default_presentation_url.empty()) {
+    ClearDefaultPresentationRequest();
+  } else {
+    DCHECK(!callback.is_null());
+    GURL frame_url(GetLastCommittedURLForFrame(render_frame_host_id));
+    PresentationRequest request(render_frame_host_id, default_presentation_url,
+                                frame_url);
+    default_presentation_started_callback_ = callback;
+    SetDefaultPresentationRequest(request);
+  }
+}
+
 void PresentationFrameManager::AddDelegateObserver(
     const RenderFrameHostId& render_frame_host_id,
     DelegateObserver* observer) {
@@ -413,11 +485,29 @@
   }
 }
 
+void PresentationFrameManager::AddDefaultPresentationRequestObserver(
+    PresentationServiceDelegateImpl::DefaultPresentationRequestObserver*
+        observer) {
+  default_presentation_request_observers_.AddObserver(observer);
+}
+
+void PresentationFrameManager::RemoveDefaultPresentationRequestObserver(
+    PresentationServiceDelegateImpl::DefaultPresentationRequestObserver*
+        observer) {
+  default_presentation_request_observers_.RemoveObserver(observer);
+}
+
 void PresentationFrameManager::Reset(
     const RenderFrameHostId& render_frame_host_id) {
   auto presentation_frame = presentation_frames_.get(render_frame_host_id);
   if (presentation_frame)
     presentation_frame->Reset();
+
+  if (default_presentation_request_ &&
+      render_frame_host_id ==
+          default_presentation_request_->render_frame_host_id()) {
+    ClearDefaultPresentationRequest();
+  }
 }
 
 PresentationFrame* PresentationFrameManager::GetOrAddPresentationFrame(
@@ -431,6 +521,37 @@
   return presentation_frames_.get(render_frame_host_id);
 }
 
+void PresentationFrameManager::ClearDefaultPresentationRequest() {
+  default_presentation_started_callback_.Reset();
+  if (!default_presentation_request_)
+    return;
+
+  default_presentation_request_.reset();
+  FOR_EACH_OBSERVER(
+      PresentationServiceDelegateImpl::DefaultPresentationRequestObserver,
+      default_presentation_request_observers_, OnDefaultPresentationRemoved());
+}
+
+bool PresentationFrameManager::IsMainFrame(
+    const RenderFrameHostId& render_frame_host_id) const {
+  RenderFrameHost* main_frame = web_contents_->GetMainFrame();
+  return main_frame && GetRenderFrameHostId(main_frame) == render_frame_host_id;
+}
+
+void PresentationFrameManager::SetDefaultPresentationRequest(
+    const PresentationRequest& default_presentation_request) {
+  if (default_presentation_request_ &&
+      default_presentation_request_->Equals(default_presentation_request))
+    return;
+
+  default_presentation_request_.reset(
+      new PresentationRequest(default_presentation_request));
+  FOR_EACH_OBSERVER(
+      PresentationServiceDelegateImpl::DefaultPresentationRequestObserver,
+      default_presentation_request_observers_,
+      OnDefaultPresentationChanged(*default_presentation_request_));
+}
+
 void PresentationFrameManager::SetMediaRouterForTest(MediaRouter* router) {
   router_ = router;
 }
@@ -494,60 +615,24 @@
                                             int render_frame_id) {
   RenderFrameHostId render_frame_host_id(render_process_id, render_frame_id);
   frame_manager_->Reset(render_frame_host_id);
-  if (render_frame_host_id == default_presentation_render_frame_host_id_) {
-    UpdateDefaultMediaSourceAndNotifyObservers(RenderFrameHostId(),
-                                               MediaSource(), GURL());
-  }
 }
 
 void PresentationServiceDelegateImpl::SetDefaultPresentationUrl(
     int render_process_id,
     int render_frame_id,
-    const std::string& default_presentation_url) {
+    const std::string& default_presentation_url,
+    const content::PresentationSessionStartedCallback& callback) {
   RenderFrameHostId render_frame_host_id(render_process_id, render_frame_id);
-  if (IsMainFrame(render_process_id, render_frame_id)) {
-    // This is the main frame, which means tab-level default presentation
-    // might have been updated.
-    MediaSource default_source;
-    if (!default_presentation_url.empty())
-      default_source = MediaSourceForPresentationUrl(default_presentation_url);
-
-    GURL default_frame_url = GetLastCommittedURLForFrame(render_frame_host_id);
-    UpdateDefaultMediaSourceAndNotifyObservers(
-        render_frame_host_id, default_source, default_frame_url);
-  }
-}
-
-bool PresentationServiceDelegateImpl::IsMainFrame(int render_process_id,
-                                                  int render_frame_id) const {
-  RenderFrameHost* main_frame = web_contents_->GetMainFrame();
-  return main_frame &&
-         GetRenderFrameHostId(main_frame) ==
-             RenderFrameHostId(render_process_id, render_frame_id);
-}
-
-void PresentationServiceDelegateImpl::
-    UpdateDefaultMediaSourceAndNotifyObservers(
-        const RenderFrameHostId& render_frame_host_id,
-        const MediaSource& new_default_source,
-        const GURL& new_default_frame_url) {
-  default_presentation_render_frame_host_id_ = render_frame_host_id;
-  if (!new_default_source.Equals(default_source_) ||
-      new_default_frame_url != default_frame_url_) {
-    default_source_ = new_default_source;
-    default_frame_url_ = new_default_frame_url;
-    FOR_EACH_OBSERVER(
-        DefaultMediaSourceObserver, default_media_source_observers_,
-        OnDefaultMediaSourceChanged(default_source_, default_frame_url_));
-  }
+  frame_manager_->SetDefaultPresentationUrl(render_frame_host_id,
+                                            default_presentation_url, callback);
 }
 
 void PresentationServiceDelegateImpl::OnJoinRouteResponse(
     int render_process_id,
     int render_frame_id,
     const content::PresentationSessionInfo& session,
-    const PresentationSessionSuccessCallback& success_cb,
-    const PresentationSessionErrorCallback& error_cb,
+    const content::PresentationSessionStartedCallback& success_cb,
+    const content::PresentationSessionErrorCallback& error_cb,
     const MediaRoute* route,
     const std::string& presentation_id,
     const std::string& error_text) {
@@ -561,7 +646,7 @@
              << ", presentation ID: " << session.presentation_id;
     DCHECK_EQ(session.presentation_id, presentation_id);
     frame_manager_->OnPresentationSessionStarted(
-        RenderFrameHostId(render_process_id, render_frame_id), false, session,
+        RenderFrameHostId(render_process_id, render_frame_id), session,
         route->media_route_id());
     success_cb.Run(session);
   }
@@ -570,7 +655,7 @@
 void PresentationServiceDelegateImpl::OnStartSessionSucceeded(
     int render_process_id,
     int render_frame_id,
-    const PresentationSessionSuccessCallback& success_cb,
+    const content::PresentationSessionStartedCallback& success_cb,
     const content::PresentationSessionInfo& new_session,
     const MediaRoute::Id& route_id) {
   DVLOG(1) << "OnStartSessionSucceeded: "
@@ -578,7 +663,7 @@
            << ", presentation URL: " << new_session.presentation_url
            << ", presentation ID: " << new_session.presentation_id;
   frame_manager_->OnPresentationSessionStarted(
-      RenderFrameHostId(render_process_id, render_frame_id), false, new_session,
+      RenderFrameHostId(render_process_id, render_frame_id), new_session,
       route_id);
   success_cb.Run(new_session);
 }
@@ -587,25 +672,26 @@
     int render_process_id,
     int render_frame_id,
     const std::string& presentation_url,
-    const PresentationSessionSuccessCallback& success_cb,
-    const PresentationSessionErrorCallback& error_cb) {
+    const content::PresentationSessionStartedCallback& success_cb,
+    const content::PresentationSessionErrorCallback& error_cb) {
   if (presentation_url.empty() || !IsValidPresentationUrl(presentation_url)) {
     error_cb.Run(content::PresentationError(content::PRESENTATION_ERROR_UNKNOWN,
                                             "Invalid presentation arguments."));
     return;
   }
-  RenderFrameHostId render_frame_host_id(render_process_id, render_frame_id);
 
-  scoped_ptr<CreatePresentationSessionRequest> context(
-      new CreatePresentationSessionRequest(
-          presentation_url, GetLastCommittedURLForFrame(render_frame_host_id),
+  RenderFrameHostId render_frame_host_id(render_process_id, render_frame_id);
+  scoped_ptr<CreatePresentationConnectionRequest> request(
+      new CreatePresentationConnectionRequest(
+          render_frame_host_id, presentation_url,
+          GetLastCommittedURLForFrame(render_frame_host_id),
           base::Bind(&PresentationServiceDelegateImpl::OnStartSessionSucceeded,
                      weak_factory_.GetWeakPtr(), render_process_id,
                      render_frame_id, success_cb),
           error_cb));
   MediaRouterDialogController* controller =
       MediaRouterDialogController::GetOrCreateForWebContents(web_contents_);
-  if (!controller->ShowMediaRouterDialogForPresentation(context.Pass())) {
+  if (!controller->ShowMediaRouterDialogForPresentation(request.Pass())) {
     LOG(ERROR) << "Media router dialog already exists. Ignoring StartSession.";
     error_cb.Run(content::PresentationError(content::PRESENTATION_ERROR_UNKNOWN,
                                             "Unable to create dialog."));
@@ -618,8 +704,8 @@
     int render_frame_id,
     const std::string& presentation_url,
     const std::string& presentation_id,
-    const PresentationSessionSuccessCallback& success_cb,
-    const PresentationSessionErrorCallback& error_cb) {
+    const content::PresentationSessionStartedCallback& success_cb,
+    const content::PresentationSessionErrorCallback& error_cb) {
   std::vector<MediaRouteResponseCallback> route_response_callbacks;
   route_response_callbacks.push_back(base::Bind(
       &PresentationServiceDelegateImpl::OnJoinRouteResponse,
@@ -689,34 +775,37 @@
 }
 
 void PresentationServiceDelegateImpl::OnRouteResponse(
+    const PresentationRequest& presentation_request,
     const MediaRoute* route,
     const std::string& presentation_id,
     const std::string& error) {
   if (!route)
     return;
-  const MediaSource& source = route->media_source();
-  DCHECK(!source.Empty());
-  if (!default_source_.Equals(source))
-    return;
-  RenderFrameHost* main_frame = web_contents_->GetMainFrame();
-  if (!main_frame)
-    return;
-  RenderFrameHostId render_frame_host_id(GetRenderFrameHostId(main_frame));
-  frame_manager_->OnPresentationSessionStarted(
-      render_frame_host_id, true,
-      content::PresentationSessionInfo(PresentationUrlFromMediaSource(source),
-                                       presentation_id),
-      route->media_route_id());
+
+  content::PresentationSessionInfo session_info(
+      presentation_request.presentation_url(), presentation_id);
+  frame_manager_->OnDefaultPresentationSessionStarted(
+      presentation_request, session_info, route->media_route_id());
 }
 
-void PresentationServiceDelegateImpl::AddDefaultMediaSourceObserver(
-    DefaultMediaSourceObserver* observer) {
-  default_media_source_observers_.AddObserver(observer);
+void PresentationServiceDelegateImpl::AddDefaultPresentationRequestObserver(
+    DefaultPresentationRequestObserver* observer) {
+  frame_manager_->AddDefaultPresentationRequestObserver(observer);
 }
 
-void PresentationServiceDelegateImpl::RemoveDefaultMediaSourceObserver(
-    DefaultMediaSourceObserver* observer) {
-  default_media_source_observers_.RemoveObserver(observer);
+void PresentationServiceDelegateImpl::RemoveDefaultPresentationRequestObserver(
+    DefaultPresentationRequestObserver* observer) {
+  frame_manager_->RemoveDefaultPresentationRequestObserver(observer);
+}
+
+PresentationRequest
+PresentationServiceDelegateImpl::GetDefaultPresentationRequest() const {
+  DCHECK(HasDefaultPresentationRequest());
+  return *frame_manager_->default_presentation_request();
+}
+
+bool PresentationServiceDelegateImpl::HasDefaultPresentationRequest() const {
+  return frame_manager_->default_presentation_request() != nullptr;
 }
 
 base::WeakPtr<PresentationServiceDelegateImpl>
diff --git a/chrome/browser/media/router/presentation_service_delegate_impl.h b/chrome/browser/media/router/presentation_service_delegate_impl.h
index 03ad8c7..0e6b633 100644
--- a/chrome/browser/media/router/presentation_service_delegate_impl.h
+++ b/chrome/browser/media/router/presentation_service_delegate_impl.h
@@ -16,6 +16,8 @@
 #include "base/observer_list.h"
 #include "chrome/browser/media/router/media_router.h"
 #include "chrome/browser/media/router/media_source.h"
+#include "chrome/browser/media/router/presentation_request.h"
+#include "chrome/browser/media/router/render_frame_host_id.h"
 #include "content/public/browser/presentation_service_delegate.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/browser/web_contents_user_data.h"
@@ -35,8 +37,6 @@
 class PresentationFrameManager;
 class PresentationSessionStateObserver;
 
-using RenderFrameHostId = std::pair<int, int>;
-
 // Implementation of PresentationServiceDelegate that interfaces an
 // instance of WebContents with the Chrome Media Router. It uses the Media
 // Router to handle presentation API calls forwarded from
@@ -49,6 +49,23 @@
     : public content::WebContentsUserData<PresentationServiceDelegateImpl>,
       public content::PresentationServiceDelegate {
  public:
+  // Observer interface for listening to default presentation request
+  // changes for the WebContents.
+  class DefaultPresentationRequestObserver {
+   public:
+    virtual ~DefaultPresentationRequestObserver() = default;
+
+    // Called when default presentation request for the corresponding
+    // WebContents is set or changed.
+    // |default_presentation_info|: New default presentation request.
+    virtual void OnDefaultPresentationChanged(
+        const PresentationRequest& default_presentation_request) = 0;
+
+    // Called when default presentation request for the corresponding
+    // WebContents has been removed.
+    virtual void OnDefaultPresentationRemoved() = 0;
+  };
+
   // Retrieves the instance of PresentationServiceDelegateImpl that was attached
   // to the specified WebContents.  If no instance was attached, creates one,
   // and attaches it to the specified WebContents.
@@ -75,18 +92,21 @@
   void SetDefaultPresentationUrl(
       int render_process_id,
       int render_frame_id,
-      const std::string& default_presentation_url) override;
-  void StartSession(int render_process_id,
-                    int render_frame_id,
-                    const std::string& presentation_url,
-                    const PresentationSessionSuccessCallback& success_cb,
-                    const PresentationSessionErrorCallback& error_cb) override;
-  void JoinSession(int render_process_id,
-                   int render_frame_id,
-                   const std::string& presentation_url,
-                   const std::string& presentation_id,
-                   const PresentationSessionSuccessCallback& success_cb,
-                   const PresentationSessionErrorCallback& error_cb) override;
+      const std::string& default_presentation_url,
+      const content::PresentationSessionStartedCallback& callback) override;
+  void StartSession(
+      int render_process_id,
+      int render_frame_id,
+      const std::string& presentation_url,
+      const content::PresentationSessionStartedCallback& success_cb,
+      const content::PresentationSessionErrorCallback& error_cb) override;
+  void JoinSession(
+      int render_process_id,
+      int render_frame_id,
+      const std::string& presentation_url,
+      const std::string& presentation_id,
+      const content::PresentationSessionStartedCallback& success_cb,
+      const content::PresentationSessionErrorCallback& error_cb) override;
   void CloseSession(int render_process_id,
                     int render_frame_id,
                     const std::string& presentation_id) override;
@@ -105,39 +125,34 @@
       int render_frame_id,
       const content::SessionStateChangedCallback& state_changed_cb) override;
 
-  // Callback invoked when there is a route response from CreateRoute/JoinRoute
-  // outside of a Presentation API request. This could be due to
-  // browser action (e.g., browser initiated media router dialog) or
-  // a media route provider (e.g., autojoin).
-  void OnRouteResponse(const MediaRoute* route,
+  // Callback invoked when a default PresentationRequest is started from a
+  // browser-initiated dialog.
+  void OnRouteResponse(const PresentationRequest& request,
+                       const MediaRoute* route,
                        const std::string& presentation_id,
                        const std::string& error);
 
-  // Returns the default MediaSource for this tab if there is one.
-  // Returns an empty MediaSource otherwise.
-  MediaSource default_source() const { return default_source_; }
+  // Adds / removes an observer for listening to default PresentationRequest
+  // changes. This class does not own |observer|. When |observer| is about to
+  // be destroyed, |RemoveDefaultPresentationRequestObserver| must be called.
+  void AddDefaultPresentationRequestObserver(
+      DefaultPresentationRequestObserver* observer);
+  void RemoveDefaultPresentationRequestObserver(
+      DefaultPresentationRequestObserver* observer);
 
-  content::WebContents* web_contents() const { return web_contents_; }
-  const GURL& default_frame_url() const { return default_frame_url_; }
+  // Gets the default presentation request for the owning tab WebContents. It
+  // is an error to call this method if the default presentation request does
+  // not exist.
+  PresentationRequest GetDefaultPresentationRequest() const;
 
-  // Observer interface for listening to default MediaSource changes for the
+  // Returns true if there is a default presentation request for the owning tab
   // WebContents.
-  class DefaultMediaSourceObserver {
-   public:
-    virtual ~DefaultMediaSourceObserver() {}
+  bool HasDefaultPresentationRequest() const;
 
-    // Called when default media source for the corresponding WebContents has
-    // changed.
-    // |source|: New default MediaSource, or empty if default was removed.
-    // |frame_url|: URL of the frame that contains the default media
-    //     source, or empty if there is no default media source.
-    virtual void OnDefaultMediaSourceChanged(const MediaSource& source,
-                                             const GURL& frame_url) = 0;
-  };
+  // Returns the WebContents that owns this instance.
+  content::WebContents* web_contents() const { return web_contents_; }
 
-  // Adds / removes an observer for listening to default MediaSource changes.
-  void AddDefaultMediaSourceObserver(DefaultMediaSourceObserver* observer);
-  void RemoveDefaultMediaSourceObserver(DefaultMediaSourceObserver* observer);
+  base::WeakPtr<PresentationServiceDelegateImpl> GetWeakPtr();
 
   void SetMediaRouterForTest(MediaRouter* router);
   bool HasScreenAvailabilityListenerForTest(
@@ -145,12 +160,16 @@
       int render_frame_id,
       const MediaSource::Id& source_id) const;
 
-  base::WeakPtr<PresentationServiceDelegateImpl> GetWeakPtr();
-
  private:
   friend class content::WebContentsUserData<PresentationServiceDelegateImpl>;
   FRIEND_TEST_ALL_PREFIXES(PresentationServiceDelegateImplTest,
                            DelegateObservers);
+  FRIEND_TEST_ALL_PREFIXES(PresentationServiceDelegateImplTest,
+                           SetDefaultPresentationUrl);
+  FRIEND_TEST_ALL_PREFIXES(PresentationServiceDelegateImplTest,
+                           DefaultPresentationRequestObserver);
+  FRIEND_TEST_ALL_PREFIXES(PresentationServiceDelegateImplTest,
+                           DefaultPresentationUrlCallback);
 
   explicit PresentationServiceDelegateImpl(content::WebContents* web_contents);
 
@@ -159,47 +178,26 @@
   MediaSource GetMediaSourceFromListener(
       content::PresentationScreenAvailabilityListener* listener);
 
-  void OnJoinRouteResponse(int render_process_id,
-                           int render_frame_id,
-                           const content::PresentationSessionInfo& session,
-                           const PresentationSessionSuccessCallback& success_cb,
-                           const PresentationSessionErrorCallback& error_cb,
-                           const MediaRoute* route,
-                           const std::string& presentation_id,
-                           const std::string& error_text);
+  void OnJoinRouteResponse(
+      int render_process_id,
+      int render_frame_id,
+      const content::PresentationSessionInfo& session,
+      const content::PresentationSessionStartedCallback& success_cb,
+      const content::PresentationSessionErrorCallback& error_cb,
+      const MediaRoute* route,
+      const std::string& presentation_id,
+      const std::string& error_text);
 
   void OnStartSessionSucceeded(
       int render_process_id,
       int render_frame_id,
-      const PresentationSessionSuccessCallback& success_cb,
+      const content::PresentationSessionStartedCallback& success_cb,
       const content::PresentationSessionInfo& new_session,
       const MediaRoute::Id& route_id);
 
-  // Returns |true| if the frame is the main frame of |web_contents_|.
-  bool IsMainFrame(int render_process_id, int render_frame_id) const;
-
-  // Updates tab-level default MediaSource, default frame URL, and the
-  // originating frame. If the source or frame URL changed, notify the
-  // observers.
-  void UpdateDefaultMediaSourceAndNotifyObservers(
-      const RenderFrameHostId& render_frame_host_id,
-      const MediaSource& new_default_source,
-      const GURL& new_default_frame_url);
-
-  // ID of RenderFrameHost that contains the default presentation.
-  RenderFrameHostId default_presentation_render_frame_host_id_;
-  // Default MediaSource for the tab associated with this instance.
-  MediaSource default_source_;
-  // URL of the frame that contains the default MediaSource.
-  GURL default_frame_url_;
-
-  // References to the observers listening for changes to default media source.
-  base::ObserverList<
-      DefaultMediaSourceObserver> default_media_source_observers_;
-
   // References to the WebContents that owns this instance, and associated
   // browser profile's MediaRouter instance.
-  content::WebContents* web_contents_;
+  content::WebContents* const web_contents_;
   MediaRouter* router_;
 
   scoped_ptr<PresentationFrameManager> frame_manager_;
diff --git a/chrome/browser/media/router/presentation_service_delegate_impl_unittest.cc b/chrome/browser/media/router/presentation_service_delegate_impl_unittest.cc
index 056f05d..c3099aa 100644
--- a/chrome/browser/media/router/presentation_service_delegate_impl_unittest.cc
+++ b/chrome/browser/media/router/presentation_service_delegate_impl_unittest.cc
@@ -24,6 +24,7 @@
 using ::testing::_;
 using ::testing::Mock;
 using ::testing::Return;
+using ::testing::SaveArg;
 using ::testing::StrictMock;
 
 namespace media_router {
@@ -36,11 +37,12 @@
                void(const content::PresentationSessionInfo&));
 };
 
-class MockDefaultMediaSourceObserver
-    : public PresentationServiceDelegateImpl::DefaultMediaSourceObserver {
+class MockDefaultPresentationRequestObserver
+    : public PresentationServiceDelegateImpl::
+          DefaultPresentationRequestObserver {
  public:
-  MOCK_METHOD2(OnDefaultMediaSourceChanged,
-               void(const MediaSource&, const GURL&));
+  MOCK_METHOD1(OnDefaultPresentationChanged, void(const PresentationRequest&));
+  MOCK_METHOD0(OnDefaultPresentationRemoved, void());
 };
 
 class PresentationServiceDelegateImplTest
@@ -55,6 +57,9 @@
     delegate_impl_->SetMediaRouterForTest(&router_);
   }
 
+  MOCK_METHOD1(OnDefaultPresentationStarted,
+               void(const content::PresentationSessionInfo& session_info));
+
   PresentationServiceDelegateImpl* delegate_impl_;
   MockMediaRouter router_;
 };
@@ -62,8 +67,8 @@
 TEST_F(PresentationServiceDelegateImplTest, AddScreenAvailabilityListener) {
   ON_CALL(router_, RegisterMediaSinksObserver(_)).WillByDefault(Return(true));
 
-  std::string presentation_url1("http://url1");
-  std::string presentation_url2("http://url2");
+  std::string presentation_url1("http://url1.fakeUrl");
+  std::string presentation_url2("http://url2.fakeUrl");
   MediaSource source1 = MediaSourceForPresentationUrl(presentation_url1);
   MediaSource source2 = MediaSourceForPresentationUrl(presentation_url2);
   MockScreenAvailabilityListener listener1(presentation_url1);
@@ -98,7 +103,7 @@
 TEST_F(PresentationServiceDelegateImplTest, AddSameListenerTwice) {
   ON_CALL(router_, RegisterMediaSinksObserver(_)).WillByDefault(Return(true));
 
-  std::string presentation_url1("http://url1");
+  std::string presentation_url1("http://url1.fakeUrl");
   MediaSource source1(MediaSourceForPresentationUrl(presentation_url1));
   MockScreenAvailabilityListener listener1(presentation_url1);
   int render_process_id = 1;
@@ -119,76 +124,144 @@
       render_process_id, render_frame_id, source1.id()));
 }
 
+// TODO(imcheng): Add a test to set default presentation URL in a different
+// RenderFrameHost and verify that it works.
 TEST_F(PresentationServiceDelegateImplTest, SetDefaultPresentationUrl) {
-  content::WebContentsTester::For(web_contents())
-      ->NavigateAndCommit(GURL("http://www.google.com"));
+  EXPECT_FALSE(delegate_impl_->HasDefaultPresentationRequest());
+
+  GURL frame_url("http://www.google.com");
+  content::WebContentsTester::For(web_contents())->NavigateAndCommit(frame_url);
   content::RenderFrameHost* main_frame = web_contents()->GetMainFrame();
   ASSERT_TRUE(main_frame);
   int render_process_id = main_frame->GetProcess()->GetID();
   int routing_id = main_frame->GetRoutingID();
 
-  std::string presentation_url1("http://foo");
+  auto callback = base::Bind(
+      &PresentationServiceDelegateImplTest::OnDefaultPresentationStarted,
+      base::Unretained(this));
+  std::string presentation_url1("http://foo.fakeUrl");
   delegate_impl_->SetDefaultPresentationUrl(render_process_id, routing_id,
-                                            presentation_url1);
-  EXPECT_TRUE(delegate_impl_->default_source().Equals(
-      MediaSourceForPresentationUrl(presentation_url1)));
-
-  // Remove default presentation URL.
-  delegate_impl_->SetDefaultPresentationUrl(render_process_id, routing_id, "");
-  EXPECT_TRUE(delegate_impl_->default_source().Empty());
+                                            presentation_url1, callback);
+  ASSERT_TRUE(delegate_impl_->HasDefaultPresentationRequest());
+  PresentationRequest request1 =
+      delegate_impl_->GetDefaultPresentationRequest();
+  EXPECT_EQ(presentation_url1, request1.presentation_url());
+  EXPECT_EQ(RenderFrameHostId(render_process_id, routing_id),
+            request1.render_frame_host_id());
+  EXPECT_EQ(frame_url, request1.frame_url());
 
   // Set to a new default presentation URL
   std::string presentation_url2("https://youtube.com");
   delegate_impl_->SetDefaultPresentationUrl(render_process_id, routing_id,
-                                            presentation_url2);
-  EXPECT_TRUE(delegate_impl_->default_source().Equals(
-      MediaSourceForPresentationUrl(presentation_url2)));
+                                            presentation_url2, callback);
+  ASSERT_TRUE(delegate_impl_->HasDefaultPresentationRequest());
+  PresentationRequest request2 =
+      delegate_impl_->GetDefaultPresentationRequest();
+  EXPECT_EQ(presentation_url2, request2.presentation_url());
+  EXPECT_EQ(RenderFrameHostId(render_process_id, routing_id),
+            request2.render_frame_host_id());
+  EXPECT_EQ(frame_url, request2.frame_url());
+
+  // Remove default presentation URL.
+  delegate_impl_->SetDefaultPresentationUrl(render_process_id, routing_id, "",
+                                            callback);
+  EXPECT_FALSE(delegate_impl_->HasDefaultPresentationRequest());
 }
 
-TEST_F(PresentationServiceDelegateImplTest, DefaultMediaSourceObserver) {
-  content::WebContentsTester::For(web_contents())
-      ->NavigateAndCommit(GURL("http://www.google.com"));
+TEST_F(PresentationServiceDelegateImplTest, DefaultPresentationUrlCallback) {
   content::RenderFrameHost* main_frame = web_contents()->GetMainFrame();
   ASSERT_TRUE(main_frame);
   int render_process_id = main_frame->GetProcess()->GetID();
   int routing_id = main_frame->GetRoutingID();
-  StrictMock<MockDefaultMediaSourceObserver> observer1;
-  StrictMock<MockDefaultMediaSourceObserver> observer2;
-  delegate_impl_->AddDefaultMediaSourceObserver(&observer1);
-  delegate_impl_->AddDefaultMediaSourceObserver(&observer2);
-  std::string url1("http://foo");
-  EXPECT_CALL(observer1, OnDefaultMediaSourceChanged(
-                             Equals(MediaSourceForPresentationUrl(url1)),
-                             GURL("http://www.google.com"))).Times(1);
-  EXPECT_CALL(observer2, OnDefaultMediaSourceChanged(
-                             Equals(MediaSourceForPresentationUrl(url1)),
-                             GURL("http://www.google.com"))).Times(1);
-  delegate_impl_->SetDefaultPresentationUrl(render_process_id,
-                                            routing_id, url1);
 
-  EXPECT_TRUE(Mock::VerifyAndClearExpectations(&observer1));
-  EXPECT_TRUE(Mock::VerifyAndClearExpectations(&observer2));
+  auto callback = base::Bind(
+      &PresentationServiceDelegateImplTest::OnDefaultPresentationStarted,
+      base::Unretained(this));
+  std::string presentation_url1("http://foo.fakeUrl");
+  delegate_impl_->SetDefaultPresentationUrl(render_process_id, routing_id,
+                                            presentation_url1, callback);
 
-  delegate_impl_->RemoveDefaultMediaSourceObserver(&observer2);
+  ASSERT_TRUE(delegate_impl_->HasDefaultPresentationRequest());
+  PresentationRequest request = delegate_impl_->GetDefaultPresentationRequest();
+
+  // Should not trigger callback since route response is error.
+  delegate_impl_->OnRouteResponse(request, nullptr, "", "Error");
+  EXPECT_TRUE(Mock::VerifyAndClearExpectations(this));
+
+  // Should not trigger callback since request doesn't match.
+  std::string presentation_url2("http://bar.fakeUrl");
+  PresentationRequest different_request(RenderFrameHostId(100, 200),
+                                        presentation_url2,
+                                        GURL("http://anotherFrameUrl.fakeUrl"));
+  MediaRoute different_route("differentRouteId",
+                             MediaSourceForPresentationUrl(presentation_url2),
+                             "mediaSinkId", "", true, "", true);
+  delegate_impl_->OnRouteResponse(different_request, &different_route,
+                                  "differentPresentationId", "");
+  EXPECT_TRUE(Mock::VerifyAndClearExpectations(this));
+
+  // Should trigger callback since request matches.
+  MediaRoute route("routeId", MediaSourceForPresentationUrl(presentation_url1),
+                   "mediaSinkId", "", true, "", true);
+  EXPECT_CALL(*this, OnDefaultPresentationStarted(_)).Times(1);
+  delegate_impl_->OnRouteResponse(request, &route, "presentationId", "");
+}
+
+TEST_F(PresentationServiceDelegateImplTest,
+       DefaultPresentationRequestObserver) {
+  auto callback = base::Bind(
+      &PresentationServiceDelegateImplTest::OnDefaultPresentationStarted,
+      base::Unretained(this));
+
+  StrictMock<MockDefaultPresentationRequestObserver> observer;
+  delegate_impl_->AddDefaultPresentationRequestObserver(&observer);
+
+  GURL frame_url("http://www.google.com");
+  content::WebContentsTester::For(web_contents())->NavigateAndCommit(frame_url);
+  content::RenderFrameHost* main_frame = web_contents()->GetMainFrame();
+  ASSERT_TRUE(main_frame);
+  int render_process_id = main_frame->GetProcess()->GetID();
+  int routing_id = main_frame->GetRoutingID();
+
+  std::string url1("http://foo.fakeUrl");
+  PresentationRequest observed_request1(
+      RenderFrameHostId(render_process_id, routing_id), url1, frame_url);
+  EXPECT_CALL(observer, OnDefaultPresentationChanged(Equals(observed_request1)))
+      .Times(1);
+  delegate_impl_->SetDefaultPresentationUrl(render_process_id, routing_id, url1,
+                                            callback);
+
+  ASSERT_TRUE(delegate_impl_->HasDefaultPresentationRequest());
+  PresentationRequest request1 =
+      delegate_impl_->GetDefaultPresentationRequest();
+  EXPECT_TRUE(request1.Equals(observed_request1));
+
+  EXPECT_TRUE(Mock::VerifyAndClearExpectations(&observer));
+
   std::string url2("http://youtube.com");
-  EXPECT_CALL(observer1, OnDefaultMediaSourceChanged(
-                             Equals(MediaSourceForPresentationUrl(url2)),
-                             GURL("http://www.google.com"))).Times(1);
-  delegate_impl_->SetDefaultPresentationUrl(render_process_id,
-                                            routing_id, url2);
+  PresentationRequest observed_request2(
+      RenderFrameHostId(render_process_id, routing_id), url2, frame_url);
+  EXPECT_CALL(observer, OnDefaultPresentationChanged(Equals(observed_request2)))
+      .Times(1);
+  delegate_impl_->SetDefaultPresentationUrl(render_process_id, routing_id, url2,
+                                            callback);
+  ASSERT_TRUE(delegate_impl_->HasDefaultPresentationRequest());
+  PresentationRequest request2 =
+      delegate_impl_->GetDefaultPresentationRequest();
+  EXPECT_TRUE(request2.Equals(observed_request2));
 
-  EXPECT_TRUE(Mock::VerifyAndClearExpectations(&observer1));
+  EXPECT_TRUE(Mock::VerifyAndClearExpectations(&observer));
+
   // Remove default presentation URL.
-  EXPECT_CALL(observer1, OnDefaultMediaSourceChanged(
-                             Equals(MediaSource()),
-                             GURL("http://www.google.com"))).Times(1);
-  delegate_impl_->SetDefaultPresentationUrl(render_process_id, routing_id, "");
+  EXPECT_CALL(observer, OnDefaultPresentationRemoved()).Times(1);
+  delegate_impl_->SetDefaultPresentationUrl(render_process_id, routing_id, "",
+                                            callback);
 }
 
 TEST_F(PresentationServiceDelegateImplTest, Reset) {
   ON_CALL(router_, RegisterMediaSinksObserver(_)).WillByDefault(Return(true));
 
-  std::string presentation_url1("http://url1");
+  std::string presentation_url1("http://url1.fakeUrl");
   MediaSource source = MediaSourceForPresentationUrl(presentation_url1);
   MockScreenAvailabilityListener listener1(presentation_url1);
   int render_process_id = 1;
@@ -225,7 +298,7 @@
 TEST_F(PresentationServiceDelegateImplTest, SinksObserverCantRegister) {
   ON_CALL(router_, RegisterMediaSinksObserver(_)).WillByDefault(Return(false));
 
-  const std::string presentation_url("http://url1");
+  const std::string presentation_url("http://url1.fakeUrl");
   MockScreenAvailabilityListener listener(presentation_url);
   const int render_process_id = 10;
   const int render_frame_id = 1;
diff --git a/chrome/browser/media/router/render_frame_host_id.h b/chrome/browser/media/router/render_frame_host_id.h
new file mode 100644
index 0000000..d9fb005
--- /dev/null
+++ b/chrome/browser/media/router/render_frame_host_id.h
@@ -0,0 +1,16 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_MEDIA_ROUTER_RENDER_FRAME_HOST_ID_H_
+#define CHROME_BROWSER_MEDIA_ROUTER_RENDER_FRAME_HOST_ID_H_
+
+#include <utility>
+
+namespace media_router {
+
+using RenderFrameHostId = std::pair<int, int>;
+
+}  // namespace media_router
+
+#endif  // CHROME_BROWSER_MEDIA_ROUTER_RENDER_FRAME_HOST_ID_H_
diff --git a/chrome/browser/password_manager/chrome_password_manager_client.cc b/chrome/browser/password_manager/chrome_password_manager_client.cc
index 6a1c44a..a9fee52 100644
--- a/chrome/browser/password_manager/chrome_password_manager_client.cc
+++ b/chrome/browser/password_manager/chrome_password_manager_client.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/password_manager/chrome_password_manager_client.h"
 
+#include <string>
+
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/command_line.h"
diff --git a/chrome/browser/resources/OWNERS b/chrome/browser/resources/OWNERS
index 88772418..dae8b002 100644
--- a/chrome/browser/resources/OWNERS
+++ b/chrome/browser/resources/OWNERS
@@ -1,7 +1,6 @@
 bauerb@chromium.org
 dbeam@chromium.org
 estade@chromium.org
-jhawkins@chromium.org
 nkostylev@chromium.org
 pam@chromium.org
 xiyuan@chromium.org
diff --git a/chrome/browser/resources/options/OWNERS b/chrome/browser/resources/options/OWNERS
index 4b65fc2..534d4015 100644
--- a/chrome/browser/resources/options/OWNERS
+++ b/chrome/browser/resources/options/OWNERS
@@ -1,4 +1,3 @@
 dbeam@chromium.org
 estade@chromium.org
-jhawkins@chromium.org
 stevenjb@chromium.org
diff --git a/chrome/browser/resources/settings/advanced_page/advanced_page.html b/chrome/browser/resources/settings/advanced_page/advanced_page.html
index 138fdda..008a1f7 100644
--- a/chrome/browser/resources/settings/advanced_page/advanced_page.html
+++ b/chrome/browser/resources/settings/advanced_page/advanced_page.html
@@ -10,6 +10,7 @@
 
 <if expr="chromeos">
 <link rel="import" href="chrome://md-settings/a11y_page/a11y_page.html">
+<link rel="import" href="chrome://md-settings/bluetooth_page/bluetooth_page.html">
 <link rel="import" href="chrome://md-settings/date_time_page/date_time_page.html">
 </if>
 
@@ -37,6 +38,14 @@
       </settings-privacy-page>
     </settings-section>
 
+<if expr="chromeos">
+    <settings-section i18n-values="page-title:bluetoothPageTitle"
+        current-route="[[currentRoute]]" section="bluetooth">
+      <settings-bluetooth-page current-route="{{currentRoute}}">
+      </settings-bluetooth-page>
+    </settings-section>
+</if>
+
     <settings-section
         i18n-values="page-title:passwordsAndAutofillPageTitle"
         current-route="[[currentRoute]]" section="passwordsAndForms">
diff --git a/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.css b/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.css
new file mode 100644
index 0000000..df0c564
--- /dev/null
+++ b/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.css
@@ -0,0 +1,7 @@
+/* Copyright 2015 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+iron-icon {
+  -webkit-margin-end: 10px;
+}
diff --git a/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.html b/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.html
new file mode 100644
index 0000000..4c093d5a
--- /dev/null
+++ b/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.html
@@ -0,0 +1,26 @@
+<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/classes/iron-flex-layout.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-icons/device-icons.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/neon-animation/neon-animatable.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-toggle-button/paper-toggle-button.html">
+<link rel="import" href="chrome://md-settings/settings_page/settings_animated_pages.html">
+
+<dom-module id="settings-bluetooth-page">
+  <link rel="import" type="css" href="chrome://md-settings/settings_page/settings_page.css">
+  <link rel="import" type="css" href="bluetooth_page.css">
+  <template>
+    <settings-animated-pages id="pages" current-route="{{currentRoute}}"
+        section="bluetooth">
+      <neon-animatable id="main">
+        <div class="layout horizontal center">
+          <iron-icon icon="device:bluetooth"></iron-icon>
+          <span class="flex" i18n-content="enableBluetooth"></span>
+          <paper-toggle-button checked="{{bluetoothEnabled}}"
+              on-change="onBluetoothEnabledChange_">
+          </paper-toggle-button>
+        </div>
+      </neon-animatable>
+    </settings-animated-pages>
+  </template>
+  <script src="bluetooth_page.js"></script>
+</dom-module>
diff --git a/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.js b/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.js
new file mode 100644
index 0000000..6328c0ae
--- /dev/null
+++ b/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.js
@@ -0,0 +1,78 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @fileoverview
+ * 'settings-bluetooth-page' is the settings page for managing bluetooth
+ *  properties and devices.
+ *
+ * Example:
+ *    <core-animated-pages>
+ *      <settings-bluetooth-page>
+ *      </settings-bluetooth-page>
+ *      ... other pages ...
+ *    </core-animated-pages>
+ *
+ * @group Chrome Settings Elements
+ * @element settings-bluetooth-page
+ */
+Polymer({
+  is: 'settings-bluetooth-page',
+
+  properties: {
+    /** The current active route. */
+    currentRoute: {
+      type: Object,
+      notify: true,
+    },
+
+    /** Whether bluetooth is enabled. */
+    bluetoothEnabled: Boolean,
+  },
+
+  /**
+   * Listener for chrome.bluetooth.onAdapterStateChanged events.
+   * @type {function(!chrome.bluetooth.AdapterState)}
+   * @private
+   */
+  bluetoothAdapterStateChangedListener_: function() {},
+
+  /** @override */
+  attached: function() {
+    this.bluetoothAdapterStateChangedListener_ =
+        this.onBluetoothAdapterStateChanged_.bind(this);
+    chrome.bluetooth.onAdapterStateChanged.addListener(
+        this.bluetoothAdapterStateChangedListener_);
+
+  },
+
+  /** @override */
+  detached: function() {
+    chrome.bluetooth.onAdapterStateChanged.removeListener(
+        this.bluetoothAdapterStateChangedListener_);
+  },
+
+  /**
+   * Event called when a user action changes the bluetoothEnabled state.
+   * @private
+   */
+  onBluetoothEnabledChange_: function() {
+    chrome.bluetoothPrivate.setAdapterState(
+        {powered: this.bluetoothEnabled}, function() {
+          if (chrome.runtime.lastError) {
+            console.error(
+                'Error enabling bluetooth:', chrome.runtime.lastError.message);
+          }
+        });
+  },
+
+  /**
+   * Process bluetooth.onAdapterStateChanged events.
+   * @param {!chrome.bluetooth.AdapterState} state
+   * @private
+   */
+  onBluetoothAdapterStateChanged_: function(state) {
+    this.bluetoothEnabled = state.powered;
+  },
+});
diff --git a/chrome/browser/resources/settings/bluetooth_page/compiled_resources.gyp b/chrome/browser/resources/settings/bluetooth_page/compiled_resources.gyp
new file mode 100644
index 0000000..cc915ac
--- /dev/null
+++ b/chrome/browser/resources/settings/bluetooth_page/compiled_resources.gyp
@@ -0,0 +1,22 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'targets': [
+    {
+      'target_name': 'bluetooth_page',
+      'variables': {
+        'depends': [
+          '../../../../../ui/webui/resources/js/compiled_resources.gyp:assert',
+          '../../../../../ui/webui/resources/js/compiled_resources.gyp:load_time_data',
+          '../settings_page/settings_animated_pages.js'
+        ],
+        'externs': [
+          '../../../../../third_party/closure_compiler/externs/bluetooth.js',
+          '../../../../../third_party/closure_compiler/externs/bluetooth_private.js'
+        ],
+      },
+      'includes': ['../../../../../third_party/closure_compiler/compile_js.gypi'],
+    },
+  ],
+}
diff --git a/chrome/browser/resources/settings/compiled_resources.gyp b/chrome/browser/resources/settings/compiled_resources.gyp
index ae8f25e..4ec217f 100644
--- a/chrome/browser/resources/settings/compiled_resources.gyp
+++ b/chrome/browser/resources/settings/compiled_resources.gyp
@@ -8,6 +8,7 @@
       'type': 'none',
       'dependencies': [
         'appearance_page/compiled_resources.gyp:*',
+        'bluetooth_page/compiled_resources.gyp:*',
         'internet_page/compiled_resources.gyp:*',
         'languages_page/compiled_resources.gyp:*',
         'on_startup_page/compiled_resources.gyp:*',
diff --git a/chrome/browser/resources/settings/settings_menu/settings_menu.html b/chrome/browser/resources/settings/settings_menu/settings_menu.html
index 12628ddf..7becb81 100644
--- a/chrome/browser/resources/settings/settings_menu/settings_menu.html
+++ b/chrome/browser/resources/settings/settings_menu/settings_menu.html
@@ -69,6 +69,10 @@
             <span i18n-content="privacyPageTitle"></span>
           </paper-icon-item>
           <paper-icon-item>
+            <iron-icon icon="device:bluetooth" item-icon></iron-icon>
+            <span i18n-content="bluetoothPageTitle"></span>
+          </paper-icon-item>
+          <paper-icon-item>
             <iron-icon icon="file-download" item-icon></iron-icon>
             <span i18n-content="downloadsPageTitle"></span>
           </paper-icon-item>
diff --git a/chrome/browser/resources/settings/settings_resources.grd b/chrome/browser/resources/settings/settings_resources.grd
index ee28081..d19e897d 100644
--- a/chrome/browser/resources/settings/settings_resources.grd
+++ b/chrome/browser/resources/settings/settings_resources.grd
@@ -379,6 +379,24 @@
       <structure name="IDR_SETTINGS_SITE_SETTINGS_PAGE_JS"
                  file="site_settings_page/site_settings_page.js"
                  type="chrome_html" />
+      <structure name="IDR_SETTINGS_SITE_SETTINGS_SITE_DETAILS_CSS"
+                 file="site_settings/site_details.css"
+                 type="chrome_html" />
+      <structure name="IDR_SETTINGS_SITE_SETTINGS_SITE_DETAILS_HTML"
+                 file="site_settings/site_details.html"
+                 type="chrome_html" />
+      <structure name="IDR_SETTINGS_SITE_SETTINGS_SITE_DETAILS_JS"
+                 file="site_settings/site_details.js"
+                 type="chrome_html" />
+      <structure name="IDR_SETTINGS_SITE_SETTINGS_SITE_DETAILS_PERMISSION_CSS"
+                 file="site_settings/site_details_permission.css"
+                 type="chrome_html" />
+      <structure name="IDR_SETTINGS_SITE_SETTINGS_SITE_DETAILS_PERMISSION_HTML"
+                 file="site_settings/site_details_permission.html"
+                 type="chrome_html" />
+      <structure name="IDR_SETTINGS_SITE_SETTINGS_SITE_DETAILS_PERMISSION_JS"
+                 file="site_settings/site_details_permission.js"
+                 type="chrome_html" />
       <structure name="IDR_SETTINGS_SEARCH_ENGINES_PAGE_SEARCH_ENGINE_ADDER_JS"
                  file="search_engines_page/search_engine_adder.js"
                  type="chrome_html" />
@@ -467,6 +485,15 @@
                  file="settings.js"
                  type="chrome_html" />
       <if expr="chromeos">
+        <structure name="IDR_SETTINGS_BLUETOOTH_PAGE_CSS"
+                   file="bluetooth_page/bluetooth_page.css"
+                   type="chrome_html" />
+        <structure name="IDR_SETTINGS_BLUETOOTH_PAGE_HTML"
+                   file="bluetooth_page/bluetooth_page.html"
+                   type="chrome_html" />
+        <structure name="IDR_SETTINGS_BLUETOOTH_PAGE_JS"
+                   file="bluetooth_page/bluetooth_page.js"
+                   type="chrome_html" />
         <structure name="IDR_SETTINGS_DATE_TIME_PAGE_CSS"
                    file="date_time_page/date_time_page.css"
                    type="chrome_html" />
diff --git a/chrome/browser/resources/settings/site_settings/compiled_resources.gyp b/chrome/browser/resources/settings/site_settings/compiled_resources.gyp
index a1d55111..12796dd8 100644
--- a/chrome/browser/resources/settings/site_settings/compiled_resources.gyp
+++ b/chrome/browser/resources/settings/site_settings/compiled_resources.gyp
@@ -4,6 +4,41 @@
 {
   'targets': [
     {
+      'target_name': 'site_details',
+      'variables': {
+        'depends': [
+          '../../../../../ui/webui/resources/js/compiled_resources.gyp:assert',
+          '../../../../../ui/webui/resources/js/compiled_resources.gyp:cr',
+          '../../../../../ui/webui/resources/js/compiled_resources.gyp:load_time_data',
+          '../prefs/prefs_behavior.js',
+          'constants.js',
+          'site_settings_behavior.js',
+          'site_details_permission.js',
+        ],
+        'externs': [
+          '../../../../../third_party/closure_compiler/externs/settings_private.js'
+        ],
+      },
+      'includes': ['../../../../../third_party/closure_compiler/compile_js.gypi'],
+    },
+    {
+      'target_name': 'site_details_permission',
+      'variables': {
+        'depends': [
+          '../../../../../ui/webui/resources/js/compiled_resources.gyp:assert',
+          '../../../../../ui/webui/resources/js/compiled_resources.gyp:cr',
+          '../../../../../ui/webui/resources/js/compiled_resources.gyp:load_time_data',
+          '../prefs/prefs_behavior.js',
+          'constants.js',
+          'site_settings_behavior.js',
+        ],
+        'externs': [
+          '../../../../../third_party/closure_compiler/externs/settings_private.js'
+        ],
+      },
+      'includes': ['../../../../../third_party/closure_compiler/compile_js.gypi'],
+    },
+    {
       'target_name': 'site_settings_behavior',
       'variables': {
         'depends': [
@@ -28,6 +63,7 @@
           '../../../../../ui/webui/resources/js/compiled_resources.gyp:load_time_data',
           '../prefs/prefs_behavior.js',
           '../prefs/prefs_types.js',
+          '../settings_page/settings_animated_pages.js',
           'constants.js',
           'site_settings_behavior.js',
         ],
diff --git a/chrome/browser/resources/settings/site_settings/constants.js b/chrome/browser/resources/settings/site_settings/constants.js
index 2f24196..909db1a 100644
--- a/chrome/browser/resources/settings/site_settings/constants.js
+++ b/chrome/browser/resources/settings/site_settings/constants.js
@@ -24,10 +24,10 @@
   };
 
   /**
-   * Contains the possible default values for a given contentSettingsType.
+   * Contains the possible values for a given contentSettingsType.
    * @enum {number}
    */
-  var DefaultValues = {
+  var PermissionValues = {
     ALLOW: 1,
     BLOCK: 2,
     ASK: 3,
@@ -35,6 +35,6 @@
 
   return {
     ContentSettingsTypes: ContentSettingsTypes,
-    DefaultValues: DefaultValues,
+    PermissionValues: PermissionValues,
   };
 });
diff --git a/chrome/browser/resources/settings/site_settings/site_details.css b/chrome/browser/resources/settings/site_settings/site_details.css
new file mode 100644
index 0000000..4a109a1
--- /dev/null
+++ b/chrome/browser/resources/settings/site_settings/site_details.css
@@ -0,0 +1,15 @@
+/* Copyright 2015 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+:host {
+  display: block;
+}
+
+.origin {
+  font-weight: bold;
+}
+
+.reset-button {
+  -webkit-margin-start: 15px;
+}
\ No newline at end of file
diff --git a/chrome/browser/resources/settings/site_settings/site_details.html b/chrome/browser/resources/settings/site_settings/site_details.html
new file mode 100644
index 0000000..9d8812e
--- /dev/null
+++ b/chrome/browser/resources/settings/site_settings/site_details.html
@@ -0,0 +1,51 @@
+<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button.html">
+<link rel="import" href="chrome://md-settings/site_settings/site_details_permission.html">
+
+<dom-module id="site-details">
+  <link rel="import" type="css"
+      href="chrome://md-settings/settings_page/settings_page.css">
+  <link rel="import" type="css" href="site_details.css">
+  <template>
+    <div class="origin">[[origin]]</div>
+    <h2 i18n-content="siteSettingsUsage" id="usage" hidden></h2>
+    <paper-item id="storage" hidden>
+      <div class="flex">[[storedData_]]</div>
+      <paper-icon-button icon="delete"
+          on-tap="onClearStorage_"
+          i18n-values="alt:siteSettingsDelete"></paper-icon-button>
+    </paper-item>
+    <h2 i18n-content="siteSettingsPermissions"></h2>
+    <site-details-permission prefs="{{prefs}}" id="cookies"
+        origin="[[origin]]">
+    </site-details-permission>
+    <site-details-permission prefs="{{prefs}}" id="javascript"
+        origin="[[origin]]">
+    </site-details-permission>
+    <site-details-permission prefs="{{prefs}}" id="popups"
+        origin="[[origin]]">
+    </site-details-permission>
+    <site-details-permission prefs="{{prefs}}" id="geolocation"
+        origin="[[origin]]">
+    </site-details-permission>
+    <site-details-permission prefs="{{prefs}}" id="notification"
+        origin="[[origin]]">
+    </site-details-permission>
+    <site-details-permission prefs="{{prefs}}" id="fullscreen"
+        origin="[[origin]]">
+    </site-details-permission>
+    <site-details-permission prefs="{{prefs}}" id="camera"
+        origin="[[origin]]">
+    </site-details-permission>
+    <site-details-permission prefs="{{prefs}}" id="mic"
+        origin="[[origin]]">
+    </site-details-permission>
+    <paper-button
+        on-tap="onClearAndReset_"
+        raised i18n-content="siteSettingsClearAndReset"
+        class="reset-button"></paper-button>
+  </template>
+  <script src="site_details.js"></script>
+</dom-module>
diff --git a/chrome/browser/resources/settings/site_settings/site_details.js b/chrome/browser/resources/settings/site_settings/site_details.js
new file mode 100644
index 0000000..cc6d5616
--- /dev/null
+++ b/chrome/browser/resources/settings/site_settings/site_details.js
@@ -0,0 +1,74 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @fileoverview
+ * 'site-details' show the details (permissions and usage) for a given origin
+ * under Site Settings.
+ *
+ * Example:
+ *
+ *      <site-details prefs="{{prefs}}" origin="{{origin}}">
+ *      </site-details>
+ *      ... other pages ...
+ *
+ * @group Chrome Settings Elements
+ * @element site-details
+ */
+Polymer({
+  is: 'site-details',
+
+  properties: {
+    /**
+     * Preferences state.
+     */
+    prefs: {
+      type: Object,
+      notify: true,
+    },
+
+    /**
+     * The origin that this widget is showing details for.
+     */
+    origin: String,
+
+    /**
+     * The amount of data stored for the origin.
+     */
+    storedData_: {
+      type: String,
+      observer: 'onStoredDataChanged_',
+    },
+  },
+
+  ready: function() {
+    this.$.cookies.category = settings.ContentSettingsTypes.COOKIES;
+    this.$.javascript.category = settings.ContentSettingsTypes.JAVASCRIPT;
+    this.$.popups.category = settings.ContentSettingsTypes.POPUPS;
+    this.$.geolocation.category = settings.ContentSettingsTypes.GEOLOCATION;
+    this.$.notification.category = settings.ContentSettingsTypes.NOTIFICATION;
+    this.$.fullscreen.category = settings.ContentSettingsTypes.FULLSCREEN;
+    this.$.camera.category = settings.ContentSettingsTypes.CAMERA;
+    this.$.mic.category = settings.ContentSettingsTypes.MIC;
+
+    this.storedData_ = '1337 MB';  // TODO(finnur): Fetch actual data.
+  },
+
+  onStoredDataChanged_: function() {
+    this.$.usage.hidden = false;
+    this.$.storage.hidden = false;
+  },
+
+  onClearStorage_: function() {
+    // TODO(finnur): Implement.
+  },
+
+  onClearAndReset_: function() {
+    Array.prototype.forEach.call(
+        this.root.querySelectorAll('site-details-permission'),
+        function(element) { element.resetPermission(); });
+
+    this.onClearStorage_();
+  },
+});
diff --git a/chrome/browser/resources/settings/site_settings/site_details_permission.css b/chrome/browser/resources/settings/site_settings/site_details_permission.css
new file mode 100644
index 0000000..85abd53f
--- /dev/null
+++ b/chrome/browser/resources/settings/site_settings/site_details_permission.css
@@ -0,0 +1,36 @@
+/* Copyright 2015 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+:host {
+  display: block;
+}
+
+.left-column {
+  -webkit-margin-start: 15px;
+}
+
+.right-column {
+  -webkit-margin-start: 10px;
+}
+
+.permission-header {
+  -webkit-margin-start: 6px;
+}
+
+.permission-list {
+  -webkit-margin-end: 35px;
+}
+
+.permission-list > paper-dropdown-menu {
+  -webkit-margin-end: 3px;
+  -webkit-margin-start: -13px;
+  margin-bottom: 12px;
+  margin-top: -20px;
+  width: 100%;
+}
+
+.permission-list > paper-dropdown-menu::shadow > paper-menu-button {
+  -webkit-margin-start: 11px;
+  width: 100%;
+}
diff --git a/chrome/browser/resources/settings/site_settings/site_details_permission.html b/chrome/browser/resources/settings/site_settings/site_details_permission.html
new file mode 100644
index 0000000..d99e49a0
--- /dev/null
+++ b/chrome/browser/resources/settings/site_settings/site_details_permission.html
@@ -0,0 +1,39 @@
+<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-icons/av-icons.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-icons/communication-icons.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-icons/social-icons.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-dropdown-menu/paper-dropdown-menu.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-item/paper-item.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-menu/paper-menu.html">
+<link rel="import" href="chrome://md-settings/prefs/prefs_behavior.html">
+<link rel="import" href="chrome://md-settings/site_settings/site_settings_behavior.html">
+
+<dom-module id="site-details-permission">
+  <link rel="import" type="css"
+      href="chrome://md-settings/settings_page/settings_page.css">
+  <link rel="import" type="css" href="site_details_permission.css">
+  <template>
+    <div id="details" class="horizontal layout top" hidden>
+      <div class="left-column">
+        <iron-icon icon="[[computeIconForContentCategory(category)]]"
+            item-icon></iron-icon>
+      </div>
+      <div class="flex right-column">
+        <div class="permission-header">
+          [[computeTitleForContentCategory(category)]]
+        </div>
+        <div class="permission-list">
+          <paper-dropdown-menu>
+            <paper-menu id="permission" class="dropdown-content">
+              <paper-item>[[i18n_.allowAction]]</paper-item>
+              <paper-item>[[i18n_.blockAction]]</paper-item>
+            </paper-menu>
+          </paper-dropdown-menu>
+        </div>
+      </div>
+    </div>
+  </template>
+  <script src="site_details_permission.js"></script>
+</dom-module>
diff --git a/chrome/browser/resources/settings/site_settings/site_details_permission.js b/chrome/browser/resources/settings/site_settings/site_details_permission.js
new file mode 100644
index 0000000..d41dd90
--- /dev/null
+++ b/chrome/browser/resources/settings/site_settings/site_details_permission.js
@@ -0,0 +1,86 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @fileoverview
+ * 'site-details-permission' handles showing the state of one permission, such
+ * as Geolocation, for a given origin.
+ *
+ * Example:
+ *
+ *      <site-details-permission prefs="{{prefs}}">
+ *      </site-details-permission>
+ *      ... other pages ...
+ *
+ * @group Chrome Settings Elements
+ * @element site-details-permission
+ */
+Polymer({
+  is: 'site-details-permission',
+
+  behaviors: [PrefsBehavior, SiteSettingsBehavior],
+
+  properties: {
+    /**
+     * Preferences state.
+     */
+    prefs: {
+      type: Object,
+      notify: true,
+    },
+
+    /**
+     * The ID of the category this widget is displaying data for.
+     */
+    category: Number,
+
+    /**
+     * The origin, which this permission affects.
+     */
+    origin: {
+      type: String,
+      observer: 'initialize_',
+    },
+
+    i18n_: {
+      readOnly: true,
+      type: Object,
+      value: function() {
+        return {
+          allowAction: loadTimeData.getString('siteSettingsActionAllow'),
+          blockAction: loadTimeData.getString('siteSettingsActionBlock'),
+        };
+      },
+    },
+  },
+
+  initialize_: function() {
+    var pref = this.getPref(
+        this.computeCategoryExceptionsPrefName(this.category));
+    var originPref = pref.value[this.origin + ',*'];
+    if (originPref === undefined)
+      originPref = pref.value[this.origin + ',' + this.origin];
+    if (originPref === undefined)
+      return;
+
+    if (/** @type {{setting: number}} */(originPref.setting) ==
+        settings.PermissionValues.ALLOW) {
+      this.$.permission.selected = 0;
+      this.$.details.hidden = false;
+    } else if (originPref.setting == settings.PermissionValues.BLOCK) {
+      this.$.permission.selected = 1;
+      this.$.details.hidden = false;
+    }
+  },
+
+  resetPermission: function() {
+    var pref = this.getPref(
+        this.computeCategoryExceptionsPrefName(this.category));
+    delete pref.value[this.origin + ',' + this.origin];
+    delete pref.value[this.origin + ',*'];
+    this.setPrefValue(
+        this.computeCategoryExceptionsPrefName(this.category), pref.value);
+    this.$.details.hidden = true;
+  },
+});
diff --git a/chrome/browser/resources/settings/site_settings/site_list.js b/chrome/browser/resources/settings/site_settings/site_list.js
index 613008a..5f0f4a7e 100644
--- a/chrome/browser/resources/settings/site_settings/site_list.js
+++ b/chrome/browser/resources/settings/site_settings/site_list.js
@@ -158,9 +158,9 @@
    */
   setUpActionMenu_: function() {
     this.showAllowAction_ =
-        this.categorySubtype == settings.DefaultValues.BLOCK;
+        this.categorySubtype == settings.PermissionValues.BLOCK;
     this.showBlockAction_ =
-        this.categorySubtype == settings.DefaultValues.ALLOW &&
+        this.categorySubtype == settings.PermissionValues.ALLOW &&
         this.category != settings.ContentSettingsTypes.FULLSCREEN;
   },
 
@@ -189,7 +189,7 @@
    * @private
    */
   computeSiteListHeader_: function(siteList, toggleState) {
-    if (this.categorySubtype == settings.DefaultValues.ALLOW) {
+    if (this.categorySubtype == settings.PermissionValues.ALLOW) {
       return loadTimeData.getStringF(
           'titleAndCount',
           loadTimeData.getString(
@@ -208,7 +208,7 @@
    * @private
    */
   isAllowList_: function() {
-    return this.categorySubtype == settings.DefaultValues.ALLOW;
+    return this.categorySubtype == settings.PermissionValues.ALLOW;
   },
 
   /**
diff --git a/chrome/browser/resources/settings/site_settings/site_settings_behavior.js b/chrome/browser/resources/settings/site_settings/site_settings_behavior.js
index 50ad9bf3..a72c5c573 100644
--- a/chrome/browser/resources/settings/site_settings/site_settings_behavior.js
+++ b/chrome/browser/resources/settings/site_settings/site_settings_behavior.js
@@ -19,9 +19,9 @@
 
     // FullScreen is Allow vs. Ask.
     if (category == settings.ContentSettingsTypes.FULLSCREEN)
-      return pref.value != settings.DefaultValues.ASK;
+      return pref.value != settings.PermissionValues.ASK;
 
-    return pref.value != settings.DefaultValues.BLOCK;
+    return pref.value != settings.PermissionValues.BLOCK;
   },
 
   /**
diff --git a/chrome/browser/resources/settings/site_settings/site_settings_category.html b/chrome/browser/resources/settings/site_settings/site_settings_category.html
index 32654af7..a98a16f 100644
--- a/chrome/browser/resources/settings/site_settings/site_settings_category.html
+++ b/chrome/browser/resources/settings/site_settings/site_settings_category.html
@@ -2,35 +2,54 @@
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-icons/av-icons.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-icons/communication-icons.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-icons/social-icons.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/neon-animation/neon-animatable.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-item/paper-icon-item.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-item/paper-item-body.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-toggle-button/paper-toggle-button.html">
 <link rel="import" href="chrome://md-settings/prefs/prefs.html">
+<link rel="import" href="chrome://md-settings/settings_page/settings_animated_pages.html">
+<link rel="import" href="chrome://md-settings/settings_page/settings_subheader.html">
 <link rel="import" href="chrome://md-settings/site_settings/constants.html">
 <link rel="import" href="chrome://md-settings/site_settings/site_list.html">
 <link rel="import" href="chrome://md-settings/site_settings/site_settings_behavior.html">
+<link rel="import" href="chrome://md-settings/site_settings/site_details.html">
 
 <dom-module id="site-settings-category">
   <link rel="import" type="css"
       href="chrome://md-settings/settings_page/settings_page.css">
   <link rel="import" type="css" href="site_settings_category.css">
   <template>
-    <paper-icon-item>
-      <iron-icon icon="[[computeIconForContentCategory(category)]]" item-icon
-          ></iron-icon>
-      <paper-item-body two-line class="flex">
-        <div>[[computeTitleForContentCategory(category)]]</div>
-        <div secondary>[[computeCategoryDesc(category, categoryEnabled)]]</div>
-      </paper-item-body>
-      <paper-toggle-button id="toggle" checked="{{categoryEnabled}}"
-          on-change="onToggleChange_"></paper-toggle-button>
-    </paper-icon-item>
-    <settings-site-list id="blockList"
-        prefs="{{prefs}}" category="[[category]]"
-        category-enabled="[[categoryEnabled]]"></settings-site-list>
-    <settings-site-list id="allowList"
-        prefs="{{prefs}}" category="[[category]]"
-        category-enabled="[[categoryEnabled]]"></settings-site-list>
+    <settings-animated-pages id="pages" current-route="{{currentRoute}}"
+        section="privacy">
+      <neon-animatable id="main">
+        <paper-icon-item>
+          <iron-icon icon="[[computeIconForContentCategory(category)]]"
+              item-icon></iron-icon>
+          <paper-item-body two-line class="flex">
+            <div>[[computeTitleForContentCategory(category)]]</div>
+            <div secondary
+                >[[computeCategoryDesc(category, categoryEnabled)]]</div>
+          </paper-item-body>
+          <paper-toggle-button id="toggle" checked="{{categoryEnabled}}"
+              on-change="onToggleChange_"></paper-toggle-button>
+        </paper-icon-item>
+        <settings-site-list id="blockList"
+            prefs="{{prefs}}" category="[[category]]"
+            category-enabled="[[categoryEnabled]]"
+            selected-origin="{{selectedOrigin}}"></settings-site-list>
+        <settings-site-list id="allowList"
+            prefs="{{prefs}}" category="[[category]]"
+            category-enabled="[[categoryEnabled]]"
+            selected-origin="{{selectedOrigin}}"></settings-site-list>
+      </neon-animatable>
+      <neon-animatable id="site-details">
+        <settings-subheader
+            page-title="[[computeTitleForContentCategory(category)]]">
+        </settings-subheader>
+        <site-details prefs="{{prefs}}"
+            origin="{{selectedOrigin}}"></site-details>
+      </neon-animatable>
+    </settings-animated-pages>
   </template>
   <script src="site_settings_category.js"></script>
 </dom-module>
diff --git a/chrome/browser/resources/settings/site_settings/site_settings_category.js b/chrome/browser/resources/settings/site_settings/site_settings_category.js
index 3e6a8928..3b58fde 100644
--- a/chrome/browser/resources/settings/site_settings/site_settings_category.js
+++ b/chrome/browser/resources/settings/site_settings/site_settings_category.js
@@ -45,6 +45,14 @@
     category: {
       type: Number,
     },
+
+    /**
+     * The origin that was selected by the user in the dropdown list.
+     */
+    selectedOrigin: {
+      type: String,
+      observer: 'onSelectedOriginChanged_',
+    },
   },
 
   observers: [
@@ -52,8 +60,8 @@
   ],
 
   ready: function() {
-    this.$.blockList.categorySubtype = settings.DefaultValues.BLOCK;
-    this.$.allowList.categorySubtype = settings.DefaultValues.ALLOW;
+    this.$.blockList.categorySubtype = settings.PermissionValues.BLOCK;
+    this.$.allowList.categorySubtype = settings.PermissionValues.ALLOW;
 
     CrSettingsPrefs.initialized.then(function() {
       this.categoryEnabled = this.isCategoryAllowed(this.category);
@@ -74,8 +82,8 @@
         // "Allowed" vs "Blocked".
         this.setPrefValue(this.computeCategoryPrefName(this.category),
                           this.categoryEnabled ?
-                              settings.DefaultValues.ALLOW :
-                              settings.DefaultValues.BLOCK);
+                              settings.PermissionValues.ALLOW :
+                              settings.PermissionValues.BLOCK);
         break;
       case settings.ContentSettingsTypes.NOTIFICATION:
       case settings.ContentSettingsTypes.GEOLOCATION:
@@ -84,21 +92,25 @@
         // "Ask" vs "Blocked".
         this.setPrefValue(this.computeCategoryPrefName(this.category),
                           this.categoryEnabled ?
-                              settings.DefaultValues.ASK :
-                              settings.DefaultValues.BLOCK);
+                              settings.PermissionValues.ASK :
+                              settings.PermissionValues.BLOCK);
         break;
       case settings.ContentSettingsTypes.FULLSCREEN:
         // "Allowed" vs. "Ask first".
         this.setPrefValue(this.computeCategoryPrefName(this.category),
                           this.categoryEnabled ?
-                              settings.DefaultValues.ALLOW :
-                              settings.DefaultValues.ASK);
+                              settings.PermissionValues.ALLOW :
+                              settings.PermissionValues.ASK);
         break;
       default:
         assertNotReached();
     }
   },
 
+  onSelectedOriginChanged_: function() {
+    this.$.pages.setSubpageChain(['site-details']);
+  },
+
   /**
    * Handles when the global toggle changes.
    * @private
diff --git a/chrome/browser/safe_browsing/incident_reporting/incident_reporting_service.cc b/chrome/browser/safe_browsing/incident_reporting/incident_reporting_service.cc
index 3428c862..14bddec 100644
--- a/chrome/browser/safe_browsing/incident_reporting/incident_reporting_service.cc
+++ b/chrome/browser/safe_browsing/incident_reporting/incident_reporting_service.cc
@@ -797,7 +797,9 @@
 }
 
 void IncidentReportingService::OnLastDownloadFound(
-    scoped_ptr<ClientIncidentReport_DownloadDetails> last_download) {
+    scoped_ptr<ClientIncidentReport_DownloadDetails> last_binary_download,
+    scoped_ptr<ClientIncidentReport_NonBinaryDownloadDetails>
+        last_non_binary_download) {
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(report_);
 
@@ -808,8 +810,13 @@
   // Harvest the finder.
   last_download_finder_.reset();
 
-  if (last_download)
-    report_->set_allocated_download(last_download.release());
+  if (last_binary_download)
+    report_->set_allocated_download(last_binary_download.release());
+
+  if (last_non_binary_download) {
+    report_->set_allocated_non_binary_download(
+        last_non_binary_download.release());
+  }
 
   ProcessIncidentsIfCollectionComplete();
 }
@@ -885,6 +892,9 @@
   if (!HasIncidentsToUpload())
     return;
 
+  bool has_download =
+      report->has_download() || report->has_non_binary_download();
+
   // Collect incidents across all profiles participating in safe browsing. Drop
   // incidents if the profile stopped participating before collection completed.
   // Prune previously submitted incidents.
@@ -912,7 +922,7 @@
       if (context->state_store->HasBeenReported(state.type, state.key,
                                                 state.digest)) {
         LogIncidentDataType(PRUNED, *incident);
-      } else if (!report->has_download()) {
+      } else if (!has_download) {
         LogIncidentDataType(NO_DOWNLOAD, *incident);
         // Drop the incident and mark for future pruning since no executable
         // download was found.
@@ -936,7 +946,7 @@
 
   // Abandon the request if all incidents were pruned or otherwise dropped.
   if (!count) {
-    if (!report->has_download()) {
+    if (!has_download) {
       UMA_HISTOGRAM_ENUMERATION("SBIRS.UploadResult",
                                 IncidentReportUploader::UPLOAD_NO_DOWNLOAD,
                                 IncidentReportUploader::NUM_UPLOAD_RESULTS);
diff --git a/chrome/browser/safe_browsing/incident_reporting/incident_reporting_service.h b/chrome/browser/safe_browsing/incident_reporting/incident_reporting_service.h
index 9cd72a9..883a203 100644
--- a/chrome/browser/safe_browsing/incident_reporting/incident_reporting_service.h
+++ b/chrome/browser/safe_browsing/incident_reporting/incident_reporting_service.h
@@ -231,9 +231,12 @@
   void CancelDownloadCollection();
 
   // A callback invoked on the UI thread by the last download finder when the
-  // search for the most recent binary download is complete.
+  // search for the most recent binary download and most recent non-binary
+  // download is complete.
   void OnLastDownloadFound(
-      scoped_ptr<ClientIncidentReport_DownloadDetails> last_download);
+      scoped_ptr<ClientIncidentReport_DownloadDetails> last_binary_download,
+      scoped_ptr<ClientIncidentReport_NonBinaryDownloadDetails>
+          last_non_binary_download);
 
   // Processes all received incidents once all data collection is
   // complete. Incidents originating from profiles that do not participate in
diff --git a/chrome/browser/safe_browsing/incident_reporting/incident_reporting_service_unittest.cc b/chrome/browser/safe_browsing/incident_reporting/incident_reporting_service_unittest.cc
index 40c6b23..99fdd29 100644
--- a/chrome/browser/safe_browsing/incident_reporting/incident_reporting_service_unittest.cc
+++ b/chrome/browser/safe_browsing/incident_reporting/incident_reporting_service_unittest.cc
@@ -157,8 +157,12 @@
   // A type for specifying the action to be taken by the test fixture when the
   // service creates a LastDownloadFinder.
   enum OnCreateDownloadFinderAction {
-    // Post a task that reports a download.
-    ON_CREATE_DOWNLOAD_FINDER_DOWNLOAD_FOUND,
+    // Post a task that reports a binary and non-binary download.
+    ON_CREATE_DOWNLOAD_FINDER_DOWNLOADS_FOUND,
+    // Post a task that reports a binary download.
+    ON_CREATE_DOWNLOAD_FINDER_BINARY_DOWNLOAD_FOUND,
+    // Post a task that reports a non-binary download.
+    ON_CREATE_DOWNLOAD_FINDER_NON_BINARY_DOWNLOAD_FOUND,
     // Post a task that reports no downloads found.
     ON_CREATE_DOWNLOAD_FINDER_NO_DOWNLOADS,
     // Immediately return due to a lack of eligible profiles.
@@ -174,6 +178,7 @@
 
   static const char kFakeOsName[];
   static const char kFakeDownloadToken[];
+  static const char kFakeDownloadHost[];
   static const char kTestTrackedPrefPath[];
   static const char kFakeExtensionId[];
 
@@ -182,7 +187,7 @@
         thread_task_runner_handle_(task_runner_),
         profile_manager_(TestingBrowserProcess::GetGlobal()),
         on_create_download_finder_action_(
-            ON_CREATE_DOWNLOAD_FINDER_DOWNLOAD_FOUND),
+            ON_CREATE_DOWNLOAD_FINDER_DOWNLOADS_FOUND),
         on_delayed_analysis_action_(ON_DELAYED_ANALYSIS_NO_ACTION),
         upload_result_(safe_browsing::IncidentReportUploader::UPLOAD_SUCCESS),
         environment_collected_(),
@@ -302,37 +307,11 @@
                    base::Unretained(this)));
   }
 
-  // Confirms that the test incident(s) was/were uploaded by the service, then
-  // clears the instance for subsequent incidents.
-  void ExpectTestIncidentUploaded(int incident_count) {
-    if (incident_count == 0) {
-      ASSERT_FALSE(uploaded_report_);
-      return;
-    }
-    ASSERT_TRUE(uploaded_report_);
-    ASSERT_EQ(incident_count, uploaded_report_->incident_size());
-    for (int i = 0; i < incident_count; ++i) {
-      ASSERT_TRUE(uploaded_report_->incident(i).has_incident_time_msec());
-      ASSERT_NE(0LL, uploaded_report_->incident(i).incident_time_msec());
-      ASSERT_TRUE(uploaded_report_->incident(i).has_tracked_preference());
-      ASSERT_TRUE(
-          uploaded_report_->incident(i).tracked_preference().has_path());
-      ASSERT_EQ(std::string(kTestTrackedPrefPath),
-                uploaded_report_->incident(i).tracked_preference().path());
-    }
-    ASSERT_TRUE(uploaded_report_->has_environment());
-    ASSERT_TRUE(uploaded_report_->environment().has_os());
-    ASSERT_TRUE(uploaded_report_->environment().os().has_os_name());
-    ASSERT_EQ(std::string(kFakeOsName),
-              uploaded_report_->environment().os().os_name());
-    ASSERT_EQ(
-        std::string(kFakeExtensionId),
-        uploaded_report_->extension_data().last_installed_extension().id());
-    ASSERT_EQ(std::string(kFakeDownloadToken),
-              uploaded_report_->download().token());
-
-    uploaded_report_.reset();
-  }
+  // Expects that |incident_count| incidents were uploaded by the service with
+  // the described downloads, then clears the instance for subsequent incidents.
+  void ExpectTestIncidentUploadWithBinaryDownload(int incident_count);
+  void ExpectTestIncidentUploadWithNonBinaryDownload(int incident_count);
+  void ExpectTestIncidentUploadWithBothDownloads(int incident_count);
 
   void AssertNoUpload() { ASSERT_FALSE(uploaded_report_); }
 
@@ -400,12 +379,15 @@
     static scoped_ptr<safe_browsing::LastDownloadFinder> Create(
         const base::Closure& on_deleted,
         scoped_ptr<safe_browsing::ClientIncidentReport_DownloadDetails>
-            download,
+            binary_download,
+        scoped_ptr<safe_browsing::ClientIncidentReport_NonBinaryDownloadDetails>
+            non_binary_download,
         const safe_browsing::LastDownloadFinder::LastDownloadCallback&
             callback) {
       // Post a task to run the callback.
       base::ThreadTaskRunnerHandle::Get()->PostTask(
-          FROM_HERE, base::Bind(callback, base::Passed(&download)));
+          FROM_HERE, base::Bind(callback, base::Passed(&binary_download),
+                                base::Passed(&non_binary_download)));
       return scoped_ptr<safe_browsing::LastDownloadFinder>(
           new FakeDownloadFinder(on_deleted));
     }
@@ -421,6 +403,47 @@
     DISALLOW_COPY_AND_ASSIGN(FakeDownloadFinder);
   };
 
+  // Confirms that the test incident(s) was/were uploaded by the service, then
+  // clears the instance for subsequent incidents.
+  void ExpectTestIncidentUploadedImpl(int incident_count,
+                                      bool withBinaryDownload,
+                                      bool withNonBinaryDownload) {
+    if (incident_count == 0) {
+      ASSERT_FALSE(uploaded_report_);
+      return;
+    }
+    ASSERT_TRUE(uploaded_report_);
+    ASSERT_EQ(incident_count, uploaded_report_->incident_size());
+    for (int i = 0; i < incident_count; ++i) {
+      ASSERT_TRUE(uploaded_report_->incident(i).has_incident_time_msec());
+      ASSERT_NE(0LL, uploaded_report_->incident(i).incident_time_msec());
+      ASSERT_TRUE(uploaded_report_->incident(i).has_tracked_preference());
+      ASSERT_TRUE(
+          uploaded_report_->incident(i).tracked_preference().has_path());
+      ASSERT_EQ(std::string(kTestTrackedPrefPath),
+                uploaded_report_->incident(i).tracked_preference().path());
+    }
+    ASSERT_TRUE(uploaded_report_->has_environment());
+    ASSERT_TRUE(uploaded_report_->environment().has_os());
+    ASSERT_TRUE(uploaded_report_->environment().os().has_os_name());
+    ASSERT_EQ(std::string(kFakeOsName),
+              uploaded_report_->environment().os().os_name());
+    ASSERT_EQ(
+        std::string(kFakeExtensionId),
+        uploaded_report_->extension_data().last_installed_extension().id());
+
+    if (withBinaryDownload) {
+      ASSERT_EQ(std::string(kFakeDownloadToken),
+                uploaded_report_->download().token());
+    }
+    if (withNonBinaryDownload) {
+      ASSERT_EQ(std::string(kFakeDownloadHost),
+                uploaded_report_->non_binary_download().host());
+    }
+
+    uploaded_report_.reset();
+  }
+
   // Properties for a profile that impact the behavior of the test.
   struct ProfileProperties {
     ProfileProperties() : on_addition_action(ON_PROFILE_ADDITION_NO_ACTION) {}
@@ -477,22 +500,36 @@
   scoped_ptr<safe_browsing::LastDownloadFinder> CreateDownloadFinder(
       const safe_browsing::LastDownloadFinder::LastDownloadCallback& callback) {
     download_finder_created_ = true;
-    scoped_ptr<safe_browsing::ClientIncidentReport_DownloadDetails> download;
+    scoped_ptr<safe_browsing::ClientIncidentReport_DownloadDetails>
+        binary_download;
+    scoped_ptr<safe_browsing::ClientIncidentReport_NonBinaryDownloadDetails>
+        non_binary_download;
     if (on_create_download_finder_action_ ==
         ON_CREATE_DOWNLOAD_FINDER_NO_PROFILES) {
       return scoped_ptr<safe_browsing::LastDownloadFinder>();
     }
     if (on_create_download_finder_action_ ==
-        ON_CREATE_DOWNLOAD_FINDER_DOWNLOAD_FOUND) {
-      download.reset(new safe_browsing::ClientIncidentReport_DownloadDetails);
-      download->set_token(kFakeDownloadToken);
+            ON_CREATE_DOWNLOAD_FINDER_DOWNLOADS_FOUND ||
+        on_create_download_finder_action_ ==
+            ON_CREATE_DOWNLOAD_FINDER_BINARY_DOWNLOAD_FOUND) {
+      binary_download.reset(
+          new safe_browsing::ClientIncidentReport_DownloadDetails);
+      binary_download->set_token(kFakeDownloadToken);
     }
+    if (on_create_download_finder_action_ ==
+            ON_CREATE_DOWNLOAD_FINDER_DOWNLOADS_FOUND ||
+        on_create_download_finder_action_ ==
+            ON_CREATE_DOWNLOAD_FINDER_NON_BINARY_DOWNLOAD_FOUND) {
+      non_binary_download.reset(
+          new safe_browsing::ClientIncidentReport_NonBinaryDownloadDetails);
+      non_binary_download->set_host(kFakeDownloadHost);
+    }
+
     return scoped_ptr<safe_browsing::LastDownloadFinder>(
         FakeDownloadFinder::Create(
             base::Bind(&IncidentReportingServiceTest::OnDownloadFinderDestroyed,
                        base::Unretained(this)),
-            download.Pass(),
-            callback));
+            binary_download.Pass(), non_binary_download.Pass(), callback));
   }
 
   // A fake StartUpload implementation invoked by the service during operation.
@@ -535,8 +572,24 @@
     IncidentReportingServiceTest::TestIncidentReportingService::test_instance_ =
         LAZY_INSTANCE_INITIALIZER;
 
+void IncidentReportingServiceTest::ExpectTestIncidentUploadWithBinaryDownload(
+    int incident_count) {
+  ExpectTestIncidentUploadedImpl(incident_count, true, false);
+}
+
+void IncidentReportingServiceTest::
+    ExpectTestIncidentUploadWithNonBinaryDownload(int incident_count) {
+  ExpectTestIncidentUploadedImpl(incident_count, false, true);
+}
+
+void IncidentReportingServiceTest::ExpectTestIncidentUploadWithBothDownloads(
+    int incident_count) {
+  ExpectTestIncidentUploadedImpl(incident_count, true, false);
+}
+
 const char IncidentReportingServiceTest::kFakeOsName[] = "fakedows";
 const char IncidentReportingServiceTest::kFakeDownloadToken[] = "fakedlt";
+const char IncidentReportingServiceTest::kFakeDownloadHost[] = "chromium.org";
 const char IncidentReportingServiceTest::kTestTrackedPrefPath[] = "some_pref";
 const char IncidentReportingServiceTest::kFakeExtensionId[] = "fakeExtensionId";
 
@@ -561,7 +614,7 @@
 
   // Verify that report upload took place and contained the incident,
   // environment data, and download details.
-  ExpectTestIncidentUploaded(1);
+  ExpectTestIncidentUploadWithBinaryDownload(1);
 
   // Verify that the download finder and the uploader were destroyed.
   ASSERT_TRUE(DownloadFinderDestroyed());
@@ -591,7 +644,7 @@
 
   // Verify that report upload took place and contained the incident,
   // environment data, and download details.
-  ExpectTestIncidentUploaded(2);
+  ExpectTestIncidentUploadWithBinaryDownload(2);
 
   // Verify that the download finder and the uploader were destroyed.
   ASSERT_TRUE(DownloadFinderDestroyed());
@@ -640,7 +693,7 @@
 
   // Verify that report upload took place and contained the incident,
   // environment data, and download details.
-  ExpectTestIncidentUploaded(1);
+  ExpectTestIncidentUploadWithBinaryDownload(1);
 
   // Verify that the download finder and the uploader were destroyed.
   ASSERT_TRUE(DownloadFinderDestroyed());
@@ -697,7 +750,7 @@
 
   // Verify that report upload took place and contained the incident,
   // environment data, and download details.
-  ExpectTestIncidentUploaded(1);
+  ExpectTestIncidentUploadWithBinaryDownload(1);
 
   // Verify that the download finder and the uploader were destroyed.
   ASSERT_TRUE(DownloadFinderDestroyed());
@@ -754,7 +807,7 @@
 
   // Verify that a report upload took place, and only the second incident was
   // uploaded.
-  ExpectTestIncidentUploaded(1);
+  ExpectTestIncidentUploadWithBinaryDownload(1);
 
   // Ensure that no report processing remains.
   ASSERT_FALSE(instance_->IsProcessingReport());
@@ -802,7 +855,7 @@
   AssertNoUpload();
 
   // Tell the fixture to return a download now.
-  SetCreateDownloadFinderAction(ON_CREATE_DOWNLOAD_FINDER_DOWNLOAD_FOUND);
+  SetCreateDownloadFinderAction(ON_CREATE_DOWNLOAD_FINDER_DOWNLOADS_FOUND);
 
   // Add a variation on the incident to the service.
   instance_->GetIncidentReceiver()->AddIncidentForProfile(
@@ -812,7 +865,7 @@
   task_runner_->RunUntilIdle();
 
   // Verify that an additional report upload took place.
-  ExpectTestIncidentUploaded(1);
+  ExpectTestIncidentUploadWithBinaryDownload(1);
 
   // Ensure that no report processing remains.
   ASSERT_FALSE(instance_->IsProcessingReport());
@@ -836,7 +889,7 @@
   AssertNoUpload();
 
   // Tell the fixture to return a download now.
-  SetCreateDownloadFinderAction(ON_CREATE_DOWNLOAD_FINDER_DOWNLOAD_FOUND);
+  SetCreateDownloadFinderAction(ON_CREATE_DOWNLOAD_FINDER_DOWNLOADS_FOUND);
 
   // Add the incident to the service again.
   AddTestIncident(profile);
@@ -889,7 +942,7 @@
 
   // Verify that report upload took place and contained the incident and
   // environment data.
-  ExpectTestIncidentUploaded(1);
+  ExpectTestIncidentUploadWithBinaryDownload(1);
 
   // Add the incident to the service again.
   AddTestIncident(profile);
@@ -917,7 +970,7 @@
 
   // Verify that report upload took place and contained the incident and
   // environment data.
-  ExpectTestIncidentUploaded(1);
+  ExpectTestIncidentUploadWithBinaryDownload(1);
 
   // Add a variation on the incident to the service.
   instance_->GetIncidentReceiver()->AddIncidentForProfile(
@@ -927,7 +980,7 @@
   task_runner_->RunUntilIdle();
 
   // Verify that an additional report upload took place.
-  ExpectTestIncidentUploaded(1);
+  ExpectTestIncidentUploadWithBinaryDownload(1);
 
   // Ensure that no report processing remains.
   ASSERT_FALSE(instance_->IsProcessingReport());
@@ -946,7 +999,7 @@
 
   // Verify that report upload took place and contained the incident and
   // environment data.
-  ExpectTestIncidentUploaded(1);
+  ExpectTestIncidentUploadWithBinaryDownload(1);
 
   // Create a second profile with its own incident on addition.
   CreateProfile("profile2", EXTENDED_REPORTING_OPT_IN,
@@ -956,7 +1009,7 @@
   task_runner_->RunUntilIdle();
 
   // Verify that a second report upload took place.
-  ExpectTestIncidentUploaded(1);
+  ExpectTestIncidentUploadWithBinaryDownload(1);
 
   // Ensure that no report processing remains.
   ASSERT_FALSE(instance_->IsProcessingReport());
@@ -979,7 +1032,7 @@
 
   // Verify that report upload took place and contained the incident and
   // environment data.
-  ExpectTestIncidentUploaded(1);
+  ExpectTestIncidentUploadWithBinaryDownload(1);
 
   // Ensure that no report processing remains.
   ASSERT_FALSE(instance_->IsProcessingReport());
@@ -1020,7 +1073,7 @@
   task_runner_->RunUntilIdle();
 
   // An upload should have taken place.
-  ExpectTestIncidentUploaded(1);
+  ExpectTestIncidentUploadWithBinaryDownload(1);
 
   // Add the incident to the service again.
   AddTestIncident(NULL);
@@ -1052,7 +1105,7 @@
   task_runner_->RunUntilIdle();
 
   // An upload should have taken place.
-  ExpectTestIncidentUploaded(1);
+  ExpectTestIncidentUploadWithBinaryDownload(1);
 
   // Add a variation on the incident to the service.
   receiver->AddIncidentForProcess(MakeTestIncident("leeches"));
@@ -1061,7 +1114,7 @@
   task_runner_->RunUntilIdle();
 
   // Verify that an additional report upload took place.
-  ExpectTestIncidentUploaded(1);
+  ExpectTestIncidentUploadWithBinaryDownload(1);
 
   // Ensure that no report processing remains.
   ASSERT_FALSE(instance_->IsProcessingReport());
@@ -1215,7 +1268,7 @@
   ASSERT_TRUE(DelayedAnalysisRan());
 
   // An upload should have taken place.
-  ExpectTestIncidentUploaded(1);
+  ExpectTestIncidentUploadWithBinaryDownload(1);
 
   // Add the incident to the service again.
   AddTestIncident(NULL);
@@ -1259,6 +1312,59 @@
   ASSERT_FALSE(instance_->IsProcessingReport());
 }
 
+// Tests that the service sends the report if a non-binary download is found.
+TEST_F(IncidentReportingServiceTest, NonBinaryDownloadStillUploads) {
+  SetFieldTrialAndCreateService(false);
+  // Tell the fixture to return only the last non-binary download.
+  SetCreateDownloadFinderAction(
+      ON_CREATE_DOWNLOAD_FINDER_NON_BINARY_DOWNLOAD_FOUND);
+
+  // Register a callback.
+  RegisterAnalysis(ON_DELAYED_ANALYSIS_ADD_INCIDENT);
+
+  // Add a profile that participates in safe browsing.
+  CreateProfile("profile1", EXTENDED_REPORTING_OPT_IN,
+                ON_PROFILE_ADDITION_NO_ACTION, nullptr);
+
+  // Let all tasks run.
+  task_runner_->RunUntilIdle();
+
+  // Confirm that the callbacks were run.
+  ASSERT_TRUE(DelayedAnalysisRan());
+
+  // Verify that a report upload took place.
+  ExpectTestIncidentUploadWithNonBinaryDownload(1);
+
+  // Ensure that no report processing remains.
+  ASSERT_FALSE(instance_->IsProcessingReport());
+}
+
+// Tests that the service can send both a binary and non-binary download.
+TEST_F(IncidentReportingServiceTest, UploadsWithBothDownloadTypes) {
+  SetFieldTrialAndCreateService(false);
+  // Tell the fixture to return only the last non-binary download.
+  SetCreateDownloadFinderAction(ON_CREATE_DOWNLOAD_FINDER_DOWNLOADS_FOUND);
+
+  // Register a callback.
+  RegisterAnalysis(ON_DELAYED_ANALYSIS_ADD_INCIDENT);
+
+  // Add a profile that participates in safe browsing.
+  CreateProfile("profile1", EXTENDED_REPORTING_OPT_IN,
+                ON_PROFILE_ADDITION_NO_ACTION, nullptr);
+
+  // Let all tasks run.
+  task_runner_->RunUntilIdle();
+
+  // Confirm that the callbacks were run.
+  ASSERT_TRUE(DelayedAnalysisRan());
+
+  // Verify that a report upload took place.
+  ExpectTestIncidentUploadWithBothDownloads(1);
+
+  // Ensure that no report processing remains.
+  ASSERT_FALSE(instance_->IsProcessingReport());
+}
+
 // Test that a profile's prune state is properly cleaned upon load.
 TEST_F(IncidentReportingServiceTest, CleanLegacyPruneState) {
   SetFieldTrialAndCreateService(false);
@@ -1310,7 +1416,7 @@
   task_runner_->RunUntilIdle();
 
   // An upload should have taken place.
-  ExpectTestIncidentUploaded(1);
+  ExpectTestIncidentUploadWithBinaryDownload(1);
 
   // Clear incident data.
   receiver->ClearIncidentForProcess(MakeTestIncident(nullptr));
@@ -1319,7 +1425,7 @@
   task_runner_->RunUntilIdle();
 
   // No uploads should have taken place.
-  ExpectTestIncidentUploaded(0);
+  ExpectTestIncidentUploadWithBinaryDownload(0);
 
   // Add the incident to the service again.
   receiver->AddIncidentForProcess(MakeTestIncident(nullptr));
@@ -1328,7 +1434,7 @@
   task_runner_->RunUntilIdle();
 
   // An upload should have taken place.
-  ExpectTestIncidentUploaded(1);
+  ExpectTestIncidentUploadWithBinaryDownload(1);
 
   // Ensure that no report processing remains.
   ASSERT_FALSE(instance_->IsProcessingReport());
@@ -1350,7 +1456,7 @@
   task_runner_->RunUntilIdle();
 
   // No uploads should have taken place.
-  ExpectTestIncidentUploaded(0);
+  ExpectTestIncidentUploadWithBinaryDownload(0);
 
   // Downloads and environment data should have not been collected.
   ASSERT_FALSE(HasCreatedDownloadFinder());
diff --git a/chrome/browser/safe_browsing/incident_reporting/last_download_finder.cc b/chrome/browser/safe_browsing/incident_reporting/last_download_finder.cc
index 5b846a3..a78f459 100644
--- a/chrome/browser/safe_browsing/incident_reporting/last_download_finder.cc
+++ b/chrome/browser/safe_browsing/incident_reporting/last_download_finder.cc
@@ -11,6 +11,8 @@
 #include "base/bind.h"
 #include "base/macros.h"
 #include "base/prefs/pref_service.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/history/history_service_factory.h"
@@ -24,6 +26,7 @@
 #include "content/public/browser/notification_details.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/notification_source.h"
+#include "crypto/sha2.h"
 
 namespace safe_browsing {
 
@@ -76,7 +79,7 @@
   return download_type == ClientDownloadRequest::WIN_EXECUTABLE;
 }
 
-// Returns true if a download represented by a DownloadRow is binary file for
+// Returns true if a download represented by a DownloadRow is a binary file for
 // the current OS.
 bool IsBinaryDownload(const history::DownloadRow& row) {
   // TODO(grt): Peek into archives to see if they contain binaries;
@@ -87,6 +90,11 @@
               download_protection_util::GetDownloadType(row.target_path)));
 }
 
+// Returns true if a download represented by a DownloadRow is not a binary file.
+bool IsNonBinaryDownload(const history::DownloadRow& row) {
+  return !download_protection_util::IsSupportedBinaryFile(row.target_path);
+}
+
 // Returns true if a download represented by a DownloadDetails is binary file
 // for the current OS.
 bool IsBinaryDownload(const ClientIncidentReport_DownloadDetails& details) {
@@ -108,24 +116,39 @@
 // non-opened for downloads that completed at the same time (extraordinarily
 // unlikely). Only files that look like some kind of executable are considered.
 template <class A, class B>
-bool IsMoreInterestingThan(const A& first, const B& second) {
+bool IsMoreInterestingBinaryThan(const A& first, const B& second) {
   if (GetEndTime(first) < GetEndTime(second) || !IsBinaryDownload(first))
     return false;
   return (GetEndTime(first) != GetEndTime(second) ||
           (HasBeenOpened(first) && !HasBeenOpened(second)));
 }
 
+// Returns true if |first| is more recent than |second|, preferring opened over
+// non-opened for downloads that completed at the same time (extraordinarily
+// unlikely). Only files that do not look like an executable are considered.
+bool IsMoreInterestingNonBinaryThan(const history::DownloadRow& first,
+                                    const history::DownloadRow& second) {
+  if (GetEndTime(first) < GetEndTime(second) || !IsNonBinaryDownload(first))
+    return false;
+  return (GetEndTime(first) != GetEndTime(second) ||
+          (HasBeenOpened(first) && !HasBeenOpened(second)));
+}
+
 // Returns a pointer to the most interesting completed download in |downloads|.
 const history::DownloadRow* FindMostInteresting(
-    const std::vector<history::DownloadRow>& downloads) {
-  const history::DownloadRow* most_recent_row = NULL;
-  for (size_t i = 0; i < downloads.size(); ++i) {
-    const history::DownloadRow& row = downloads[i];
+    const std::vector<history::DownloadRow>& downloads,
+    bool is_binary) {
+  const history::DownloadRow* most_recent_row = nullptr;
+  for (const auto& row : downloads) {
     // Ignore incomplete downloads.
     if (row.state != history::DownloadState::COMPLETE)
       continue;
-    if (!most_recent_row || IsMoreInterestingThan(row, *most_recent_row))
+
+    if (!most_recent_row ||
+        (is_binary ? IsMoreInterestingBinaryThan(row, *most_recent_row)
+                   : IsMoreInterestingNonBinaryThan(row, *most_recent_row))) {
       most_recent_row = &row;
+    }
   }
   return most_recent_row;
 }
@@ -133,12 +156,12 @@
 // Returns true if |candidate| is more interesting than whichever of |details|
 // or |best_row| is present.
 template <class D>
-bool IsMostInteresting(const D& candidate,
-                       const ClientIncidentReport_DownloadDetails* details,
-                       const history::DownloadRow& best_row) {
-  return details ?
-      IsMoreInterestingThan(candidate, *details) :
-      IsMoreInterestingThan(candidate, best_row);
+bool IsMostInterestingBinary(
+    const D& candidate,
+    const ClientIncidentReport_DownloadDetails* details,
+    const history::DownloadRow& best_row) {
+  return details ? IsMoreInterestingBinaryThan(candidate, *details)
+                 : IsMoreInterestingBinaryThan(candidate, best_row);
 }
 
 // Populates the |details| protobuf with information pertaining to |download|.
@@ -177,6 +200,22 @@
     details->set_open_time_msec(download.end_time.ToJavaTime());
 }
 
+// Populates the |details| protobuf with information pertaining to the
+// (non-binary) |download|.
+void PopulateNonBinaryDetailsFromRow(
+    const history::DownloadRow& download,
+    ClientIncidentReport_NonBinaryDownloadDetails* details) {
+  details->set_file_type(
+      base::FilePath(
+          download_protection_util::GetFileExtension(download.target_path))
+          .AsUTF8Unsafe());
+  details->set_length(download.received_bytes);
+  if (download.url_chain.back().has_host())
+    details->set_host(download.url_chain.back().host());
+  details->set_url_spec_sha256(
+      crypto::SHA256HashString(download.url_chain.back().spec()));
+}
+
 }  // namespace
 
 LastDownloadFinder::~LastDownloadFinder() {
@@ -251,32 +290,32 @@
     return;
 
   if (details) {
-    if (IsMostInteresting(*details, details_.get(), most_recent_row_)) {
+    if (IsMostInterestingBinary(*details, details_.get(),
+                                most_recent_binary_row_)) {
       details_ = details.Pass();
-      most_recent_row_.end_time = base::Time();
+      most_recent_binary_row_.end_time = base::Time();
     }
-
-    RemoveProfileAndReportIfDone(iter);
+    iter->second = WAITING_FOR_NON_BINARY_HISTORY;
   } else {
-    // Search history since no metadata was found.
     iter->second = WAITING_FOR_HISTORY;
-    history::HistoryService* history_service =
-        HistoryServiceFactory::GetForProfile(
-            profile, ServiceAccessType::IMPLICIT_ACCESS);
-    // No history service is returned for profiles that do not save history.
-    if (!history_service) {
-      RemoveProfileAndReportIfDone(iter);
-      return;
-    }
-    if (history_service->BackendLoaded()) {
-      history_service->QueryDownloads(
-          base::Bind(&LastDownloadFinder::OnDownloadQuery,
-                     weak_ptr_factory_.GetWeakPtr(),
-                     profile));
-    } else {
-      // else wait until history is loaded.
-      history_service_observer_.Add(history_service);
-    }
+  }
+
+  // Initiate a history search
+  history::HistoryService* history_service =
+      HistoryServiceFactory::GetForProfile(profile,
+                                           ServiceAccessType::IMPLICIT_ACCESS);
+  // No history service is returned for profiles that do not save history.
+  if (!history_service) {
+    RemoveProfileAndReportIfDone(iter);
+    return;
+  }
+  if (history_service->BackendLoaded()) {
+    history_service->QueryDownloads(
+        base::Bind(&LastDownloadFinder::OnDownloadQuery,
+                   weak_ptr_factory_.GetWeakPtr(), profile));
+  } else {
+    // else wait until history is loaded.
+    history_service_observer_.Add(history_service);
   }
 }
 
@@ -295,13 +334,26 @@
   if (iter == profile_states_.end())
     return;
 
-  // Find the most recent from this profile and use it if it's better than
-  // anything else found so far.
-  const history::DownloadRow* profile_best = FindMostInteresting(*downloads);
-  if (profile_best &&
-      IsMostInteresting(*profile_best, details_.get(), most_recent_row_)) {
-    details_.reset();
-    most_recent_row_ = *profile_best;
+  // Don't overwrite the download from metadata if it came from this profile.
+  if (iter->second == WAITING_FOR_HISTORY) {
+    // Find the most recent from this profile and use it if it's better than
+    // anything else found so far.
+    const history::DownloadRow* profile_best_binary =
+        FindMostInteresting(*downloads, true);
+    if (profile_best_binary &&
+        IsMostInterestingBinary(*profile_best_binary, details_.get(),
+                                most_recent_binary_row_)) {
+      details_.reset();
+      most_recent_binary_row_ = *profile_best_binary;
+    }
+  }
+
+  const history::DownloadRow* profile_best_non_binary =
+      FindMostInteresting(*downloads, false);
+  if (profile_best_non_binary &&
+      IsMoreInterestingNonBinaryThan(*profile_best_non_binary,
+                                     most_recent_non_binary_row_)) {
+    most_recent_non_binary_row_ = *profile_best_non_binary;
   }
 
   RemoveProfileAndReportIfDone(iter);
@@ -320,23 +372,28 @@
 
 void LastDownloadFinder::ReportResults() {
   DCHECK(profile_states_.empty());
+
+  scoped_ptr<ClientIncidentReport_DownloadDetails> binary_details = nullptr;
+  scoped_ptr<ClientIncidentReport_NonBinaryDownloadDetails> non_binary_details =
+      nullptr;
+
   if (details_) {
-    callback_.Run(make_scoped_ptr(new ClientIncidentReport_DownloadDetails(
-                                      *details_)).Pass());
-    // Do not touch this LastDownloadFinder after running the callback, since it
-    // may have been deleted.
-  } else if (!most_recent_row_.end_time.is_null()) {
-    scoped_ptr<ClientIncidentReport_DownloadDetails> details(
-        new ClientIncidentReport_DownloadDetails());
-    PopulateDetailsFromRow(most_recent_row_, details.get());
-    callback_.Run(details.Pass());
-    // Do not touch this LastDownloadFinder after running the callback, since it
-    // may have been deleted.
-  } else {
-    callback_.Run(scoped_ptr<ClientIncidentReport_DownloadDetails>());
-    // Do not touch this LastDownloadFinder after running the callback, since it
-    // may have been deleted.
+    binary_details.reset(new ClientIncidentReport_DownloadDetails(*details_));
+  } else if (!most_recent_binary_row_.end_time.is_null()) {
+    binary_details.reset(new ClientIncidentReport_DownloadDetails());
+    PopulateDetailsFromRow(most_recent_binary_row_, binary_details.get());
   }
+
+  if (!most_recent_non_binary_row_.end_time.is_null()) {
+    non_binary_details.reset(
+        new ClientIncidentReport_NonBinaryDownloadDetails());
+    PopulateNonBinaryDetailsFromRow(most_recent_non_binary_row_,
+                                    non_binary_details.get());
+  }
+
+  callback_.Run(binary_details.Pass(), non_binary_details.Pass());
+  // Do not touch this LastDownloadFinder after running the callback, since it
+  // may have been deleted.
 }
 
 void LastDownloadFinder::Observe(int type,
@@ -362,7 +419,8 @@
     if (hs == history_service) {
       // Start the query in the history service if the finder was waiting for
       // the service to load.
-      if (pair.second == WAITING_FOR_HISTORY) {
+      if (pair.second == WAITING_FOR_HISTORY ||
+          pair.second == WAITING_FOR_NON_BINARY_HISTORY) {
         history_service->QueryDownloads(
             base::Bind(&LastDownloadFinder::OnDownloadQuery,
                        weak_ptr_factory_.GetWeakPtr(),
diff --git a/chrome/browser/safe_browsing/incident_reporting/last_download_finder.h b/chrome/browser/safe_browsing/incident_reporting/last_download_finder.h
index 588b04c8..4e00c9a 100644
--- a/chrome/browser/safe_browsing/incident_reporting/last_download_finder.h
+++ b/chrome/browser/safe_browsing/incident_reporting/last_download_finder.h
@@ -34,9 +34,10 @@
 namespace safe_browsing {
 
 class ClientIncidentReport_DownloadDetails;
+class ClientIncidentReport_NonBinaryDownloadDetails;
 
-// Finds the most recent executable downloaded by any on-the-record profile with
-// history that participates in safe browsing.
+// Finds the most recent executable download and non-executable download by
+// any on-the-record profile with history that participates in safe browsing.
 class LastDownloadFinder : public content::NotificationObserver,
                            public history::HistoryServiceObserver {
  public:
@@ -45,15 +46,17 @@
       const DownloadMetadataManager::GetDownloadDetailsCallback&)>
       DownloadDetailsGetter;
 
-  // The type of a callback run by the finder upon completion. The argument is a
-  // protobuf containing details of the download that was found, or an empty
-  // pointer if none was found.
-  typedef base::Callback<void(scoped_ptr<ClientIncidentReport_DownloadDetails>)>
+  // The type of a callback run by the finder upon completion. Each argument is
+  // a protobuf containing details of the respective download that was found,
+  // or an empty pointer if none was found.
+  typedef base::Callback<void(
+      scoped_ptr<ClientIncidentReport_DownloadDetails>,
+      scoped_ptr<ClientIncidentReport_NonBinaryDownloadDetails>)>
       LastDownloadCallback;
 
   ~LastDownloadFinder() override;
 
-  // Initiates an asynchronous search for the most recent download. |callback|
+  // Initiates an asynchronous search for the most recent downloads. |callback|
   // will be run when the search is complete. The returned instance can be
   // deleted to terminate the search, in which case |callback| is not invoked.
   // Returns NULL without running |callback| if there are no eligible profiles
@@ -70,6 +73,7 @@
   enum ProfileWaitState {
     WAITING_FOR_METADATA,
     WAITING_FOR_HISTORY,
+    WAITING_FOR_NON_BINARY_HISTORY,
   };
 
   LastDownloadFinder(const DownloadDetailsGetter& download_details_getter,
@@ -137,7 +141,11 @@
   scoped_ptr<ClientIncidentReport_DownloadDetails> details_;
 
   // The most recent download, updated progressively as query results arrive.
-  history::DownloadRow most_recent_row_;
+  history::DownloadRow most_recent_binary_row_;
+
+  // The most recent non-binary download, updated progressively as query results
+  // arrive.
+  history::DownloadRow most_recent_non_binary_row_;
 
   // HistoryServiceObserver
   ScopedObserver<history::HistoryService, history::HistoryServiceObserver>
diff --git a/chrome/browser/safe_browsing/incident_reporting/last_download_finder_unittest.cc b/chrome/browser/safe_browsing/incident_reporting/last_download_finder_unittest.cc
index bd13d283..845a3d7 100644
--- a/chrome/browser/safe_browsing/incident_reporting/last_download_finder_unittest.cc
+++ b/chrome/browser/safe_browsing/incident_reporting/last_download_finder_unittest.cc
@@ -97,13 +97,18 @@
     FILE_PATH_LITERAL("spam.exe");
 #endif
 
+static const base::FilePath::CharType kPDFFileName[] =
+    FILE_PATH_LITERAL("download.pdf");
+
 }  // namespace
 
 namespace safe_browsing {
 
 class LastDownloadFinderTest : public testing::Test {
  public:
-  void NeverCalled(scoped_ptr<ClientIncidentReport_DownloadDetails> download) {
+  void NeverCalled(scoped_ptr<ClientIncidentReport_DownloadDetails> download,
+                   scoped_ptr<ClientIncidentReport_NonBinaryDownloadDetails>
+                       non_binary_download) {
     FAIL();
   }
 
@@ -122,11 +127,15 @@
 
   // LastDownloadFinder::LastDownloadCallback implementation that
   // passes the found download to |result| and then runs a closure.
-  void OnLastDownload(
-      scoped_ptr<ClientIncidentReport_DownloadDetails>* result,
-      const base::Closure& quit_closure,
-      scoped_ptr<ClientIncidentReport_DownloadDetails> download) {
+  void OnLastDownload(scoped_ptr<ClientIncidentReport_DownloadDetails>* result,
+                      scoped_ptr<ClientIncidentReport_NonBinaryDownloadDetails>*
+                          non_binary_result,
+                      const base::Closure& quit_closure,
+                      scoped_ptr<ClientIncidentReport_DownloadDetails> download,
+                      scoped_ptr<ClientIncidentReport_NonBinaryDownloadDetails>
+                          non_binary_download) {
     *result = download.Pass();
+    *non_binary_result = non_binary_download.Pass();
     quit_closure.Run();
   }
 
@@ -139,7 +148,7 @@
     EXTENDED_REPORTING_OPT_IN,
   };
 
-  LastDownloadFinderTest() : profile_number_() {}
+  LastDownloadFinderTest() : profile_number_(), download_id_(1) {}
 
   void SetUp() override {
     testing::Test::SetUp();
@@ -233,24 +242,21 @@
     base::RunLoop().RunUntilIdle();
   }
 
-  // Runs the last download finder on all loaded profiles, returning the found
-  // download or an empty pointer if none was found.
-  scoped_ptr<ClientIncidentReport_DownloadDetails> RunLastDownloadFinder() {
+  // Runs the last download finder on all loaded profiles.
+  void RunLastDownloadFinder(
+      scoped_ptr<ClientIncidentReport_DownloadDetails>* last_binary_download,
+      scoped_ptr<ClientIncidentReport_NonBinaryDownloadDetails>*
+          last_non_binary_download) {
     base::RunLoop run_loop;
 
-    scoped_ptr<ClientIncidentReport_DownloadDetails> last_download;
-
     scoped_ptr<LastDownloadFinder> finder(LastDownloadFinder::Create(
         GetDownloadDetailsGetter(),
         base::Bind(&LastDownloadFinderTest::OnLastDownload,
-                   base::Unretained(this),
-                   &last_download,
-                   run_loop.QuitClosure())));
+                   base::Unretained(this), last_binary_download,
+                   last_non_binary_download, run_loop.QuitClosure())));
 
     if (finder)
       run_loop.Run();
-
-    return last_download.Pass();
   }
 
   history::DownloadRow CreateTestDownloadRow(
@@ -272,22 +278,12 @@
         history::DownloadDangerType::NOT_DANGEROUS,  // danger_type
         history::ToHistoryDownloadInterruptReason(
             content::DOWNLOAD_INTERRUPT_REASON_NONE),  // interrupt_reason,
-        1,                                             // id
+        download_id_++,                                // id
         false,                                         // download_opened
         std::string(),                                 // ext_id
         std::string());                                // ext_name
   }
 
-  void ExpectNoDownloadFound(
-      scoped_ptr<ClientIncidentReport_DownloadDetails> download) {
-    EXPECT_FALSE(download);
-  }
-
-  void ExpectFoundTestDownload(
-      scoped_ptr<ClientIncidentReport_DownloadDetails> download) {
-    ASSERT_TRUE(download);
-  }
-
   content::TestBrowserThreadBundle browser_thread_bundle_;
   scoped_ptr<TestingProfileManager> profile_manager_;
 
@@ -310,11 +306,19 @@
   }
 
   int profile_number_;
+
+  // Incremented on every download addition to avoid downloads with the same id.
+  int download_id_;
 };
 
 // Tests that nothing happens if there are no profiles at all.
 TEST_F(LastDownloadFinderTest, NoProfiles) {
-  ExpectNoDownloadFound(RunLastDownloadFinder());
+  scoped_ptr<ClientIncidentReport_DownloadDetails> last_binary_download;
+  scoped_ptr<ClientIncidentReport_NonBinaryDownloadDetails>
+      last_non_binary_download;
+  RunLastDownloadFinder(&last_binary_download, &last_non_binary_download);
+  EXPECT_FALSE(last_binary_download);
+  EXPECT_FALSE(last_non_binary_download);
 }
 
 // Tests that nothing happens other than the callback being invoked if there are
@@ -326,7 +330,12 @@
   // Add a download.
   AddDownload(profile, CreateTestDownloadRow(kBinaryFileName));
 
-  ExpectNoDownloadFound(RunLastDownloadFinder());
+  scoped_ptr<ClientIncidentReport_DownloadDetails> last_binary_download;
+  scoped_ptr<ClientIncidentReport_NonBinaryDownloadDetails>
+      last_non_binary_download;
+  RunLastDownloadFinder(&last_binary_download, &last_non_binary_download);
+  EXPECT_FALSE(last_binary_download);
+  EXPECT_FALSE(last_non_binary_download);
 }
 
 // Tests that a download is found from a single profile.
@@ -334,10 +343,32 @@
   // Create a profile with a history service that is opted-in.
   TestingProfile* profile = CreateProfile(EXTENDED_REPORTING_OPT_IN);
 
-  // Add a download.
+  // Add a binary and non-binary download.
   AddDownload(profile, CreateTestDownloadRow(kBinaryFileName));
+  AddDownload(profile, CreateTestDownloadRow(kPDFFileName));
 
-  ExpectFoundTestDownload(RunLastDownloadFinder());
+  scoped_ptr<ClientIncidentReport_DownloadDetails> last_binary_download;
+  scoped_ptr<ClientIncidentReport_NonBinaryDownloadDetails>
+      last_non_binary_download;
+  RunLastDownloadFinder(&last_binary_download, &last_non_binary_download);
+  EXPECT_TRUE(last_binary_download);
+  EXPECT_TRUE(last_non_binary_download);
+}
+
+// Tests that a non-binary download is found
+TEST_F(LastDownloadFinderTest, NonBinaryOnly) {
+  // Create a profile with a history service that is opted-in.
+  TestingProfile* profile = CreateProfile(EXTENDED_REPORTING_OPT_IN);
+
+  // Add a non-binary download.
+  AddDownload(profile, CreateTestDownloadRow(kPDFFileName));
+
+  scoped_ptr<ClientIncidentReport_DownloadDetails> last_binary_download;
+  scoped_ptr<ClientIncidentReport_NonBinaryDownloadDetails>
+      last_non_binary_download;
+  RunLastDownloadFinder(&last_binary_download, &last_non_binary_download);
+  EXPECT_FALSE(last_binary_download);
+  EXPECT_TRUE(last_non_binary_download);
 }
 
 // Tests that a download is found from a single profile when the field trial is
@@ -354,7 +385,12 @@
   // Add a download.
   AddDownload(profile, CreateTestDownloadRow(kBinaryFileName));
 
-  ExpectFoundTestDownload(RunLastDownloadFinder());
+  scoped_ptr<ClientIncidentReport_DownloadDetails> last_binary_download;
+  scoped_ptr<ClientIncidentReport_NonBinaryDownloadDetails>
+      last_non_binary_download;
+  RunLastDownloadFinder(&last_binary_download, &last_non_binary_download);
+  EXPECT_FALSE(last_non_binary_download);
+  EXPECT_TRUE(last_binary_download);
 }
 
 #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_ANDROID)
@@ -366,7 +402,12 @@
   // Add a download.
   AddDownload(profile, CreateTestDownloadRow(kBinaryFileNameForOtherOS));
 
-  ExpectNoDownloadFound(RunLastDownloadFinder());
+  scoped_ptr<ClientIncidentReport_DownloadDetails> last_binary_download;
+  scoped_ptr<ClientIncidentReport_NonBinaryDownloadDetails>
+      last_non_binary_download;
+  RunLastDownloadFinder(&last_binary_download, &last_non_binary_download);
+  EXPECT_FALSE(last_binary_download);
+  EXPECT_FALSE(last_non_binary_download);
 }
 #endif
 
@@ -392,7 +433,9 @@
   // Create a profile with a history service that is opted-in.
   CreateProfile(EXTENDED_REPORTING_OPT_IN);
 
-  scoped_ptr<ClientIncidentReport_DownloadDetails> last_download;
+  scoped_ptr<ClientIncidentReport_DownloadDetails> last_binary_download;
+  scoped_ptr<ClientIncidentReport_NonBinaryDownloadDetails>
+      last_non_binary_download;
   base::RunLoop run_loop;
 
   // Post a task that will create a second profile once the main loop is run.
@@ -404,13 +447,12 @@
   scoped_ptr<LastDownloadFinder> finder(LastDownloadFinder::Create(
       GetDownloadDetailsGetter(),
       base::Bind(&LastDownloadFinderTest::OnLastDownload,
-                 base::Unretained(this),
-                 &last_download,
-                 run_loop.QuitClosure())));
+                 base::Unretained(this), &last_binary_download,
+                 &last_non_binary_download, run_loop.QuitClosure())));
 
   run_loop.Run();
 
-  ExpectFoundTestDownload(last_download.Pass());
+  ASSERT_TRUE(last_binary_download);
 }
 
 }  // namespace safe_browsing
diff --git a/chrome/browser/stack_sampling_configuration.cc b/chrome/browser/stack_sampling_configuration.cc
index 51d6280..c5fc88b6 100644
--- a/chrome/browser/stack_sampling_configuration.cc
+++ b/chrome/browser/stack_sampling_configuration.cc
@@ -11,11 +11,17 @@
 
 namespace {
 
-bool IsProfilerEnabledForCurrentChannel() {
+// The profiler is currently only implemented for Windows x64, and only runs on
+// trunk, canary, and dev.
+bool IsProfilerSupported() {
+#if !defined(_WIN64)
+  return false;
+#else
   const version_info::Channel channel = chrome::GetChannel();
   return (channel == version_info::Channel::UNKNOWN ||
           channel == version_info::Channel::CANARY ||
           channel == version_info::Channel::DEV);
+#endif
 }
 
 }  // namespace
@@ -66,12 +72,12 @@
 }
 
 bool StackSamplingConfiguration::IsProfilerEnabled() const {
-  return IsProfilerEnabledForCurrentChannel() &&
-      configuration_ != PROFILE_DISABLED;
+  return (configuration_ != PROFILE_DISABLED &&
+          configuration_ != PROFILE_CONTROL);
 }
 
 void StackSamplingConfiguration::RegisterSyntheticFieldTrial() const {
-  if (!IsProfilerEnabledForCurrentChannel())
+  if (!IsProfilerSupported())
     return;
 
   std::string group;
@@ -109,37 +115,45 @@
 // static
 StackSamplingConfiguration::ProfileConfiguration
 StackSamplingConfiguration::GenerateConfiguration() {
+  if (!IsProfilerSupported())
+    return PROFILE_DISABLED;
+
   // Enable the profiler in the intended ultimate production configuration for
   // development/waterfall builds.
   if (chrome::GetChannel() == version_info::Channel::UNKNOWN)
     return PROFILE_10HZ;
 
-  struct Variation {
-    ProfileConfiguration config;
-    int weight;
-  };
+  // Enable according to the variations below in canary and dev.
+  if (chrome::GetChannel() == version_info::Channel::CANARY ||
+      chrome::GetChannel() == version_info::Channel::DEV) {
+    struct Variation {
+      ProfileConfiguration config;
+      int weight;
+    };
 
-  // Generate a configuration according to the associated weights.
-  const Variation variations[] = {
-    { PROFILE_10HZ, 15},
-    { PROFILE_CONTROL, 15},
-    { PROFILE_DISABLED, 70}
-  };
+    // Generate a configuration according to the associated weights.
+    const Variation variations[] = {
+      { PROFILE_10HZ, 50},
+      { PROFILE_CONTROL, 50},
+      { PROFILE_DISABLED, 0}
+    };
 
-  int total_weight = 0;
-  for (const Variation& variation : variations)
-    total_weight += variation.weight;
-  DCHECK_EQ(100, total_weight);
+    int total_weight = 0;
+    for (const Variation& variation : variations)
+      total_weight += variation.weight;
+    DCHECK_EQ(100, total_weight);
 
-  int chosen = base::RandInt(0, total_weight - 1);  // Max is inclusive.
-  int cumulative_weight = 0;
-  for (const Variation& variation : variations) {
-    if (chosen >= cumulative_weight &&
-        chosen < cumulative_weight + variation.weight) {
-      return variation.config;
+    int chosen = base::RandInt(0, total_weight - 1);  // Max is inclusive.
+    int cumulative_weight = 0;
+    for (const Variation& variation : variations) {
+      if (chosen >= cumulative_weight &&
+          chosen < cumulative_weight + variation.weight) {
+        return variation.config;
+      }
+      cumulative_weight += variation.weight;
     }
-    cumulative_weight += variation.weight;
+    NOTREACHED();
   }
-  NOTREACHED();
+
   return PROFILE_DISABLED;
 }
diff --git a/chrome/browser/ui/passwords/manage_passwords_state.h b/chrome/browser/ui/passwords/manage_passwords_state.h
index c1275bf..eed55be 100644
--- a/chrome/browser/ui/passwords/manage_passwords_state.h
+++ b/chrome/browser/ui/passwords/manage_passwords_state.h
@@ -5,6 +5,8 @@
 #ifndef CHROME_BROWSER_UI_PASSWORDS_MANAGE_PASSWORDS_STATE_H_
 #define CHROME_BROWSER_UI_PASSWORDS_MANAGE_PASSWORDS_STATE_H_
 
+#include <vector>
+
 #include "base/callback.h"
 #include "base/macros.h"
 #include "base/memory/scoped_ptr.h"
diff --git a/chrome/browser/ui/tab_helpers.cc b/chrome/browser/ui/tab_helpers.cc
index f61cc10..8ebb1e9 100644
--- a/chrome/browser/ui/tab_helpers.cc
+++ b/chrome/browser/ui/tab_helpers.cc
@@ -93,6 +93,7 @@
 #if defined(ENABLE_PRINT_PREVIEW)
 #include "chrome/browser/printing/print_preview_message_handler.h"
 #include "chrome/browser/printing/print_view_manager.h"
+#include "chrome/browser/ui/webui/print_preview/print_preview_distiller.h"
 #else
 #include "chrome/browser/printing/print_view_manager_basic.h"
 #endif  // defined(ENABLE_PRINT_PREVIEW)
@@ -238,10 +239,14 @@
 #endif  // defined(ENABLE_PRINT_PREVIEW)
 #endif  // defined(ENABLE_PRINTING) && !defined(OS_ANDROID)
 
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kEnableDomDistiller) ||
-      !base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kDisablePrintPreviewSimplify)) {
+  bool enabled_distiller = base::CommandLine::ForCurrentProcess()->HasSwitch(
+      switches::kEnableDomDistiller);
+#if defined(ENABLE_PRINT_PREVIEW)
+  if (PrintPreviewDistiller::IsEnabled())
+    enabled_distiller = true;
+#endif  // defined(ENABLE_PRINT_PREVIEW)
+
+  if (enabled_distiller) {
     dom_distiller::WebContentsMainFrameObserver::CreateForWebContents(
         web_contents);
   }
diff --git a/chrome/browser/ui/webui/OWNERS b/chrome/browser/ui/webui/OWNERS
index a8e8d6c..f908032 100644
--- a/chrome/browser/ui/webui/OWNERS
+++ b/chrome/browser/ui/webui/OWNERS
@@ -1,7 +1,6 @@
 bauerb@chromium.org
 dbeam@chromium.org
 estade@chromium.org
-jhawkins@chromium.org
 nkostylev@chromium.org
 pam@chromium.org
 xiyuan@chromium.org
diff --git a/chrome/browser/ui/webui/media_router/media_router_dialog_controller_impl.cc b/chrome/browser/ui/webui/media_router/media_router_dialog_controller_impl.cc
index ffcecc2..d81c695 100644
--- a/chrome/browser/ui/webui/media_router/media_router_dialog_controller_impl.cc
+++ b/chrome/browser/ui/webui/media_router/media_router_dialog_controller_impl.cc
@@ -274,18 +274,18 @@
     return;
   }
 
-  scoped_ptr<CreatePresentationSessionRequest> presentation_request(
-      TakePresentationRequest());
+  scoped_ptr<CreatePresentationConnectionRequest> create_connection_request(
+      TakeCreateConnectionRequest());
   // TODO(imcheng): Don't create PresentationServiceDelegateImpl if it doesn't
   // exist (crbug.com/508695).
   base::WeakPtr<PresentationServiceDelegateImpl> delegate =
       PresentationServiceDelegateImpl::GetOrCreateForWebContents(initiator())
           ->GetWeakPtr();
-  if (!presentation_request.get()) {
+  if (!create_connection_request.get()) {
     media_router_ui->InitWithDefaultMediaSource(delegate);
   } else {
     media_router_ui->InitWithPresentationSessionRequest(
-        initiator(), delegate, presentation_request.Pass());
+        initiator(), delegate, create_connection_request.Pass());
   }
 }
 
diff --git a/chrome/browser/ui/webui/media_router/media_router_ui.cc b/chrome/browser/ui/webui/media_router/media_router_ui.cc
index 4d05a51..afb9c42 100644
--- a/chrome/browser/ui/webui/media_router/media_router_ui.cc
+++ b/chrome/browser/ui/webui/media_router/media_router_ui.cc
@@ -9,7 +9,7 @@
 #include "base/guid.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/media/router/create_presentation_session_request.h"
+#include "chrome/browser/media/router/create_presentation_connection_request.h"
 #include "chrome/browser/media/router/issue.h"
 #include "chrome/browser/media/router/issues_observer.h"
 #include "chrome/browser/media/router/media_route.h"
@@ -163,11 +163,12 @@
   if (query_result_manager_.get())
     query_result_manager_->RemoveObserver(this);
   if (presentation_service_delegate_.get())
-    presentation_service_delegate_->RemoveDefaultMediaSourceObserver(this);
-  // If |presentation_request_| still exists, then it means presentation route
+    presentation_service_delegate_->RemoveDefaultPresentationRequestObserver(
+        this);
+  // If |create_session_request_| still exists, then it means presentation route
   // request was never attempted.
-  if (presentation_request_) {
-    presentation_request_->InvokeErrorCallback(content::PresentationError(
+  if (create_session_request_) {
+    create_session_request_->InvokeErrorCallback(content::PresentationError(
         content::PRESENTATION_ERROR_SESSION_REQUEST_CANCELLED,
         "Dialog closed."));
   }
@@ -180,30 +181,30 @@
   DCHECK(!query_result_manager_.get());
 
   presentation_service_delegate_ = delegate;
-  presentation_service_delegate_->AddDefaultMediaSourceObserver(this);
-  InitCommon(presentation_service_delegate_->web_contents(),
-             presentation_service_delegate_->default_source(),
-             presentation_service_delegate_->default_frame_url());
+  presentation_service_delegate_->AddDefaultPresentationRequestObserver(this);
+  InitCommon(presentation_service_delegate_->web_contents());
+  if (presentation_service_delegate_->HasDefaultPresentationRequest()) {
+    OnDefaultPresentationChanged(
+        presentation_service_delegate_->GetDefaultPresentationRequest());
+  }
 }
 
 void MediaRouterUI::InitWithPresentationSessionRequest(
     content::WebContents* initiator,
     const base::WeakPtr<PresentationServiceDelegateImpl>& delegate,
-    scoped_ptr<CreatePresentationSessionRequest> presentation_request) {
+    scoped_ptr<CreatePresentationConnectionRequest> create_session_request) {
   DCHECK(initiator);
-  DCHECK(presentation_request);
-  DCHECK(!presentation_request_);
+  DCHECK(create_session_request);
+  DCHECK(!create_session_request_);
   DCHECK(!query_result_manager_);
 
-  presentation_request_ = presentation_request.Pass();
+  create_session_request_ = create_session_request.Pass();
   presentation_service_delegate_ = delegate;
-  InitCommon(initiator, presentation_request_->media_source(),
-             presentation_request_->frame_url());
+  InitCommon(initiator);
+  OnDefaultPresentationChanged(create_session_request_->presentation_request());
 }
 
-void MediaRouterUI::InitCommon(content::WebContents* initiator,
-                               const MediaSource& default_source,
-                               const GURL& default_frame_url) {
+void MediaRouterUI::InitCommon(content::WebContents* initiator) {
   DCHECK(initiator);
   DCHECK(router_);
 
@@ -223,26 +224,31 @@
       MediaSourceForTab(SessionTabHelper::IdForTab(initiator)));
   query_result_manager_->StartSinksQuery(
       MediaCastMode::TAB_MIRROR, mirroring_source);
-
-  OnDefaultMediaSourceChanged(default_source, default_frame_url);
 }
 
-void MediaRouterUI::OnDefaultMediaSourceChanged(const MediaSource& source,
-                                                const GURL& frame_url) {
-  if (source.Empty()) {
-    query_result_manager_->StopSinksQuery(MediaCastMode::DEFAULT);
-  } else {
-    query_result_manager_->StartSinksQuery(MediaCastMode::DEFAULT, source);
-  }
-  UpdateSourceHostAndCastModes(frame_url);
+void MediaRouterUI::OnDefaultPresentationChanged(
+    const PresentationRequest& presentation_request) {
+  presentation_request_.reset(new PresentationRequest(presentation_request));
+  query_result_manager_->StartSinksQuery(
+      MediaCastMode::DEFAULT, presentation_request_->GetMediaSource());
+  UpdateCastModes();
 }
 
-void MediaRouterUI::UpdateSourceHostAndCastModes(const GURL& frame_url) {
-  DCHECK(query_result_manager_);
-  frame_url_ = frame_url;
+void MediaRouterUI::OnDefaultPresentationRemoved() {
+  presentation_request_.reset();
+  query_result_manager_->StopSinksQuery(MediaCastMode::DEFAULT);
+  UpdateCastModes();
+}
+
+void MediaRouterUI::UpdateCastModes() {
+  // Gets updated cast modes from |query_result_manager_| and forwards it to UI.
   query_result_manager_->GetSupportedCastModes(&cast_modes_);
-  if (ui_initialized_)
-    handler_->UpdateCastModes(cast_modes_, GetHostFromURL(frame_url_));
+  if (ui_initialized_) {
+    handler_->UpdateCastModes(
+        cast_modes_, presentation_request_
+                         ? GetHostFromURL(presentation_request_->frame_url())
+                         : std::string());
+  }
 }
 
 void MediaRouterUI::Close() {
@@ -268,11 +274,11 @@
   DCHECK(initiator_);
 
   // Note that there is a rarely-encountered bug, where the MediaCastMode to
-  // MediaSource mapping could have been updated, between when the user
-  // clicked on the UI to start a create route request,
-  // and when this function is called.
-  // However, since the user does not have visibility into the MediaSource, and
-  // that it occurs very rarely in practice, we leave it as-is for now.
+  // MediaSource mapping could have been updated, between when the user clicked
+  // on the UI to start a create route request, and when this function is
+  // called. However, since the user does not have visibility into the
+  // MediaSource, and that it occurs very rarely in practice, we leave it as-is
+  // for now.
   MediaSource source = query_result_manager_->GetSourceForCastMode(cast_mode);
   if (source.Empty()) {
     LOG(ERROR) << "No corresponding MediaSource for cast mode " << cast_mode;
@@ -280,11 +286,16 @@
   }
 
   requesting_route_for_default_source_ = cast_mode == MediaCastMode::DEFAULT;
+  if (requesting_route_for_default_source_ && !presentation_request_) {
+    DLOG(ERROR) << "Requested to create a route for presentation, but "
+                << "presentation request is missing.";
+    return false;
+  }
+
   current_route_request_id_ = ++route_request_counter_;
   GURL origin;
-  // TODO(imcheng): What is the origin if not creating route in DEFAULT mode?
   if (requesting_route_for_default_source_) {
-    origin = frame_url_.GetOrigin();
+    origin = presentation_request_->frame_url().GetOrigin();
   } else {
     // Requesting route for mirroring. Use a placeholder URL as origin.
     origin = GURL(chrome::kChromeUIMediaRouterURL);
@@ -297,7 +308,7 @@
   // (1) Non-presentation route request (e.g., mirroring). No additional
   // notification necessary.
   // (2) Presentation route request for a Presentation API startSession call.
-  // The startSession (CreatePresentationSessionRequest) will need to be
+  // The startSession (CreatePresentationConnectionRequest) will need to be
   // answered with the
   // route response.
   // (3) Browser-initiated presentation route request. If successful,
@@ -310,16 +321,16 @@
                  weak_factory_.GetWeakPtr(), current_route_request_id_,
                  sink_id));
   if (requesting_route_for_default_source_) {
-    if (presentation_request_) {
-      // |presentation_request_| will be nullptr after this call, as the
+    if (create_session_request_) {
+      // |create_session_request_| will be nullptr after this call, as the
       // object will be transferred to the callback.
       route_response_callbacks.push_back(
-          base::Bind(&CreatePresentationSessionRequest::HandleRouteResponse,
-                     base::Passed(&presentation_request_)));
+          base::Bind(&CreatePresentationConnectionRequest::HandleRouteResponse,
+                     base::Passed(&create_session_request_)));
     } else if (presentation_service_delegate_) {
       route_response_callbacks.push_back(
           base::Bind(&PresentationServiceDelegateImpl::OnRouteResponse,
-                     presentation_service_delegate_));
+                     presentation_service_delegate_, *presentation_request_));
     }
   }
 
diff --git a/chrome/browser/ui/webui/media_router/media_router_ui.h b/chrome/browser/ui/webui/media_router/media_router_ui.h
index 3d7859f4..4c8ef33 100644
--- a/chrome/browser/ui/webui/media_router/media_router_ui.h
+++ b/chrome/browser/ui/webui/media_router/media_router_ui.h
@@ -38,13 +38,13 @@
 class MediaRoutesObserver;
 class MediaSink;
 class MediaSinksObserver;
-class CreatePresentationSessionRequest;
+class CreatePresentationConnectionRequest;
 
 // Implements the chrome://media-router user interface.
-class MediaRouterUI
-    : public ConstrainedWebDialogUI,
-      public QueryResultManager::Observer,
-      public PresentationServiceDelegateImpl::DefaultMediaSourceObserver {
+class MediaRouterUI : public ConstrainedWebDialogUI,
+                      public QueryResultManager::Observer,
+                      public PresentationServiceDelegateImpl::
+                          DefaultPresentationRequestObserver {
  public:
   // |web_ui| owns this object and is used to initialize the base class.
   explicit MediaRouterUI(content::WebUI* web_ui);
@@ -79,7 +79,7 @@
   void InitWithPresentationSessionRequest(
       content::WebContents* initiator,
       const base::WeakPtr<PresentationServiceDelegateImpl>& delegate,
-      scoped_ptr<CreatePresentationSessionRequest> presentation_request);
+      scoped_ptr<CreatePresentationConnectionRequest> presentation_request);
 
   // Closes the media router UI.
   void Close();
@@ -163,20 +163,17 @@
   // Creates and sends an issue if route creation times out.
   void RouteCreationTimeout();
 
-  // Sets the source host name to be displayed in the UI.
-  // Gets cast modes from |query_result_manager_| and forwards it to UI.
-  // One of the Init* functions must have been called before.
-  void UpdateSourceHostAndCastModes(const GURL& frame_url);
+  // Initializes the dialog with mirroring sources derived from |initiator|.
+  void InitCommon(content::WebContents* initiator);
 
-  // Initializes the dialog with mirroring sources derived from |initiator|,
-  // and optional |default_source| and |default_frame_url| if any.
-  void InitCommon(content::WebContents* initiator,
-                  const MediaSource& default_source,
-                  const GURL& default_frame_url);
+  // PresentationServiceDelegateImpl::DefaultPresentationObserver
+  void OnDefaultPresentationChanged(
+      const PresentationRequest& presentation_request) override;
+  void OnDefaultPresentationRemoved() override;
 
-  // PresentationServiceDelegateImpl::DefaultMediaSourceObserver
-  void OnDefaultMediaSourceChanged(const MediaSource& source,
-                                   const GURL& frame_url) override;
+  // Updates the set of supported cast modes and sends the updated set to
+  // |handler_|.
+  void UpdateCastModes();
 
   // Owned by the |web_ui| passed in the ctor, and guaranteed to be deleted
   // only after it has deleted |this|.
@@ -208,7 +205,11 @@
 
   // If set, then the result of the next presentation route request will
   // be handled by this object.
-  scoped_ptr<CreatePresentationSessionRequest> presentation_request_;
+  scoped_ptr<CreatePresentationConnectionRequest> create_session_request_;
+
+  // Set to the presentation request corresponding to the presentation cast
+  // mode, if supported. Otherwise set to nullptr.
+  scoped_ptr<PresentationRequest> presentation_request_;
 
   // It's possible for PresentationServiceDelegateImpl to be destroyed before
   // this class.
diff --git a/chrome/browser/ui/webui/options/OWNERS b/chrome/browser/ui/webui/options/OWNERS
index ea9615d5..e126253 100644
--- a/chrome/browser/ui/webui/options/OWNERS
+++ b/chrome/browser/ui/webui/options/OWNERS
@@ -1,6 +1,5 @@
 dbeam@chromium.org
 estade@chromium.org
-jhawkins@chromium.org
 stevenjb@chromium.org
 
 per-file sync_setup_handler*=atwilson@chromium.org
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_distiller.cc b/chrome/browser/ui/webui/print_preview/print_preview_distiller.cc
index 159ed82..8bc95a9 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_distiller.cc
+++ b/chrome/browser/ui/webui/print_preview/print_preview_distiller.cc
@@ -6,6 +6,8 @@
 
 #include <string>
 
+#include "base/command_line.h"
+#include "base/feature_list.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/dom_distiller/tab_utils.h"
@@ -13,6 +15,7 @@
 #include "chrome/browser/printing/print_preview_message_handler.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/web_contents_sizer.h"
+#include "chrome/common/chrome_switches.h"
 #include "chrome/common/prerender_messages.h"
 #include "components/dom_distiller/content/browser/distiller_javascript_utils.h"
 #include "components/printing/common/print_messages.h"
@@ -204,6 +207,14 @@
   base::Closure on_failed_callback_;
 };
 
+const base::Feature PrintPreviewDistiller::kFeature = {
+    "PrintPreviewDistiller", base::FEATURE_ENABLED_BY_DEFAULT,
+};
+
+bool PrintPreviewDistiller::IsEnabled() {
+  return base::FeatureList::IsEnabled(kFeature);
+}
+
 PrintPreviewDistiller::PrintPreviewDistiller(
     WebContents* source_web_contents,
     const base::Closure on_failed_callback,
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_distiller.h b/chrome/browser/ui/webui/print_preview/print_preview_distiller.h
index d9ef5db..ed2a7cc 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_distiller.h
+++ b/chrome/browser/ui/webui/print_preview/print_preview_distiller.h
@@ -6,6 +6,7 @@
 #define CHROME_BROWSER_UI_WEBUI_PRINT_PREVIEW_PRINT_PREVIEW_DISTILLER_H_
 
 #include "base/callback.h"
+#include "base/feature_list.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/values.h"
@@ -19,6 +20,10 @@
 // generated by a source web contents
 class PrintPreviewDistiller {
  public:
+  static const base::Feature kFeature;
+
+  static bool IsEnabled();
+
   PrintPreviewDistiller(content::WebContents* source_web_contents,
                         base::Closure on_failed_callback,
                         scoped_ptr<base::DictionaryValue> settings);
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_handler.cc b/chrome/browser/ui/webui/print_preview/print_preview_handler.cc
index 58e43745..6cfd861 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_handler.cc
+++ b/chrome/browser/ui/webui/print_preview/print_preview_handler.cc
@@ -1298,13 +1298,11 @@
     GetNumberFormatAndMeasurementSystem(&initial_settings);
   web_ui()->CallJavascriptFunction("setInitialSettings", initial_settings);
 
-  if (cmdline->HasSwitch(switches::kDisablePrintPreviewSimplify))
-    return;
-
-  WebContents* initiator = GetInitiator();
-  if (initiator && dom_distiller::url_utils::IsUrlDistillable(
-                       initiator->GetLastCommittedURL())) {
-    web_ui()->CallJavascriptFunction("allowDistillPage");
+  if (PrintPreviewDistiller::IsEnabled()) {
+    using dom_distiller::url_utils::IsUrlDistillable;
+    WebContents* initiator = GetInitiator();
+    if (initiator && IsUrlDistillable(initiator->GetLastCommittedURL()))
+      web_ui()->CallJavascriptFunction("allowDistillPage");
   }
 }
 
diff --git a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
index 4c7281f..c2587e6e 100644
--- a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
@@ -121,6 +121,15 @@
       "chooseFromWebStore", IDS_SETTINGS_WEB_STORE);
 }
 
+#if defined(OS_CHROMEOS)
+void AddBluetoothStrings(content::WebUIDataSource* html_source) {
+  html_source->AddLocalizedString(
+      "bluetoothPageTitle", IDS_SETTINGS_BLUETOOTH);
+  html_source->AddLocalizedString(
+      "enableBluetooth", IDS_SETTINGS_BLUETOOTH_ENABLE);
+}
+#endif
+
 void AddCertificateManagerStrings(content::WebUIDataSource* html_source) {
   html_source->AddLocalizedString("certificateManagerPageTitle",
                                   IDS_SETTINGS_CERTIFICATE_MANAGER);
@@ -541,6 +550,14 @@
                                   IDS_SETTINGS_SITE_SETTINGS_BLOCK_MENU);
   html_source->AddLocalizedString("siteSettingsActionReset",
                                   IDS_SETTINGS_SITE_SETTINGS_RESET_MENU);
+  html_source->AddLocalizedString("siteSettingsUsage",
+                                  IDS_SETTINGS_SITE_SETTINGS_USAGE);
+  html_source->AddLocalizedString("siteSettingsPermissions",
+                                  IDS_SETTINGS_SITE_SETTINGS_PERMISSIONS);
+  html_source->AddLocalizedString("siteSettingsClearAndReset",
+                                  IDS_SETTINGS_SITE_SETTINGS_CLEAR_BUTTON);
+  html_source->AddLocalizedString("siteSettingsDelete",
+                                  IDS_SETTINGS_SITE_SETTINGS_DELETE);
 }
 
 void AddSyncStrings(content::WebUIDataSource* html_source) {
@@ -688,6 +705,9 @@
   AddAccountUITweaksStrings(html_source, profile);
 #endif
   AddAppearanceStrings(html_source);
+#if defined(OS_CHROMEOS)
+  AddBluetoothStrings(html_source);
+#endif
   AddCertificateManagerStrings(html_source);
   AddClearBrowsingDataStrings(html_source);
 #if !defined(OS_CHROMEOS)
diff --git a/chrome/browser/ui/webui/sync_internals_message_handler.cc b/chrome/browser/ui/webui/sync_internals_message_handler.cc
index 9adbcc22..54196ce28 100644
--- a/chrome/browser/ui/webui/sync_internals_message_handler.cc
+++ b/chrome/browser/ui/webui/sync_internals_message_handler.cc
@@ -11,7 +11,7 @@
 #include "chrome/browser/sync/profile_sync_service_factory.h"
 #include "chrome/common/channel_info.h"
 #include "components/browser_sync/browser/profile_sync_service.h"
-#include "components/sync_driver/about_sync_util.h"
+#include "components/signin/core/browser/signin_manager_base.h"
 #include "components/sync_driver/about_sync_util.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/web_ui.h"
@@ -215,9 +215,10 @@
 
 void SyncInternalsMessageHandler::SendAboutInfo() {
   ProfileSyncService* sync_service = GetProfileSyncService();
+  SigninManagerBase* signin = sync_service ? sync_service->signin() : nullptr;
   scoped_ptr<base::DictionaryValue> value =
       sync_driver::sync_ui_util::ConstructAboutInformation(
-          sync_service, sync_service->signin(), chrome::GetChannel());
+          sync_service, signin, chrome::GetChannel());
   web_ui()->CallJavascriptFunction(
       sync_driver::sync_ui_util::kDispatchEvent,
       base::StringValue(sync_driver::sync_ui_util::kOnAboutInfoUpdated),
diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi
index 7f0dbf56..649fa12 100644
--- a/chrome/chrome_tests_unit.gypi
+++ b/chrome/chrome_tests_unit.gypi
@@ -1432,7 +1432,7 @@
       'browser/supervised_user/legacy/supervised_user_sync_service_unittest.cc',
     ],
     'chrome_unit_tests_media_router_sources': [
-      'browser/media/router/create_presentation_session_request_unittest.cc',
+      'browser/media/router/create_presentation_connection_request_unittest.cc',
       'browser/media/router/issue_manager_unittest.cc',
       'browser/media/router/issue_unittest.cc',
       'browser/media/router/media_route_unittest.cc',
@@ -1440,6 +1440,7 @@
       'browser/media/router/media_source_helper_unittest.cc',
       'browser/media/router/media_source_unittest.cc',
       'browser/media/router/presentation_media_sinks_observer_unittest.cc',
+      'browser/media/router/presentation_request_unittest.cc',
       'browser/media/router/presentation_service_delegate_impl_unittest.cc',
       'browser/media/router/presentation_session_state_observer_unittest.cc',
     ],
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index 3619c4cd..1fdfe380 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -315,9 +315,6 @@
 // Disables print preview (For testing, and for users who don't like us. :[ )
 const char kDisablePrintPreview[]           = "disable-print-preview";
 
-// Switch to disable simplify page on the print preview dialog.
-const char kDisablePrintPreviewSimplify[] = "disable-print-preview-simplify";
-
 // Normally when the user attempts to navigate to a page that was the result of
 // a post we prompt to make sure they want to. This switch may be used to
 // disable that check. This switch is used during automated testing.
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index 0c5be3c..461eb33 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -92,7 +92,6 @@
 extern const char kDisablePopupBlocking[];
 extern const char kDisablePreconnect[];
 extern const char kDisablePrintPreview[];
-extern const char kDisablePrintPreviewSimplify[];
 extern const char kDisablePromptOnRepost[];
 extern const char kDisablePushApiBackgroundMode[];
 extern const char kDisableQuic[];
diff --git a/chrome/common/safe_browsing/csd.proto b/chrome/common/safe_browsing/csd.proto
index fcce36b..9c9f8de 100644
--- a/chrome/common/safe_browsing/csd.proto
+++ b/chrome/common/safe_browsing/csd.proto
@@ -628,6 +628,15 @@
   optional ChromeUserPopulation population = 7;
 
   optional ExtensionData extension_data = 8;
+
+  message NonBinaryDownloadDetails {
+    optional string file_type = 1;
+    optional bytes url_spec_sha256 = 2;
+    optional string host = 3;
+    optional int64 length = 4;
+  }
+
+  optional NonBinaryDownloadDetails non_binary_download = 9;
 }
 
 message ClientIncidentResponse {
diff --git a/chrome/common/safe_browsing/download_protection_util.cc b/chrome/common/safe_browsing/download_protection_util.cc
index 060b26a..9fa1e4d2 100644
--- a/chrome/common/safe_browsing/download_protection_util.cc
+++ b/chrome/common/safe_browsing/download_protection_util.cc
@@ -6,7 +6,6 @@
 
 #include <algorithm>
 
-#include "base/files/file_path.h"
 #include "base/logging.h"
 #include "base/strings/string_util.h"
 
@@ -382,11 +381,7 @@
     nullptr, EXTENSION_OTHER, false, false
   };
 
-  base::FilePath::StringType file_basename = file.BaseName().value();
-  base::FilePath::StringPieceType trimmed_filename = base::TrimString(
-      file_basename, FILE_PATH_LITERAL(". "), base::TRIM_TRAILING);
-  base::FilePath::StringType extension =
-      base::FilePath(trimmed_filename).FinalExtension();
+  base::FilePath::StringType extension = GetFileExtension(file);
   SafeBrowsingFiletype needle = {extension.c_str()};
 
   const auto begin = kSafeBrowsingFileTypes;
@@ -408,6 +403,14 @@
 
 const int kSBClientDownloadExtensionsMax = EXTENSION_MAX;
 
+const base::FilePath::StringType GetFileExtension(const base::FilePath& file) {
+  // Remove trailing space and period characters from the extension.
+  base::FilePath::StringType file_basename = file.BaseName().value();
+  base::FilePath::StringPieceType trimmed_filename = base::TrimString(
+      file_basename, FILE_PATH_LITERAL(". "), base::TRIM_TRAILING);
+  return base::FilePath(trimmed_filename).FinalExtension();
+}
+
 bool IsArchiveFile(const base::FilePath& file) {
   // List of interesting archive file formats in kSafeBrowsingFileTypes is by no
   // means exhaustive, but are currently file types that Safe Browsing would
diff --git a/chrome/common/safe_browsing/download_protection_util.h b/chrome/common/safe_browsing/download_protection_util.h
index 9fc0e3b..f07181c 100644
--- a/chrome/common/safe_browsing/download_protection_util.h
+++ b/chrome/common/safe_browsing/download_protection_util.h
@@ -5,12 +5,9 @@
 #ifndef CHROME_COMMON_SAFE_BROWSING_DOWNLOAD_PROTECTION_UTIL_H_
 #define CHROME_COMMON_SAFE_BROWSING_DOWNLOAD_PROTECTION_UTIL_H_
 
+#include "base/files/file_path.h"
 #include "chrome/common/safe_browsing/csd.pb.h"
 
-namespace base {
-class FilePath;
-}
-
 namespace safe_browsing {
 namespace download_protection_util {
 
@@ -24,6 +21,9 @@
 // for paths that satisfy IsSupportedBinaryFile() above.
 ClientDownloadRequest::DownloadType GetDownloadType(const base::FilePath& file);
 
+// Returns the extension of the file at |path|.
+const base::FilePath::StringType GetFileExtension(const base::FilePath& file);
+
 // The maximum value returned by GetSBClientDownloadExtensionValueForUMA() + 1.
 extern const int kSBClientDownloadExtensionsMax;
 
diff --git a/chrome_elf/chrome_elf_constants.cc b/chrome_elf/chrome_elf_constants.cc
index 0300b53..2182268 100644
--- a/chrome_elf/chrome_elf_constants.cc
+++ b/chrome_elf/chrome_elf_constants.cc
@@ -12,9 +12,6 @@
 #error Unknown branding
 #endif
 
-const wchar_t kLocalStateFilename[] = L"Local State";
-const wchar_t kUserDataDirName[] = L"User Data";
-
 namespace blacklist {
 
 const wchar_t kRegistryBeaconPath[] =
diff --git a/chrome_elf/chrome_elf_constants.h b/chrome_elf/chrome_elf_constants.h
index bda7a50..a989eeb 100644
--- a/chrome_elf/chrome_elf_constants.h
+++ b/chrome_elf/chrome_elf_constants.h
@@ -9,10 +9,6 @@
 
 #include <windows.h>
 
-// directory names
-extern const wchar_t kLocalStateFilename[];
-extern const wchar_t kUserDataDirName[];
-
 namespace blacklist {
 
 // The registry path of the blacklist beacon.
diff --git a/components/BUILD.gn b/components/BUILD.gn
index 6acbea7..5f68cdd 100644
--- a/components/BUILD.gn
+++ b/components/BUILD.gn
@@ -7,6 +7,10 @@
 import("//testing/test.gni")
 import("//tools/grit/repack.gni")
 
+if (is_android) {
+  import("//build/config/android/rules.gni")
+}
+
 # Collection of all components. You wouldn't link to this, but this is rather
 # to reference the files so they can be compiled by the build system.
 group("all_components") {
@@ -516,6 +520,48 @@
   ]
 }
 
+if (is_android) {
+  android_assets("components_browsertests_assets") {
+    testonly = true
+    sources = [
+      "$root_out_dir/components_tests_resources.pak",
+      "$root_out_dir/content_shell.pak",
+    ]
+    deps = [
+      ":components_tests_pak",
+      "//content/shell:pak",
+      "//third_party/icu:icu_assets",
+      "//v8:v8_external_startup_data_assets",
+    ]
+  }
+
+  android_library("components_browsertests_java") {
+    testonly = true
+    deps = [
+      ":components_browsertests_resources",
+      "//base:base_java",
+      "//content/public/test/android:content_java_test_support",
+      "//content/shell/android:content_shell_browsertests_java",
+      "//testing/android/native_test:native_test_java",
+    ]
+    DEPRECATED_java_in_dir = "//components/test/android/browsertests_apk/src"
+  }
+
+  jinja_template("components_browsertests_manifest") {
+    testonly = true
+    input =
+        "//components/test/android/browsertests_apk/AndroidManifest.xml.jinja2"
+    output =
+        "${target_gen_dir}/components_browsertests_manifest/AndroidManifest.xml"
+  }
+
+  android_resources("components_browsertests_resources") {
+    testonly = true
+    resource_dirs = [ "//components/test/android/browsertests_apk/res" ]
+    custom_package = "org.chromium.components_browsertests_apk"
+  }
+}
+
 # TODO(GYP): Delete this after we've converted everything to GN.
 # The _run targets exist only for compatibility w/ GYP.
 group("components_browsertests_run") {
@@ -590,8 +636,15 @@
     sources += [ "test/android/browsertests_apk/components_browser_tests_jni_onload.cc" ]
     sources -= [ "autofill/content/browser/risk/fingerprint_browsertest.cc" ]
     deps += [ "//testing/android/native_test:native_test_support" ]
-    use_launcher = false
+    use_default_launcher = false
     isolate_file = "components_browsertests.isolate"
+    android_manifest =
+        "${target_gen_dir}/components_browsertests_manifest/AndroidManifest.xml"
+    apk_deps = [
+      ":components_browsertests_assets",
+      ":components_browsertests_java",
+      ":components_browsertests_manifest",
+    ]
   }
 
   if (is_linux) {
diff --git a/components/OWNERS b/components/OWNERS
index 2eae610..e1596ab 100644
--- a/components/OWNERS
+++ b/components/OWNERS
@@ -330,7 +330,6 @@
 per-file version_ui.gypi=bauerb@chromium.org
 per-file version_ui.gypi=dbeam@chromium.org
 per-file version_ui.gypi=estade@chromium.org
-per-file version_ui.gypi=jhawkins@chromium.org
 per-file version_ui.gypi=nkostylev@chromium.org
 per-file version_ui.gypi=pam@chromium.org
 per-file version_ui.gypi=xiyuan@chromium.org
diff --git a/components/about_ui/OWNERS b/components/about_ui/OWNERS
index da5824440..4298fad 100644
--- a/components/about_ui/OWNERS
+++ b/components/about_ui/OWNERS
@@ -1,7 +1,6 @@
 bauerb@chromium.org
 dbeam@chromium.org
 estade@chromium.org
-jhawkins@chromium.org
 nkostylev@chromium.org
 pam@chromium.org
 xiyuan@chromium.org
diff --git a/components/autofill/content/browser/content_autofill_driver_factory.cc b/components/autofill/content/browser/content_autofill_driver_factory.cc
index d19bd574..3d78a89 100644
--- a/components/autofill/content/browser/content_autofill_driver_factory.cc
+++ b/components/autofill/content/browser/content_autofill_driver_factory.cc
@@ -92,6 +92,9 @@
     content::RenderFrameHost* rfh,
     const content::LoadCommittedDetails& details,
     const content::FrameNavigateParams& params) {
+  // TODO(vabr): Remove those as soon as http://crbug.com/554479 is clarified.
+  CHECK(rfh->IsRenderFrameLive());
+  CHECK(ContainsKey(frame_driver_map_, rfh));
   frame_driver_map_[rfh]->DidNavigateFrame(details, params);
 }
 
diff --git a/components/component_updater/component_updater_service.cc b/components/component_updater/component_updater_service.cc
index 29b120ea..1c49d26 100644
--- a/components/component_updater/component_updater_service.cc
+++ b/components/component_updater/component_updater_service.cc
@@ -89,6 +89,7 @@
   DCHECK(thread_checker_.CalledOnValidThread());
   VLOG(1) << "CrxUpdateService stopping";
   timer_.Stop();
+  update_client_->Stop();
 }
 
 // Adds a component to be checked for upgrades. If the component exists it
diff --git a/components/component_updater/component_updater_service_unittest.cc b/components/component_updater/component_updater_service_unittest.cc
index c44c63b..9d78eb8 100644
--- a/components/component_updater/component_updater_service_unittest.cc
+++ b/components/component_updater/component_updater_service_unittest.cc
@@ -71,6 +71,7 @@
   MOCK_CONST_METHOD2(GetCrxUpdateState,
                      bool(const std::string& id, CrxUpdateItem* update_item));
   MOCK_CONST_METHOD1(IsUpdating, bool(const std::string& id));
+  MOCK_METHOD0(Stop, void());
 
  private:
   ~MockUpdateClient() override;
@@ -190,12 +191,14 @@
 TEST_F(ComponentUpdaterTest, AddObserver) {
   MockServiceObserver observer;
   EXPECT_CALL(update_client(), AddObserver(&observer)).Times(1);
+  EXPECT_CALL(update_client(), Stop()).Times(1);
   component_updater().AddObserver(&observer);
 }
 
 TEST_F(ComponentUpdaterTest, RemoveObserver) {
   MockServiceObserver observer;
   EXPECT_CALL(update_client(), RemoveObserver(&observer)).Times(1);
+  EXPECT_CALL(update_client(), Stop()).Times(1);
   component_updater().RemoveObserver(&observer);
 }
 
@@ -250,6 +253,7 @@
       .WillRepeatedly(Invoke(&loop_handler, &LoopHandler::OnUpdate));
 
   EXPECT_CALL(update_client(), IsUpdating(id1)).Times(1);
+  EXPECT_CALL(update_client(), Stop()).Times(1);
 
   EXPECT_TRUE(component_updater().RegisterComponent(crx_component1));
   EXPECT_TRUE(component_updater().RegisterComponent(crx_component2));
@@ -301,6 +305,7 @@
   EXPECT_CALL(update_client(),
               Install("jebgalgnebhfojomionfpkfelancnnkf", _, _))
       .WillOnce(Invoke(&loop_handler, &LoopHandler::OnInstall));
+  EXPECT_CALL(update_client(), Stop()).Times(1);
 
   EXPECT_TRUE(cus.RegisterComponent(crx_component));
   EXPECT_TRUE(OnDemandTester::OnDemand(&cus, id));
@@ -345,6 +350,7 @@
   EXPECT_CALL(update_client(),
               Install("jebgalgnebhfojomionfpkfelancnnkf", _, _))
       .WillOnce(Invoke(&loop_handler, &LoopHandler::OnInstall));
+  EXPECT_CALL(update_client(), Stop()).Times(1);
 
   EXPECT_TRUE(component_updater().RegisterComponent(crx_component));
   component_updater().MaybeThrottle(
diff --git a/components/components_browsertests.isolate b/components/components_browsertests.isolate
index c3ed0b48..c3a8b56 100644
--- a/components/components_browsertests.isolate
+++ b/components/components_browsertests.isolate
@@ -34,20 +34,10 @@
         ],
       },
     }],
-    ['OS=="android"', {
-      'variables': {
-        'files': [
-          '<(PRODUCT_DIR)/components_browsertests_apk_shell/assets/components_tests_resources.pak',
-          '<(PRODUCT_DIR)/components_browsertests_apk_shell/assets/content_shell.pak',
-        ],
-      },
-    }],
     ['OS=="linux" or OS=="mac" or OS=="win"', {
       'variables': {
         'files': [
           '../testing/test_env.py',
-          '<(PRODUCT_DIR)/components_tests_resources.pak',
-          '<(PRODUCT_DIR)/content_shell.pak',
         ],
       },
     }],
@@ -57,6 +47,8 @@
           'test/data/',
           'dom_distiller/core/javascript/',
           '../third_party/dom_distiller_js/dist/test/data/',
+          '<(PRODUCT_DIR)/components_tests_resources.pak',
+          '<(PRODUCT_DIR)/content_shell.pak',
         ],
       },
     }],
diff --git a/components/components_tests.gyp b/components/components_tests.gyp
index 437bf940..8187a69 100644
--- a/components/components_tests.gyp
+++ b/components/components_tests.gyp
@@ -1519,7 +1519,7 @@
           'includes': [ '../build/android/jinja_template.gypi' ],
         },
         {
-          # TODO(GN)
+          # GN: //components:components_browsertests_apk
           'target_name': 'components_browsertests_apk',
           'type': 'none',
           'dependencies': [
diff --git a/components/flags_ui/OWNERS b/components/flags_ui/OWNERS
index da5824440..4298fad 100644
--- a/components/flags_ui/OWNERS
+++ b/components/flags_ui/OWNERS
@@ -1,7 +1,6 @@
 bauerb@chromium.org
 dbeam@chromium.org
 estade@chromium.org
-jhawkins@chromium.org
 nkostylev@chromium.org
 pam@chromium.org
 xiyuan@chromium.org
diff --git a/components/html_viewer/devtools_agent_impl.cc b/components/html_viewer/devtools_agent_impl.cc
index bc4c871..a547062 100644
--- a/components/html_viewer/devtools_agent_impl.cc
+++ b/components/html_viewer/devtools_agent_impl.cc
@@ -21,7 +21,7 @@
 
   if (state) {
     cache_until_client_ready_ = true;
-    frame_->devToolsAgent()->reattach(blink::WebString::fromUTF8(id_),
+    frame_->devToolsAgent()->reattach(blink::WebString::fromUTF8(id_), 0,
                                       blink::WebString::fromUTF8(*state));
   }
 }
@@ -52,16 +52,17 @@
                                        message.state);
     cached_client_messages_.clear();
   } else {
-    frame_->devToolsAgent()->attach(blink::WebString::fromUTF8(id_));
+    frame_->devToolsAgent()->attach(blink::WebString::fromUTF8(id_), 0);
   }
 }
 
 void DevToolsAgentImpl::DispatchProtocolMessage(const mojo::String& message) {
   frame_->devToolsAgent()->dispatchOnInspectorBackend(
-      blink::WebString::fromUTF8(message));
+      0, blink::WebString::fromUTF8(message));
 }
 
-void DevToolsAgentImpl::sendProtocolMessage(int call_id,
+void DevToolsAgentImpl::sendProtocolMessage(int session_id,
+                                            int call_id,
                                             const blink::WebString& response,
                                             const blink::WebString& state) {
   DCHECK(!response.isNull());
diff --git a/components/html_viewer/devtools_agent_impl.h b/components/html_viewer/devtools_agent_impl.h
index f062b31d..17ff601d 100644
--- a/components/html_viewer/devtools_agent_impl.h
+++ b/components/html_viewer/devtools_agent_impl.h
@@ -38,7 +38,8 @@
   void DispatchProtocolMessage(const mojo::String& message) override;
 
   // blink::WebDevToolsAgentClient implementation.
-  void sendProtocolMessage(int call_id,
+  void sendProtocolMessage(int session_id,
+                           int call_id,
                            const blink::WebString& response,
                            const blink::WebString& state);
 
diff --git a/components/mus/public/cpp/lib/in_flight_change.cc b/components/mus/public/cpp/lib/in_flight_change.cc
index 114b497..706f973b 100644
--- a/components/mus/public/cpp/lib/in_flight_change.cc
+++ b/components/mus/public/cpp/lib/in_flight_change.cc
@@ -33,4 +33,18 @@
     WindowPrivate(window).LocalSetBounds(window->bounds(), revert_bounds_);
 }
 
+CrashInFlightChange::CrashInFlightChange(Id window_id, ChangeType type)
+    : InFlightChange(window_id, type) {}
+
+CrashInFlightChange::~CrashInFlightChange() {}
+
+void CrashInFlightChange::PreviousChangeCompleted(InFlightChange* change,
+                                                  bool success) {
+  CHECK(success);
+}
+
+void CrashInFlightChange::Revert() {
+  CHECK(false);
+}
+
 }  // namespace mus
diff --git a/components/mus/public/cpp/lib/in_flight_change.h b/components/mus/public/cpp/lib/in_flight_change.h
index 6856c72f..a627760 100644
--- a/components/mus/public/cpp/lib/in_flight_change.h
+++ b/components/mus/public/cpp/lib/in_flight_change.h
@@ -15,6 +15,7 @@
 
 enum class ChangeType {
   BOUNDS,
+  NEW_WINDOW,
 };
 
 // InFlightChange is used to track function calls to the server and take the
@@ -78,6 +79,21 @@
   DISALLOW_COPY_AND_ASSIGN(InFlightBoundsChange);
 };
 
+// Inflight change that crashes on failure. This is useful for changes that are
+// expected to always complete.
+class CrashInFlightChange : public InFlightChange {
+ public:
+  CrashInFlightChange(Id window_id, ChangeType type);
+  ~CrashInFlightChange() override;
+
+  // InFlightChange:
+  void PreviousChangeCompleted(InFlightChange* change, bool success) override;
+  void Revert() override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(CrashInFlightChange);
+};
+
 }  // namespace mus
 
 #endif  // COMPONENTS_MUS_PUBLIC_CPP_LIB_IN_FLIGHT_CHANGE_H_
diff --git a/components/mus/public/cpp/lib/window_tree_client_impl.cc b/components/mus/public/cpp/lib/window_tree_client_impl.cc
index 1056ead0..3c5e329 100644
--- a/components/mus/public/cpp/lib/window_tree_client_impl.cc
+++ b/components/mus/public/cpp/lib/window_tree_client_impl.cc
@@ -186,12 +186,8 @@
                                      const gfx::Rect& old_bounds,
                                      const gfx::Rect& bounds) {
   DCHECK(tree_);
-  const uint32_t change_id = next_change_id_++;
-  {
-    scoped_ptr<InFlightBoundsChange> change(
-        new InFlightBoundsChange(this, window_id, old_bounds));
-    in_flight_map_.set(change_id, change.Pass());
-  }
+  const uint32_t change_id = ScheduleInFlightChange(
+      make_scoped_ptr(new InFlightBoundsChange(this, window_id, old_bounds)));
   tree_->SetWindowBounds(change_id, window_id, mojo::Rect::From(bounds));
 }
 
@@ -307,9 +303,9 @@
 Id WindowTreeClientImpl::CreateWindowOnServer() {
   DCHECK(tree_);
   const Id window_id = MakeTransportId(connection_id_, next_window_id_++);
-  tree_->NewWindow(window_id, [this](mojom::ErrorCode code) {
-    OnActionCompleted(code == mojom::ERROR_CODE_NONE);
-  });
+  const uint32_t change_id = ScheduleInFlightChange(make_scoped_ptr(
+      new CrashInFlightChange(window_id, ChangeType::NEW_WINDOW)));
+  tree_->NewWindow(change_id, window_id);
   return window_id;
 }
 
@@ -325,6 +321,13 @@
   return nullptr;
 }
 
+uint32_t WindowTreeClientImpl::ScheduleInFlightChange(
+    scoped_ptr<InFlightChange> change) {
+  const uint32_t change_id = next_change_id_++;
+  in_flight_map_.set(change_id, change.Pass());
+  return change_id;
+}
+
 void WindowTreeClientImpl::OnEmbedImpl(mojom::WindowTree* window_tree,
                                        ConnectionSpecificId connection_id,
                                        mojom::WindowDataPtr root_data,
diff --git a/components/mus/public/cpp/lib/window_tree_client_impl.h b/components/mus/public/cpp/lib/window_tree_client_impl.h
index 41aca1c..04fe215 100644
--- a/components/mus/public/cpp/lib/window_tree_client_impl.h
+++ b/components/mus/public/cpp/lib/window_tree_client_impl.h
@@ -115,6 +115,8 @@
   InFlightChange* GetOldestInFlightChangeMatching(Id window_id,
                                                   ChangeType change_type);
 
+  uint32_t ScheduleInFlightChange(scoped_ptr<InFlightChange> change);
+
   // OnEmbed() calls into this. Exposed as a separate function for testing.
   void OnEmbedImpl(mojom::WindowTree* window_tree,
                    ConnectionSpecificId connection_id,
diff --git a/components/mus/public/cpp/tests/test_window_tree.cc b/components/mus/public/cpp/tests/test_window_tree.cc
index 38f0bc9..15efbf76 100644
--- a/components/mus/public/cpp/tests/test_window_tree.cc
+++ b/components/mus/public/cpp/tests/test_window_tree.cc
@@ -20,8 +20,7 @@
   return true;
 }
 
-void TestWindowTree::NewWindow(uint32_t window_id,
-                               const NewWindowCallback& callback) {}
+void TestWindowTree::NewWindow(uint32_t change_id, uint32_t window_id) {}
 
 void TestWindowTree::DeleteWindow(uint32_t window_id,
                                   const DeleteWindowCallback& callback) {}
diff --git a/components/mus/public/cpp/tests/test_window_tree.h b/components/mus/public/cpp/tests/test_window_tree.h
index e732476e2..57e60cd1 100644
--- a/components/mus/public/cpp/tests/test_window_tree.h
+++ b/components/mus/public/cpp/tests/test_window_tree.h
@@ -23,8 +23,7 @@
 
  private:
   // mojom::WindowTree:
-  void NewWindow(uint32_t window_id,
-                 const NewWindowCallback& callback) override;
+  void NewWindow(uint32_t change_id, uint32_t window_id) override;
   void DeleteWindow(uint32_t window_id,
                     const DeleteWindowCallback& callback) override;
   void SetWindowBounds(uint32_t change_id,
diff --git a/components/mus/public/interfaces/window_tree.mojom b/components/mus/public/interfaces/window_tree.mojom
index 834b60c9..37b29e6 100644
--- a/components/mus/public/interfaces/window_tree.mojom
+++ b/components/mus/public/interfaces/window_tree.mojom
@@ -89,7 +89,7 @@
   //
   // TODO(erg): Once we have default values in mojo, make this take a map of
   // properties.
-  NewWindow(uint32 window_id) => (ErrorCode error_code);
+  NewWindow(uint32 change_id, uint32 window_id);
 
   // Deletes a window. This does not recurse. No hierarchy change notifications
   // are sent as a result of this. Only the connection that created the window
diff --git a/components/mus/ws/window_tree_apptest.cc b/components/mus/ws/window_tree_apptest.cc
index 09ad12a..0edf629 100644
--- a/components/mus/ws/window_tree_apptest.cc
+++ b/components/mus/ws/window_tree_apptest.cc
@@ -51,13 +51,6 @@
   run_loop->Quit();
 }
 
-void ErrorCodeResultCallback(base::RunLoop* run_loop,
-                             ErrorCode* result_cache,
-                             ErrorCode result) {
-  *result_cache = result;
-  run_loop->Quit();
-}
-
 void WindowTreeResultCallback(base::RunLoop* run_loop,
                               std::vector<TestWindow>* windows,
                               Array<WindowDataPtr> results) {
@@ -106,15 +99,6 @@
   return result;
 }
 
-ErrorCode NewWindowWithErrorCode(WindowTree* ws, Id window_id) {
-  ErrorCode result = ERROR_CODE_NONE;
-  base::RunLoop run_loop;
-  ws->NewWindow(window_id,
-                base::Bind(&ErrorCodeResultCallback, &run_loop, &result));
-  run_loop.Run();
-  return result;
-}
-
 bool AddWindow(WindowTree* ws, Id parent, Id child) {
   bool result = false;
   base::RunLoop run_loop;
@@ -189,19 +173,6 @@
 
 // Utility functions -----------------------------------------------------------
 
-// Waits for all messages to be received by |ws|. This is done by attempting to
-// create a bogus window. When we get the response we know all messages have
-// been
-// processed.
-bool WaitForAllMessages(WindowTree* ws) {
-  ErrorCode result = ERROR_CODE_NONE;
-  base::RunLoop run_loop;
-  ws->NewWindow(WindowIdToTransportId(InvalidWindowId()),
-                base::Bind(&ErrorCodeResultCallback, &run_loop, &result));
-  run_loop.Run();
-  return result != ERROR_CODE_NONE;
-}
-
 const Id kNullParentId = 0;
 std::string IdToString(Id id) {
   return (id == kNullParentId) ? "null" : base::StringPrintf(
@@ -224,6 +195,9 @@
         app_(app),
         connection_id_(0),
         root_window_id_(0),
+        // Start with a random large number so tests can use lower ids if they
+        // want.
+        next_change_id_(10000),
         waiting_change_id_(0),
         on_change_completed_result_(false) {
     tracker_.set_delegate(this);
@@ -249,6 +223,8 @@
     wait_state_.reset();
   }
 
+  uint32_t GetAndAdvanceChangeId() { return next_change_id_++; }
+
   // Runs a nested MessageLoop until OnEmbed() has been encountered.
   void WaitForOnEmbed() {
     if (tree_)
@@ -269,14 +245,24 @@
     return on_change_completed_result_;
   }
 
+  // Waits for all messages to be received by |ws|. This is done by attempting
+  // to create a bogus window. When we get the response we know all messages
+  // have been processed.
+  bool WaitForAllMessages() {
+    return NewWindowWithCompleteId(WindowIdToTransportId(InvalidWindowId())) ==
+           0;
+  }
+
   Id NewWindow(ConnectionSpecificId window_id) {
-    ErrorCode result = ERROR_CODE_NONE;
-    base::RunLoop run_loop;
-    Id id = BuildWindowId(connection_id_, window_id);
-    tree()->NewWindow(id,
-                      base::Bind(&ErrorCodeResultCallback, &run_loop, &result));
-    run_loop.Run();
-    return result == ERROR_CODE_NONE ? id : 0;
+    return NewWindowWithCompleteId(BuildWindowId(connection_id_, window_id));
+  }
+
+  // Generally you want NewWindow(), but use this if you need to test given
+  // a complete window id (NewWindow() ors with the connection id).
+  Id NewWindowWithCompleteId(Id id) {
+    const uint32_t change_id = GetAndAdvanceChangeId();
+    tree()->NewWindow(change_id, id);
+    return WaitForChangeCompleted(change_id) ? id : 0;
   }
 
   void set_root_window(Id root_window_id) { root_window_id_ = root_window_id; }
@@ -395,6 +381,7 @@
   mojo::ApplicationImpl* app_;
   Id connection_id_;
   Id root_window_id_;
+  uint32_t next_change_id_;
   uint32_t waiting_change_id_;
   bool on_change_completed_result_;
   scoped_ptr<base::RunLoop> change_completed_run_loop_;
@@ -752,14 +739,12 @@
   EXPECT_TRUE(changes1()->empty());
 
   // Can't create a window with the same id.
-  ASSERT_EQ(mojom::ERROR_CODE_VALUE_IN_USE,
-            NewWindowWithErrorCode(ws1(), window_1_1));
+  ASSERT_EQ(0u, ws_client1()->NewWindowWithCompleteId(window_1_1));
   EXPECT_TRUE(changes1()->empty());
 
   // Can't create a window with a bogus connection id.
-  EXPECT_EQ(
-      mojom::ERROR_CODE_ILLEGAL_ARGUMENT,
-      NewWindowWithErrorCode(ws1(), BuildWindowId(connection_id_1() + 1, 1)));
+  ASSERT_EQ(0u, ws_client1()->NewWindowWithCompleteId(
+                    BuildWindowId(connection_id_1() + 1, 1)));
   EXPECT_TRUE(changes1()->empty());
 }
 
@@ -834,14 +819,14 @@
   ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
   ASSERT_TRUE(SetWindowVisibility(ws1(), window_1_1, true));
 
-  ASSERT_TRUE(WaitForAllMessages(ws2()));
+  ASSERT_TRUE(ws_client2()->WaitForAllMessages());
   changes2()->clear();
 
   // 1,1->1,2->1,11
   {
     // Client 2 should not get anything (1,2 is from another connection).
     ASSERT_TRUE(AddWindow(ws1(), window_1_1, window_1_2));
-    ASSERT_TRUE(WaitForAllMessages(ws2()));
+    ASSERT_TRUE(ws_client2()->WaitForAllMessages());
     EXPECT_TRUE(changes2()->empty());
   }
 
@@ -875,7 +860,7 @@
   {
     changes2()->clear();
     ASSERT_TRUE(AddWindow(ws1(), window_1_11, window_1_111));
-    ASSERT_TRUE(WaitForAllMessages(ws2()));
+    ASSERT_TRUE(ws_client2()->WaitForAllMessages());
     EXPECT_TRUE(changes2()->empty());
   }
 
@@ -1451,7 +1436,7 @@
   ASSERT_TRUE(window_2_3);
   ASSERT_TRUE(SetWindowVisibility(ws2(), window_2_3, true));
   ASSERT_TRUE(AddWindow(ws2(), window_1_2, window_2_3));
-  WaitForAllMessages(ws1());
+  ASSERT_TRUE(ws_client1()->WaitForAllMessages());
 
   changes2()->clear();
   // Hide 1,2 from connection 1. Connection 2 should see this.
@@ -1686,7 +1671,7 @@
   // Establish a third connection in window_2_2.
   ASSERT_NO_FATAL_FAILURE(EstablishThirdConnection(ws1(), window_2_2));
 
-  WaitForAllMessages(ws2());
+  ASSERT_TRUE(ws_client2()->WaitForAllMessages());
   EXPECT_EQ(std::string(), SingleChangeToDescription(*changes2()));
 }
 
diff --git a/components/mus/ws/window_tree_impl.cc b/components/mus/ws/window_tree_impl.cc
index 627a6f2..a16188c 100644
--- a/components/mus/ws/window_tree_impl.cc
+++ b/components/mus/ws/window_tree_impl.cc
@@ -119,15 +119,15 @@
       change_id, error_code == mojom::WINDOW_MANAGER_ERROR_CODE_SUCCESS);
 }
 
-mojom::ErrorCode WindowTreeImpl::NewWindow(const WindowId& window_id) {
+bool WindowTreeImpl::NewWindow(const WindowId& window_id) {
   if (window_id.connection_id != id_)
-    return mojom::ERROR_CODE_ILLEGAL_ARGUMENT;
+    return false;
   if (window_map_.find(window_id.window_id) != window_map_.end())
-    return mojom::ERROR_CODE_VALUE_IN_USE;
+    return false;
   window_map_[window_id.window_id] =
       connection_manager_->CreateServerWindow(window_id);
   known_windows_.insert(WindowIdToTransportId(window_id));
-  return mojom::ERROR_CODE_NONE;
+  return true;
 }
 
 bool WindowTreeImpl::AddWindow(const WindowId& parent_id,
@@ -559,10 +559,9 @@
     window->Remove(children[i]);
 }
 
-void WindowTreeImpl::NewWindow(
-    Id transport_window_id,
-    const Callback<void(mojom::ErrorCode)>& callback) {
-  callback.Run(NewWindow(WindowIdFromTransportId(transport_window_id)));
+void WindowTreeImpl::NewWindow(uint32_t change_id, Id transport_window_id) {
+  client_->OnChangeCompleted(
+      change_id, NewWindow(WindowIdFromTransportId(transport_window_id)));
 }
 
 void WindowTreeImpl::DeleteWindow(Id transport_window_id,
diff --git a/components/mus/ws/window_tree_impl.h b/components/mus/ws/window_tree_impl.h
index 80e0476..92717ed1 100644
--- a/components/mus/ws/window_tree_impl.h
+++ b/components/mus/ws/window_tree_impl.h
@@ -74,7 +74,7 @@
 
   // These functions are synchronous variants of those defined in the mojom. The
   // WindowTree implementations all call into these. See the mojom for details.
-  mojom::ErrorCode NewWindow(const WindowId& window_id);
+  bool NewWindow(const WindowId& window_id);
   bool AddWindow(const WindowId& parent_id, const WindowId& child_id);
   std::vector<const ServerWindow*> GetWindowTree(
       const WindowId& window_id) const;
@@ -182,9 +182,7 @@
                              mojom::WindowManagerErrorCode error_code);
 
   // WindowTree:
-  void NewWindow(
-      Id transport_window_id,
-      const mojo::Callback<void(mojom::ErrorCode)>& callback) override;
+  void NewWindow(uint32_t change_id, Id transport_window_id) override;
   void DeleteWindow(Id transport_window_id,
                     const mojo::Callback<void(bool)>& callback) override;
   void AddWindow(Id parent_id,
diff --git a/components/mus/ws/window_tree_unittest.cc b/components/mus/ws/window_tree_unittest.cc
index 77661f9..c2c9482 100644
--- a/components/mus/ws/window_tree_unittest.cc
+++ b/components/mus/ws/window_tree_unittest.cc
@@ -345,7 +345,7 @@
 // Verifies focus correctly changes on pointer events.
 TEST_F(WindowTreeTest, FocusOnPointer) {
   const WindowId embed_window_id(wm_connection()->id(), 1);
-  EXPECT_EQ(ERROR_CODE_NONE, wm_connection()->NewWindow(embed_window_id));
+  EXPECT_TRUE(wm_connection()->NewWindow(embed_window_id));
   EXPECT_TRUE(wm_connection()->SetWindowVisibility(embed_window_id, true));
   EXPECT_TRUE(
       wm_connection()->AddWindow(*(wm_connection()->root()), embed_window_id));
@@ -370,7 +370,7 @@
       ->SetBounds(gfx::Rect(0, 0, 50, 50));
 
   const WindowId child1(connection1->id(), 1);
-  EXPECT_EQ(ERROR_CODE_NONE, connection1->NewWindow(child1));
+  EXPECT_TRUE(connection1->NewWindow(child1));
   EXPECT_TRUE(connection1->AddWindow(embed_window_id, child1));
   ServerWindow* v1 = connection1->GetWindow(child1);
   v1->SetVisible(true);
@@ -427,7 +427,7 @@
 
 TEST_F(WindowTreeTest, BasicInputEventTarget) {
   const WindowId embed_window_id(wm_connection()->id(), 1);
-  EXPECT_EQ(ERROR_CODE_NONE, wm_connection()->NewWindow(embed_window_id));
+  EXPECT_TRUE(wm_connection()->NewWindow(embed_window_id));
   EXPECT_TRUE(wm_connection()->SetWindowVisibility(embed_window_id, true));
   EXPECT_TRUE(
       wm_connection()->AddWindow(*(wm_connection()->root()), embed_window_id));
@@ -452,7 +452,7 @@
       ->SetBounds(gfx::Rect(0, 0, 50, 50));
 
   const WindowId child1(connection1->id(), 1);
-  EXPECT_EQ(ERROR_CODE_NONE, connection1->NewWindow(child1));
+  EXPECT_TRUE(connection1->NewWindow(child1));
   EXPECT_TRUE(connection1->AddWindow(embed_window_id, child1));
   ServerWindow* v1 = connection1->GetWindow(child1);
   v1->SetVisible(true);
diff --git a/components/password_manager/content/browser/content_password_manager_driver.h b/components/password_manager/content/browser/content_password_manager_driver.h
index 6060495..504a913 100644
--- a/components/password_manager/content/browser/content_password_manager_driver.h
+++ b/components/password_manager/content/browser/content_password_manager_driver.h
@@ -5,6 +5,9 @@
 #ifndef COMPONENTS_PASSWORD_MANAGER_CONTENT_BROWSER_CONTENT_PASSWORD_MANAGER_DRIVER_H_
 #define COMPONENTS_PASSWORD_MANAGER_CONTENT_BROWSER_CONTENT_PASSWORD_MANAGER_DRIVER_H_
 
+#include <map>
+#include <vector>
+
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
 #include "components/autofill/core/common/password_form_field_prediction_map.h"
diff --git a/components/password_manager/content/browser/content_password_manager_driver_factory.cc b/components/password_manager/content/browser/content_password_manager_driver_factory.cc
index b401017..8a07ab9 100644
--- a/components/password_manager/content/browser/content_password_manager_driver_factory.cc
+++ b/components/password_manager/content/browser/content_password_manager_driver_factory.cc
@@ -99,6 +99,9 @@
     content::RenderFrameHost* render_frame_host,
     const content::LoadCommittedDetails& details,
     const content::FrameNavigateParams& params) {
+  // TODO(vabr): Remove those as soon as http://crbug.com/554479 is clarified.
+  CHECK(render_frame_host->IsRenderFrameLive());
+  CHECK(ContainsKey(frame_driver_map_, render_frame_host));
   if (!render_frame_host->IsRenderFrameLive())
     return;
   frame_driver_map_.find(render_frame_host)
diff --git a/components/password_manager/content/browser/credential_manager_dispatcher_unittest.cc b/components/password_manager/content/browser/credential_manager_dispatcher_unittest.cc
index d176b07..939579b 100644
--- a/components/password_manager/content/browser/credential_manager_dispatcher_unittest.cc
+++ b/components/password_manager/content/browser/credential_manager_dispatcher_unittest.cc
@@ -4,6 +4,9 @@
 
 #include "components/password_manager/content/browser/credential_manager_dispatcher.h"
 
+#include <string>
+#include <vector>
+
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/prefs/pref_registry_simple.h"
@@ -31,6 +34,8 @@
 
 using testing::_;
 
+namespace password_manager {
+
 namespace {
 
 // Chosen by fair dice roll. Guaranteed to be random.
@@ -40,8 +45,7 @@
 const char kTestAndroidRealm1[] = "android://hash@com.example.one.android/";
 const char kTestAndroidRealm2[] = "android://hash@com.example.two.android/";
 
-class MockPasswordManagerClient
-    : public password_manager::StubPasswordManagerClient {
+class MockPasswordManagerClient : public StubPasswordManagerClient {
  public:
   MOCK_CONST_METHOD0(IsSavingAndFillingEnabledForCurrentPage, bool());
   MOCK_CONST_METHOD0(IsOffTheRecord, bool());
@@ -49,34 +53,28 @@
   MOCK_METHOD1(NotifyUserAutoSigninPtr,
                bool(const std::vector<autofill::PasswordForm*>& local_forms));
   MOCK_METHOD2(PromptUserToSavePasswordPtr,
-               void(password_manager::PasswordFormManager*,
-                    password_manager::CredentialSourceType type));
+               void(PasswordFormManager*, CredentialSourceType type));
   MOCK_METHOD4(PromptUserToChooseCredentialsPtr,
                bool(const std::vector<autofill::PasswordForm*>& local_forms,
                     const std::vector<autofill::PasswordForm*>& federated_forms,
                     const GURL& origin,
-                    base::Callback<void(
-                        const password_manager::CredentialInfo&)> callback));
+                    base::Callback<void(const CredentialInfo&)> callback));
 
-  MockPasswordManagerClient(password_manager::PasswordStore* store)
-      : store_(store) {
-    prefs_.registry()->RegisterBooleanPref(
-        password_manager::prefs::kPasswordManagerAutoSignin, true);
+  explicit MockPasswordManagerClient(PasswordStore* store) : store_(store) {
+    prefs_.registry()->RegisterBooleanPref(prefs::kPasswordManagerAutoSignin,
+                                           true);
   }
   ~MockPasswordManagerClient() override {}
 
-  bool PromptUserToSaveOrUpdatePassword(
-      scoped_ptr<password_manager::PasswordFormManager> manager,
-      password_manager::CredentialSourceType type,
-      bool update_password) override {
+  bool PromptUserToSaveOrUpdatePassword(scoped_ptr<PasswordFormManager> manager,
+                                        CredentialSourceType type,
+                                        bool update_password) override {
     manager_.swap(manager);
     PromptUserToSavePasswordPtr(manager_.get(), type);
     return true;
   }
 
-  password_manager::PasswordStore* GetPasswordStore() const override {
-    return store_;
-  }
+  PasswordStore* GetPasswordStore() const override { return store_; }
 
   PrefService* GetPrefs() override { return &prefs_; }
 
@@ -84,13 +82,12 @@
       ScopedVector<autofill::PasswordForm> local_forms,
       ScopedVector<autofill::PasswordForm> federated_forms,
       const GURL& origin,
-      base::Callback<void(const password_manager::CredentialInfo&)> callback) {
+      base::Callback<void(const CredentialInfo&)> callback) {
     EXPECT_FALSE(local_forms.empty() && federated_forms.empty());
-    password_manager::CredentialInfo info(
+    CredentialInfo info(
         local_forms.empty() ? *federated_forms[0] : *local_forms[0],
-        local_forms.empty()
-            ? password_manager::CredentialType::CREDENTIAL_TYPE_FEDERATED
-            : password_manager::CredentialType::CREDENTIAL_TYPE_PASSWORD);
+        local_forms.empty() ? CredentialType::CREDENTIAL_TYPE_FEDERATED
+                            : CredentialType::CREDENTIAL_TYPE_PASSWORD);
     base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
                                                   base::Bind(callback, info));
     PromptUserToChooseCredentialsPtr(local_forms.get(), federated_forms.get(),
@@ -104,46 +101,40 @@
     NotifyUserAutoSigninPtr(local_forms.get());
   }
 
-  password_manager::PasswordFormManager* pending_manager() const {
-    return manager_.get();
-  }
+  PasswordFormManager* pending_manager() const { return manager_.get(); }
 
   void set_zero_click_enabled(bool zero_click_enabled) {
-    prefs_.SetBoolean(password_manager::prefs::kPasswordManagerAutoSignin,
-                      zero_click_enabled);
+    prefs_.SetBoolean(prefs::kPasswordManagerAutoSignin, zero_click_enabled);
   }
 
  private:
   TestingPrefServiceSimple prefs_;
-  password_manager::PasswordStore* store_;
-  scoped_ptr<password_manager::PasswordFormManager> manager_;
+  PasswordStore* store_;
+  scoped_ptr<PasswordFormManager> manager_;
 
   DISALLOW_COPY_AND_ASSIGN(MockPasswordManagerClient);
 };
 
-class TestCredentialManagerDispatcher
-    : public password_manager::CredentialManagerDispatcher {
+class TestCredentialManagerDispatcher : public CredentialManagerDispatcher {
  public:
-  TestCredentialManagerDispatcher(
-      content::WebContents* web_contents,
-      password_manager::PasswordManagerClient* client,
-      password_manager::PasswordManagerDriver* driver);
+  TestCredentialManagerDispatcher(content::WebContents* web_contents,
+                                  PasswordManagerClient* client,
+                                  PasswordManagerDriver* driver);
 
  private:
-  base::WeakPtr<password_manager::PasswordManagerDriver> GetDriver() override;
+  base::WeakPtr<PasswordManagerDriver> GetDriver() override;
 
-  base::WeakPtr<password_manager::PasswordManagerDriver> driver_;
+  base::WeakPtr<PasswordManagerDriver> driver_;
 };
 
 TestCredentialManagerDispatcher::TestCredentialManagerDispatcher(
     content::WebContents* web_contents,
-    password_manager::PasswordManagerClient* client,
-    password_manager::PasswordManagerDriver* driver)
+    PasswordManagerClient* client,
+    PasswordManagerDriver* driver)
     : CredentialManagerDispatcher(web_contents, client),
-      driver_(driver->AsWeakPtr()) {
-}
+      driver_(driver->AsWeakPtr()) {}
 
-base::WeakPtr<password_manager::PasswordManagerDriver>
+base::WeakPtr<PasswordManagerDriver>
 TestCredentialManagerDispatcher::GetDriver() {
   return driver_;
 }
@@ -157,8 +148,6 @@
 
 }  // namespace
 
-namespace password_manager {
-
 class CredentialManagerDispatcherTest
     : public content::RenderViewHostTestHarness {
  public:
@@ -283,12 +272,9 @@
 };
 
 TEST_F(CredentialManagerDispatcherTest, CredentialManagerOnStore) {
-  CredentialInfo info(
-      form_, password_manager::CredentialType::CREDENTIAL_TYPE_PASSWORD);
-  EXPECT_CALL(
-      *client_,
-      PromptUserToSavePasswordPtr(
-          _, password_manager::CredentialSourceType::CREDENTIAL_SOURCE_API))
+  CredentialInfo info(form_, CredentialType::CREDENTIAL_TYPE_PASSWORD);
+  EXPECT_CALL(*client_, PromptUserToSavePasswordPtr(
+                            _, CredentialSourceType::CREDENTIAL_SOURCE_API))
       .Times(testing::Exactly(1));
 
   dispatcher()->OnStore(kRequestId, info);
@@ -320,10 +306,8 @@
   CredentialInfo info(form_, CredentialType::CREDENTIAL_TYPE_PASSWORD);
   EXPECT_CALL(*client_, IsSavingAndFillingEnabledForCurrentPage())
       .WillRepeatedly(testing::Return(false));
-  EXPECT_CALL(
-      *client_,
-      PromptUserToSavePasswordPtr(
-          _, password_manager::CredentialSourceType::CREDENTIAL_SOURCE_API))
+  EXPECT_CALL(*client_, PromptUserToSavePasswordPtr(
+                            _, CredentialSourceType::CREDENTIAL_SOURCE_API))
       .Times(testing::Exactly(0));
 
   dispatcher()->OnStore(kRequestId, info);
@@ -409,10 +393,8 @@
 TEST_F(CredentialManagerDispatcherTest,
        CredentialManagerOnRequestCredentialWithEmptyPasswordStore) {
   std::vector<GURL> federations;
-  EXPECT_CALL(
-      *client_,
-      PromptUserToSavePasswordPtr(
-          _, password_manager::CredentialSourceType::CREDENTIAL_SOURCE_API))
+  EXPECT_CALL(*client_, PromptUserToSavePasswordPtr(
+                            _, CredentialSourceType::CREDENTIAL_SOURCE_API))
       .Times(testing::Exactly(0));
   EXPECT_CALL(*client_, PromptUserToChooseCredentialsPtr(_, _, _, _))
       .Times(testing::Exactly(0));
@@ -437,10 +419,8 @@
   store_->AddLogin(cross_origin_form_);
 
   std::vector<GURL> federations;
-  EXPECT_CALL(
-      *client_,
-      PromptUserToSavePasswordPtr(
-          _, password_manager::CredentialSourceType::CREDENTIAL_SOURCE_API))
+  EXPECT_CALL(*client_, PromptUserToSavePasswordPtr(
+                            _, CredentialSourceType::CREDENTIAL_SOURCE_API))
       .Times(testing::Exactly(0));
   EXPECT_CALL(*client_, PromptUserToChooseCredentialsPtr(_, _, _, _))
       .Times(testing::Exactly(0));
diff --git a/components/password_manager/core/browser/password_form_manager.cc b/components/password_manager/core/browser/password_form_manager.cc
index 04c3bc2..7d499f3 100644
--- a/components/password_manager/core/browser/password_form_manager.cc
+++ b/components/password_manager/core/browser/password_form_manager.cc
@@ -5,6 +5,7 @@
 #include "components/password_manager/core/browser/password_form_manager.h"
 
 #include <algorithm>
+#include <map>
 #include <set>
 
 #include "base/metrics/histogram_macros.h"
diff --git a/components/precache/content/precache_manager.cc b/components/precache/content/precache_manager.cc
index 3e91b920..3d317ee 100644
--- a/components/precache/content/precache_manager.cc
+++ b/components/precache/content/precache_manager.cc
@@ -242,9 +242,14 @@
 
   precache_fetcher_.reset();
 
-  precache_completion_callback_.Run(!is_precaching_);
-  // Uninitialize the callback so that any scoped_refptrs in it are released.
-  precache_completion_callback_.Reset();
+  // Run completion callback if not null. It's null if the client is in the
+  // Control group and CancelPrecaching is called before TopHosts computation
+  // finishes.
+  if (!precache_completion_callback_.is_null()) {
+    precache_completion_callback_.Run(!is_precaching_);
+    // Uninitialize the callback so that any scoped_refptrs in it are released.
+    precache_completion_callback_.Reset();
+  }
 
   is_precaching_ = false;
 }
diff --git a/components/precache/content/precache_manager_unittest.cc b/components/precache/content/precache_manager_unittest.cc
index bccbbda..674883b 100644
--- a/components/precache/content/precache_manager_unittest.cc
+++ b/components/precache/content/precache_manager_unittest.cc
@@ -117,10 +117,17 @@
   PrecacheManagerUnderTest(content::BrowserContext* browser_context,
                            const sync_driver::SyncService* const sync_service,
                            const history::HistoryService* const history_service)
-      : PrecacheManager(browser_context, sync_service, history_service) {}
-  bool IsInExperimentGroup() const override { return true; }
-  bool IsInControlGroup() const override { return false; }
+      : PrecacheManager(browser_context, sync_service, history_service),
+        control_group_(false) {}
+  bool IsInExperimentGroup() const override { return !control_group_; }
+  bool IsInControlGroup() const override { return control_group_; }
   bool IsPrecachingAllowed() const override { return true; }
+  void SetInControlGroup(bool in_control_group) {
+    control_group_ = in_control_group;
+  }
+
+ private:
+  bool control_group_;
 };
 
 class PrecacheManagerTest : public testing::Test {
@@ -184,6 +191,26 @@
   EXPECT_EQ(expected_requested_urls, url_callback_.requested_urls());
 }
 
+TEST_F(PrecacheManagerTest, StartAndCancelPrecachingBeforeTopHostsCompleted) {
+  EXPECT_FALSE(precache_manager_.IsPrecaching());
+
+  MockHistoryService::TopHostsCallback top_hosts_callback;
+  EXPECT_CALL(history_service_, TopHosts(NumTopHosts(), _))
+      .WillOnce(SaveArg<1>(&top_hosts_callback));
+
+  precache_manager_.SetInControlGroup(true);
+  precache_manager_.StartPrecaching(precache_callback_.GetCallback());
+  EXPECT_TRUE(precache_manager_.IsPrecaching());
+
+  precache_manager_.CancelPrecaching();
+  EXPECT_FALSE(precache_manager_.IsPrecaching());
+
+  top_hosts_callback.Run(
+      history::TopHostsList(1, std::make_pair("starting-url.com", 1)));
+  EXPECT_FALSE(precache_manager_.IsPrecaching());
+  EXPECT_FALSE(precache_callback_.was_on_done_called());
+}
+
 TEST_F(PrecacheManagerTest, StartAndCancelPrecachingBeforeURLsReceived) {
   EXPECT_FALSE(precache_manager_.IsPrecaching());
 
diff --git a/components/resources/OWNERS b/components/resources/OWNERS
index fb4812d5..b11d144 100644
--- a/components/resources/OWNERS
+++ b/components/resources/OWNERS
@@ -15,7 +15,6 @@
 per-file version_ui*=bauerb@chromium.org
 per-file version_ui*=dbeam@chromium.org
 per-file version_ui*=estade@chromium.org
-per-file version_ui*=jhawkins@chromium.org
 per-file version_ui*=nkostylev@chromium.org
 per-file version_ui*=pam@chromium.org
 per-file version_ui*=xiyuan@chromium.org
diff --git a/components/ssl_errors/BUILD.gn b/components/ssl_errors/BUILD.gn
index cc1c7ce..2ca78c0 100644
--- a/components/ssl_errors/BUILD.gn
+++ b/components/ssl_errors/BUILD.gn
@@ -22,7 +22,7 @@
 source_set("unit_tests") {
   testonly = true
   sources = [
-    "error_classification_unittests.cc",
+    "error_classification_unittest.cc",
   ]
 
   deps = [
diff --git a/components/update_client/task.h b/components/update_client/task.h
index a6d1f6c..0a5b7f3 100644
--- a/components/update_client/task.h
+++ b/components/update_client/task.h
@@ -26,6 +26,11 @@
 
   virtual void Run() = 0;
 
+  // Does a best effort attempt to make a task release its resources and stop
+  // soon. It is possible that a running task may complete even if this
+  // method is called.
+  virtual void Cancel() = 0;
+
   // Returns the ids corresponding to the CRXs associated with this update task.
   virtual std::vector<std::string> GetIds() const = 0;
 };
diff --git a/components/update_client/task_update.cc b/components/update_client/task_update.cc
index d253466..c6a72e6 100644
--- a/components/update_client/task_update.cc
+++ b/components/update_client/task_update.cc
@@ -8,6 +8,7 @@
 #include "base/location.h"
 #include "base/single_thread_task_runner.h"
 #include "base/thread_task_runner_handle.h"
+#include "components/update_client/update_client.h"
 #include "components/update_client/update_engine.h"
 
 namespace update_client {
@@ -32,23 +33,30 @@
   DCHECK(thread_checker_.CalledOnValidThread());
 
   if (ids_.empty()) {
-    RunComplete(-1);
+    TaskComplete(Error::ERROR_UPDATE_INVALID_ARGUMENT);
     return;
   }
 
   update_engine_->Update(
       is_foreground_, ids_, crx_data_callback_,
-      base::Bind(&TaskUpdate::RunComplete, base::Unretained(this)));
+      base::Bind(&TaskUpdate::TaskComplete, base::Unretained(this)));
+}
+
+void TaskUpdate::Cancel() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  TaskComplete(Error::ERROR_UPDATE_CANCELED);
 }
 
 std::vector<std::string> TaskUpdate::GetIds() const {
   return ids_;
 }
 
-void TaskUpdate::RunComplete(int error) {
+void TaskUpdate::TaskComplete(int error) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
-  callback_.Run(this, error);
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(callback_, this, error));
 }
 
 }  // namespace update_client
diff --git a/components/update_client/task_update.h b/components/update_client/task_update.h
index 3d0963f..aa3ce9d 100644
--- a/components/update_client/task_update.h
+++ b/components/update_client/task_update.h
@@ -40,11 +40,14 @@
 
   void Run() override;
 
+  void Cancel() override;
+
   std::vector<std::string> GetIds() const override;
 
  private:
-  // Called when the Run function associated with this task has completed.
-  void RunComplete(int error);
+  // Called when the task has completed either because the task has run or
+  // it has been canceled.
+  void TaskComplete(int error);
 
   base::ThreadChecker thread_checker_;
 
diff --git a/components/update_client/update_client.cc b/components/update_client/update_client.cc
index ac1ac05..497fedb 100644
--- a/components/update_client/update_client.cc
+++ b/components/update_client/update_client.cc
@@ -68,7 +68,8 @@
     scoped_ptr<PingManager> ping_manager,
     UpdateChecker::Factory update_checker_factory,
     CrxDownloader::Factory crx_downloader_factory)
-    : config_(config),
+    : is_stopped_(false),
+      config_(config),
       ping_manager_(ping_manager.Pass()),
       update_engine_(
           new UpdateEngine(config,
@@ -76,16 +77,13 @@
                            crx_downloader_factory,
                            ping_manager_.get(),
                            base::Bind(&UpdateClientImpl::NotifyObservers,
-                                      base::Unretained(this)))) {
-}
+                                      base::Unretained(this)))) {}
 
 UpdateClientImpl::~UpdateClientImpl() {
   DCHECK(thread_checker_.CalledOnValidThread());
 
-  while (!task_queue_.empty()) {
-    delete task_queue_.front();
-    task_queue_.pop();
-  }
+  DCHECK(task_queue_.empty());
+  DCHECK(tasks_.empty());
 
   config_ = nullptr;
 }
@@ -150,9 +148,17 @@
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(completion_callback, error));
 
+  // Remove the task from the set of the running tasks. Only tasks handled by
+  // the update engine can be in this data structure.
   tasks_.erase(task);
+
+  // Delete the completed task. A task can be completed because the update
+  // engine has run it or because it has been canceled but never run.
   delete task;
 
+  if (is_stopped_)
+    return;
+
   // Pick up a task from the queue if the queue has pending tasks and no other
   // task is running.
   if (tasks_.empty() && !task_queue_.empty()) {
@@ -195,6 +201,31 @@
   return false;
 }
 
+void UpdateClientImpl::Stop() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  is_stopped_ = true;
+
+  // In the current implementation it is sufficient to cancel the pending
+  // tasks only. The tasks that are run by the update engine will stop
+  // making progress naturally, as the main task runner stops running task
+  // actions. Upon the browser shutdown, the resources employed by the active
+  // tasks will leak, as the operating system kills the thread associated with
+  // the update engine task runner. Further refactoring may be needed in this
+  // area, to cancel the running tasks by canceling the current action update.
+  // This behavior would be expected, correct, and result in no resource leaks
+  // in all cases, in shutdown or not.
+  //
+  // Cancel the pending tasks. These tasks are safe to cancel and delete since
+  // they have not picked up by the update engine, and not shared with any
+  // task runner yet.
+  while (!task_queue_.empty()) {
+    const auto task(task_queue_.front());
+    task_queue_.pop();
+    task->Cancel();
+  }
+}
+
 scoped_refptr<UpdateClient> UpdateClientFactory(
     const scoped_refptr<Configurator>& config) {
   scoped_ptr<PingManager> ping_manager(new PingManager(*config));
diff --git a/components/update_client/update_client.h b/components/update_client/update_client.h
index e53b634..f5107d58 100644
--- a/components/update_client/update_client.h
+++ b/components/update_client/update_client.h
@@ -140,7 +140,9 @@
 struct CrxUpdateItem;
 
 enum Error {
+  ERROR_UPDATE_INVALID_ARGUMENT = -1,
   ERROR_UPDATE_IN_PROGRESS = 1,
+  ERROR_UPDATE_CANCELED = 2,
 };
 
 // Defines an interface for a generic CRX installer.
@@ -296,6 +298,12 @@
   // Returns true if the |id| is found in any running task.
   virtual bool IsUpdating(const std::string& id) const = 0;
 
+  // Cancels the queued updates and makes a best effort to stop updates in
+  // progress as soon as possible. Some updates may not be stopped, in which
+  // case, the updates will run to completion. Calling this function has no
+  // effect if updates are not currently executed or queued up.
+  virtual void Stop() = 0;
+
  protected:
   friend class base::RefCounted<UpdateClient>;
 
diff --git a/components/update_client/update_client_internal.h b/components/update_client/update_client_internal.h
index 0dc98be..6a5bf39 100644
--- a/components/update_client/update_client_internal.h
+++ b/components/update_client/update_client_internal.h
@@ -52,6 +52,7 @@
   bool GetCrxUpdateState(const std::string& id,
                          CrxUpdateItem* update_item) const override;
   bool IsUpdating(const std::string& id) const override;
+  void Stop() override;
 
  private:
   ~UpdateClientImpl() override;
@@ -65,12 +66,15 @@
 
   base::ThreadChecker thread_checker_;
 
+  // True is Stop method has been called.
+  bool is_stopped_;
+
   scoped_refptr<Configurator> config_;
 
   // Contains the tasks that are pending. In the current implementation,
   // only update tasks (background tasks) are queued up. These tasks are
-  // pending while they are in this queue. They are not being handled for
-  // the moment.
+  // pending while they are in this queue. They have not been picked up yet
+  // by the update engine.
   std::queue<Task*> task_queue_;
 
   // Contains all tasks in progress. These are the tasks that the update engine
@@ -86,12 +90,6 @@
 
   base::ObserverList<Observer> observer_list_;
 
-  // Used to post responses back to the main thread.
-  scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
-
-  // Used to execute blocking tasks.
-  scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
-
   DISALLOW_COPY_AND_ASSIGN(UpdateClientImpl);
 };
 
diff --git a/components/version_info/OWNERS b/components/version_info/OWNERS
index 3b572a40..d33a4b7d 100644
--- a/components/version_info/OWNERS
+++ b/components/version_info/OWNERS
@@ -1,5 +1,4 @@
 jochen@chromium.org
-jhawkins@chromium.org
 sky@chromium.org
 thakis@chromium.org
 thestig@chromium.org
diff --git a/components/version_ui/OWNERS b/components/version_ui/OWNERS
index da5824440..4298fad 100644
--- a/components/version_ui/OWNERS
+++ b/components/version_ui/OWNERS
@@ -1,7 +1,6 @@
 bauerb@chromium.org
 dbeam@chromium.org
 estade@chromium.org
-jhawkins@chromium.org
 nkostylev@chromium.org
 pam@chromium.org
 xiyuan@chromium.org
diff --git a/components/web_cache/OWNERS b/components/web_cache/OWNERS
index 5948538..3463baf5 100644
--- a/components/web_cache/OWNERS
+++ b/components/web_cache/OWNERS
@@ -1,6 +1,5 @@
 # Reviewers:
 jochen@chromium.org
-jhawkins@chromium.org
 sky@chromium.org
 thakis@chromium.org
 thestig@chromium.org
diff --git a/content/browser/bluetooth/bluetooth_dispatcher_host.cc b/content/browser/bluetooth/bluetooth_dispatcher_host.cc
index e8c9b300..d310f111 100644
--- a/content/browser/bluetooth/bluetooth_dispatcher_host.cc
+++ b/content/browser/bluetooth/bluetooth_dispatcher_host.cc
@@ -269,15 +269,34 @@
 void BluetoothDispatcherHost::SetBluetoothAdapterForTesting(
     scoped_refptr<device::BluetoothAdapter> mock_adapter) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  current_delay_time_ = kTestingDelayTime;
-  devices_with_discovered_services_.clear();
-  // Reset the discovery session timer to use the new delay time.
-  discovery_session_timer_.Start(
-      FROM_HERE, base::TimeDelta::FromSecondsD(current_delay_time_),
-      base::Bind(&BluetoothDispatcherHost::StopDeviceDiscovery,
-                 // base::Timer guarantees it won't call back after its
-                 // destructor starts.
-                 base::Unretained(this)));
+
+  if (mock_adapter.get()) {
+    current_delay_time_ = kTestingDelayTime;
+    // Reset the discovery session timer to use the new delay time.
+    discovery_session_timer_.Start(
+        FROM_HERE, base::TimeDelta::FromSecondsD(current_delay_time_),
+        base::Bind(&BluetoothDispatcherHost::StopDeviceDiscovery,
+                   // base::Timer guarantees it won't call back after its
+                   // destructor starts.
+                   base::Unretained(this)));
+  } else {
+    // The following data structures are used to store pending operations.
+    // They should never contain elements at the end of a test.
+    DCHECK(request_device_sessions_.IsEmpty());
+    DCHECK(pending_primary_services_requests_.empty());
+
+    // The following data structures are cleaned up when a
+    // device/service/characteristic is removed.
+    // Since this can happen after the test is done and the cleanup function is
+    // called, we clean them here.
+    service_to_device_.clear();
+    characteristic_to_service_.clear();
+    characteristic_id_to_notify_session_.clear();
+    active_characteristic_threads_.clear();
+    connections_.clear();
+    devices_with_discovered_services_.clear();
+  }
+
   set_adapter(mock_adapter.Pass());
 }
 
diff --git a/content/browser/devtools/browser_devtools_agent_host.cc b/content/browser/devtools/browser_devtools_agent_host.cc
index d045571..d7c3423 100644
--- a/content/browser/devtools/browser_devtools_agent_host.cc
+++ b/content/browser/devtools/browser_devtools_agent_host.cc
@@ -31,10 +31,7 @@
                                                     tethering_task_runner)),
       tracing_handler_(new devtools::tracing::TracingHandler(
           devtools::tracing::TracingHandler::Browser, GetIOContext())),
-      protocol_handler_(new DevToolsProtocolHandler(
-          this,
-          base::Bind(&BrowserDevToolsAgentHost::SendMessageToClient,
-                     base::Unretained(this)))) {
+      protocol_handler_(new DevToolsProtocolHandler(this)) {
   DevToolsProtocolDispatcher* dispatcher = protocol_handler_->dispatcher();
   dispatcher->SetIOHandler(io_handler_.get());
   dispatcher->SetMemoryHandler(memory_handler_.get());
@@ -74,7 +71,7 @@
 
 bool BrowserDevToolsAgentHost::DispatchProtocolMessage(
     const std::string& message) {
-  protocol_handler_->HandleMessage(message);
+  protocol_handler_->HandleMessage(session_id(), message);
   return true;
 }
 
diff --git a/content/browser/devtools/devtools_agent_host_impl.cc b/content/browser/devtools/devtools_agent_host_impl.cc
index 4d93551..28318e04 100644
--- a/content/browser/devtools/devtools_agent_host_impl.cc
+++ b/content/browser/devtools/devtools_agent_host_impl.cc
@@ -76,8 +76,7 @@
 }
 
 DevToolsAgentHostImpl::DevToolsAgentHostImpl()
-    : id_(base::GenerateGUID()),
-      client_(NULL) {
+    : id_(base::GenerateGUID()), session_id_(0), client_(NULL) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   g_instances.Get()[id_] = this;
 }
@@ -106,6 +105,7 @@
 
 void DevToolsAgentHostImpl::AttachClient(DevToolsAgentHostClient* client) {
   scoped_refptr<DevToolsAgentHostImpl> protect(this);
+  ++session_id_;
   if (client_) {
     client_->AgentHostClosed(this, true);
     InnerDetach();
@@ -153,6 +153,16 @@
 void DevToolsAgentHostImpl::ConnectWebContents(WebContents* wc) {
 }
 
+void DevToolsAgentHostImpl::SendProtocolResponse(int session_id,
+                                                 const std::string& message) {
+  SendMessageToClient(session_id, message);
+}
+
+void DevToolsAgentHostImpl::SendProtocolNotification(
+    const std::string& message) {
+  SendMessageToClient(session_id(), message);
+}
+
 void DevToolsAgentHostImpl::HostClosed() {
   if (!client_)
     return;
@@ -164,9 +174,13 @@
   client->AgentHostClosed(this, false);
 }
 
-void DevToolsAgentHostImpl::SendMessageToClient(const std::string& message) {
+void DevToolsAgentHostImpl::SendMessageToClient(int session_id,
+                                                const std::string& message) {
   if (!client_)
     return;
+  // Filter any messages from previous sessions.
+  if (session_id != session_id_)
+    return;
   client_->DispatchProtocolMessage(this, message);
 }
 
@@ -249,7 +263,7 @@
 
   if (chunk.is_first && chunk.is_last) {
     CHECK(message_buffer_size_ == 0);
-    callback_.Run(chunk.data);
+    callback_.Run(chunk.session_id, chunk.data);
     return;
   }
 
@@ -265,7 +279,7 @@
 
   if (chunk.is_last) {
     CHECK(message_buffer_.size() == message_buffer_size_);
-    callback_.Run(message_buffer_);
+    callback_.Run(chunk.session_id, message_buffer_);
     message_buffer_ = std::string();
     message_buffer_size_ = 0;
   }
diff --git a/content/browser/devtools/devtools_agent_host_impl.h b/content/browser/devtools/devtools_agent_host_impl.h
index 8474c0a..3d27cd7 100644
--- a/content/browser/devtools/devtools_agent_host_impl.h
+++ b/content/browser/devtools/devtools_agent_host_impl.h
@@ -9,6 +9,7 @@
 
 #include "base/compiler_specific.h"
 #include "content/browser/devtools/devtools_io_context.h"
+#include "content/browser/devtools/protocol/devtools_protocol_delegate.h"
 #include "content/common/content_export.h"
 #include "content/common/devtools_messages.h"
 #include "content/public/browser/devtools_agent_host.h"
@@ -22,7 +23,8 @@
 class BrowserContext;
 
 // Describes interface for managing devtools agents from the browser process.
-class CONTENT_EXPORT DevToolsAgentHostImpl : public DevToolsAgentHost {
+class CONTENT_EXPORT DevToolsAgentHostImpl : public DevToolsAgentHost,
+                                             public DevToolsProtocolDelegate {
  public:
   // Informs the hosted agent that a client host has attached.
   virtual void Attach() = 0;
@@ -44,14 +46,21 @@
   void DisconnectWebContents() override;
   void ConnectWebContents(WebContents* wc) override;
 
+  // DevToolsProtocolDelegate implementation.
+  void SendProtocolResponse(int session_id,
+                            const std::string& message) override;
+  void SendProtocolNotification(const std::string& message) override;
+
  protected:
   DevToolsAgentHostImpl();
   ~DevToolsAgentHostImpl() override;
 
   void HostClosed();
-  void SendMessageToClient(const std::string& message);
+  void SendMessageToClient(int session_id, const std::string& message);
   devtools::DevToolsIOContext* GetIOContext() { return &io_context_; }
 
+  int session_id() { return session_id_; }
+
   static void NotifyCallbacks(DevToolsAgentHostImpl* agent_host, bool attached);
 
  private:
@@ -59,13 +68,14 @@
   void InnerDetach();
 
   const std::string id_;
+  int session_id_;
   DevToolsAgentHostClient* client_;
   devtools::DevToolsIOContext io_context_;
 };
 
 class DevToolsMessageChunkProcessor {
  public:
-  using SendMessageCallback = base::Callback<void(const std::string&)>;
+  using SendMessageCallback = base::Callback<void(int, const std::string&)>;
   explicit DevToolsMessageChunkProcessor(const SendMessageCallback& callback);
   ~DevToolsMessageChunkProcessor();
 
diff --git a/content/browser/devtools/devtools_protocol_handler.cc b/content/browser/devtools/devtools_protocol_handler.cc
index 86ccd8e..9f69cfb 100644
--- a/content/browser/devtools/devtools_protocol_handler.cc
+++ b/content/browser/devtools/devtools_protocol_handler.cc
@@ -7,6 +7,7 @@
 #include "base/bind.h"
 #include "base/json/json_reader.h"
 #include "base/json/json_writer.h"
+#include "content/browser/devtools/devtools_agent_host_impl.h"
 #include "content/browser/devtools/devtools_manager.h"
 #include "content/public/browser/devtools_manager_delegate.h"
 
@@ -36,35 +37,35 @@
 }  // namespace
 
 DevToolsProtocolHandler::DevToolsProtocolHandler(
-    DevToolsAgentHost* agent_host, const Notifier& notifier)
-    : agent_host_(agent_host),
-      client_(notifier),
-      dispatcher_(notifier) {
-}
+    DevToolsAgentHostImpl* agent_host)
+    : agent_host_(agent_host), client_(agent_host), dispatcher_(agent_host) {}
 
 DevToolsProtocolHandler::~DevToolsProtocolHandler() {
 }
 
-void DevToolsProtocolHandler::HandleMessage(const std::string& message) {
-  scoped_ptr<base::DictionaryValue> command = ParseCommand(message);
+void DevToolsProtocolHandler::HandleMessage(int session_id,
+                                            const std::string& message) {
+  scoped_ptr<base::DictionaryValue> command = ParseCommand(session_id, message);
   if (!command)
     return;
-  if (PassCommandToDelegate(command.get()))
+  if (PassCommandToDelegate(session_id, command.get()))
     return;
-  HandleCommand(command.Pass());
+  HandleCommand(session_id, command.Pass());
 }
 
-bool DevToolsProtocolHandler::HandleOptionalMessage(
-    const std::string& message, int* call_id) {
-  scoped_ptr<base::DictionaryValue> command = ParseCommand(message);
+bool DevToolsProtocolHandler::HandleOptionalMessage(int session_id,
+                                                    const std::string& message,
+                                                    int* call_id) {
+  scoped_ptr<base::DictionaryValue> command = ParseCommand(session_id, message);
   if (!command)
     return true;
-  if (PassCommandToDelegate(command.get()))
+  if (PassCommandToDelegate(session_id, command.get()))
     return true;
-  return HandleOptionalCommand(command.Pass(), call_id);
+  return HandleOptionalCommand(session_id, command.Pass(), call_id);
 }
 
 bool DevToolsProtocolHandler::PassCommandToDelegate(
+    int session_id,
     base::DictionaryValue* command) {
   DevToolsManagerDelegate* delegate =
       DevToolsManager::GetInstance()->delegate();
@@ -74,41 +75,41 @@
   scoped_ptr<base::DictionaryValue> response(
       delegate->HandleCommand(agent_host_, command));
   if (response) {
-    std::string json_response;
-    base::JSONWriter::Write(*response, &json_response);
-    client_.SendRawMessage(json_response);
+    client_.SendMessage(session_id, *response);
     return true;
   }
 
   return false;
 }
 
-scoped_ptr<base::DictionaryValue>
-DevToolsProtocolHandler::ParseCommand(const std::string& message) {
+scoped_ptr<base::DictionaryValue> DevToolsProtocolHandler::ParseCommand(
+    int session_id,
+    const std::string& message) {
   scoped_ptr<base::Value> value = base::JSONReader::Read(message);
   if (!value || !value->IsType(base::Value::TYPE_DICTIONARY)) {
-    client_.SendError(DevToolsProtocolClient::kNoId,
-                      Response(kStatusParseError,
-                               "Message must be in JSON format"));
+    client_.SendError(
+        DevToolsCommandId(DevToolsCommandId::kNoId, session_id),
+        Response(kStatusParseError, "Message must be in JSON format"));
     return nullptr;
   }
 
   scoped_ptr<base::DictionaryValue> command =
       make_scoped_ptr(static_cast<base::DictionaryValue*>(value.release()));
-  int id = DevToolsProtocolClient::kNoId;
-  bool ok = command->GetInteger(kIdParam, &id) && id >= 0;
+  int call_id = DevToolsCommandId::kNoId;
+  bool ok = command->GetInteger(kIdParam, &call_id) && call_id >= 0;
   if (!ok) {
-    client_.SendError(id, Response(kStatusInvalidRequest,
-                                   "The type of 'id' property must be number"));
+    client_.SendError(DevToolsCommandId(call_id, session_id),
+                      Response(kStatusInvalidRequest,
+                               "The type of 'id' property must be number"));
     return nullptr;
   }
 
   std::string method;
   ok = command->GetString(kMethodParam, &method);
   if (!ok) {
-    client_.SendError(id,
-        Response(kStatusInvalidRequest,
-                 "The type of 'method' property must be string"));
+    client_.SendError(DevToolsCommandId(call_id, session_id),
+                      Response(kStatusInvalidRequest,
+                               "The type of 'method' property must be string"));
     return nullptr;
   }
 
@@ -116,34 +117,39 @@
 }
 
 void DevToolsProtocolHandler::HandleCommand(
+    int session_id,
     scoped_ptr<base::DictionaryValue> command) {
-  int id = DevToolsProtocolClient::kNoId;
+  int call_id = DevToolsCommandId::kNoId;
   std::string method;
-  command->GetInteger(kIdParam, &id);
+  command->GetInteger(kIdParam, &call_id);
   command->GetString(kMethodParam, &method);
   DevToolsProtocolDispatcher::CommandHandler command_handler(
       dispatcher_.FindCommandHandler(method));
   if (command_handler.is_null()) {
-    client_.SendError(id, Response(kStatusNoSuchMethod, "No such method"));
+    client_.SendError(DevToolsCommandId(call_id, session_id),
+                      Response(kStatusNoSuchMethod, "No such method"));
     return;
   }
 
   bool result =
-      command_handler.Run(id, TakeDictionary(command.get(), kParamsParam));
+      command_handler.Run(DevToolsCommandId(call_id, session_id),
+                          TakeDictionary(command.get(), kParamsParam));
   DCHECK(result);
 }
 
 bool DevToolsProtocolHandler::HandleOptionalCommand(
-    scoped_ptr<base::DictionaryValue> command, int* call_id) {
-  *call_id = DevToolsProtocolClient::kNoId;
+    int session_id,
+    scoped_ptr<base::DictionaryValue> command,
+    int* call_id) {
+  *call_id = DevToolsCommandId::kNoId;
   std::string method;
   command->GetInteger(kIdParam, call_id);
   command->GetString(kMethodParam, &method);
   DevToolsProtocolDispatcher::CommandHandler command_handler(
       dispatcher_.FindCommandHandler(method));
   if (!command_handler.is_null()) {
-    return command_handler.Run(
-        *call_id, TakeDictionary(command.get(), kParamsParam));
+    return command_handler.Run(DevToolsCommandId(*call_id, session_id),
+                               TakeDictionary(command.get(), kParamsParam));
   }
   return false;
 }
diff --git a/content/browser/devtools/devtools_protocol_handler.h b/content/browser/devtools/devtools_protocol_handler.h
index 299b342..32f4928 100644
--- a/content/browser/devtools/devtools_protocol_handler.h
+++ b/content/browser/devtools/devtools_protocol_handler.h
@@ -10,26 +10,30 @@
 namespace content {
 
 class DevToolsAgentHost;
+class DevToolsAgentHostImpl;
+class DevToolsProtocolDelegate;
 
 class DevToolsProtocolHandler {
  public:
   using Response = DevToolsProtocolClient::Response;
-  using Notifier = base::Callback<void(const std::string& message)>;
 
-  DevToolsProtocolHandler(DevToolsAgentHost* agent_host,
-                          const Notifier& notifier);
+  explicit DevToolsProtocolHandler(DevToolsAgentHostImpl* agent_host);
   virtual ~DevToolsProtocolHandler();
 
-  void HandleMessage(const std::string& message);
-  bool HandleOptionalMessage(const std::string& message, int* call_id);
+  void HandleMessage(int session_id, const std::string& message);
+  bool HandleOptionalMessage(int session_id,
+                             const std::string& message,
+                             int* call_id);
 
   DevToolsProtocolDispatcher* dispatcher() { return &dispatcher_; }
 
  private:
-  scoped_ptr<base::DictionaryValue> ParseCommand(const std::string& message);
-  bool PassCommandToDelegate(base::DictionaryValue* command);
-  void HandleCommand(scoped_ptr<base::DictionaryValue> command);
-  bool HandleOptionalCommand(scoped_ptr<base::DictionaryValue> command,
+  scoped_ptr<base::DictionaryValue> ParseCommand(int session_id,
+                                                 const std::string& message);
+  bool PassCommandToDelegate(int session_id, base::DictionaryValue* command);
+  void HandleCommand(int session_id, scoped_ptr<base::DictionaryValue> command);
+  bool HandleOptionalCommand(int session_id,
+                             scoped_ptr<base::DictionaryValue> command,
                              int* call_id);
 
   DevToolsAgentHost* agent_host_;
diff --git a/content/browser/devtools/forwarding_agent_host.cc b/content/browser/devtools/forwarding_agent_host.cc
index ef7f82c..b8b8c2f8 100644
--- a/content/browser/devtools/forwarding_agent_host.cc
+++ b/content/browser/devtools/forwarding_agent_host.cc
@@ -18,7 +18,7 @@
 }
 
 void ForwardingAgentHost::DispatchOnClientHost(const std::string& message) {
-  SendMessageToClient(message);
+  SendMessageToClient(session_id(), message);
 }
 
 void ForwardingAgentHost::ConnectionClosed() {
diff --git a/content/browser/devtools/protocol/devtools_protocol_client.cc b/content/browser/devtools/protocol/devtools_protocol_client.cc
index 4b7c25d..9ca03f9d 100644
--- a/content/browser/devtools/protocol/devtools_protocol_client.cc
+++ b/content/browser/devtools/protocol/devtools_protocol_client.cc
@@ -6,6 +6,7 @@
 
 #include "base/json/json_writer.h"
 #include "base/strings/stringprintf.h"
+#include "content/browser/devtools/protocol/devtools_protocol_delegate.h"
 
 namespace content {
 
@@ -30,24 +31,24 @@
 }  // namespace
 
 // static
-const DevToolsCommandId DevToolsProtocolClient::kNoId = -1;
+const int DevToolsCommandId::kNoId = -1;
 
 DevToolsProtocolClient::DevToolsProtocolClient(
-    const RawMessageCallback& raw_message_callback)
-    : raw_message_callback_(raw_message_callback) {
-}
+    DevToolsProtocolDelegate* notifier)
+    : notifier_(notifier) {}
 
 DevToolsProtocolClient::~DevToolsProtocolClient() {
 }
 
-void DevToolsProtocolClient::SendRawMessage(const std::string& message) {
-  raw_message_callback_.Run(message);
+void DevToolsProtocolClient::SendRawNotification(const std::string& message) {
+  notifier_->SendProtocolNotification(message);
 }
 
-void DevToolsProtocolClient::SendMessage(const base::DictionaryValue& message) {
+void DevToolsProtocolClient::SendMessage(int session_id,
+                                         const base::DictionaryValue& message) {
   std::string json_message;
   base::JSONWriter::Write(message, &json_message);
-  SendRawMessage(json_message);
+  notifier_->SendProtocolResponse(session_id, json_message);
 }
 
 void DevToolsProtocolClient::SendNotification(
@@ -58,19 +59,21 @@
   if (params)
     notification.Set(kParamsParam, params.release());
 
-  SendMessage(notification);
+  std::string json_message;
+  base::JSONWriter::Write(notification, &json_message);
+  SendRawNotification(json_message);
 }
 
 void DevToolsProtocolClient::SendSuccess(
     DevToolsCommandId command_id,
     scoped_ptr<base::DictionaryValue> params) {
   base::DictionaryValue response;
-  response.SetInteger(kIdParam, command_id);
+  response.SetInteger(kIdParam, command_id.call_id);
 
   response.Set(kResultParam,
       params ? params.release() : new base::DictionaryValue());
 
-  SendMessage(response);
+  SendMessage(command_id.session_id, response);
 }
 
 bool DevToolsProtocolClient::SendError(DevToolsCommandId command_id,
@@ -80,10 +83,10 @@
     return false;
   }
   base::DictionaryValue dict;
-  if (command_id == kNoId)
+  if (command_id.call_id == DevToolsCommandId::kNoId)
     dict.Set(kIdParam, base::Value::CreateNullValue());
   else
-    dict.SetInteger(kIdParam, command_id);
+    dict.SetInteger(kIdParam, command_id.call_id);
 
   base::DictionaryValue* error_object = new base::DictionaryValue();
   error_object->SetInteger(kErrorCodeParam, response.status());
@@ -91,7 +94,7 @@
     error_object->SetString(kErrorMessageParam, response.message());
 
   dict.Set(kErrorParam, error_object);
-  SendMessage(dict);
+  SendMessage(command_id.session_id, dict);
   return true;
 }
 
diff --git a/content/browser/devtools/protocol/devtools_protocol_client.h b/content/browser/devtools/protocol/devtools_protocol_client.h
index 9297187..780bc74 100644
--- a/content/browser/devtools/protocol/devtools_protocol_client.h
+++ b/content/browser/devtools/protocol/devtools_protocol_client.h
@@ -10,16 +10,22 @@
 
 namespace content {
 
-using DevToolsCommandId = int;
-class DevToolsProtocolHandler;
+struct DevToolsCommandId {
+  static const int kNoId;
+
+  DevToolsCommandId(int call_id, int session_id)
+      : call_id(call_id), session_id(session_id) {}
+
+  int call_id;
+  int session_id;
+};
+
+class DevToolsProtocolDelegate;
 class DevToolsProtocolDispatcher;
+class DevToolsProtocolHandler;
 
 class DevToolsProtocolClient {
  public:
-  typedef base::Callback<void(const std::string& message)>
-      RawMessageCallback;
-  static const DevToolsCommandId kNoId;
-
   struct Response {
    public:
     static Response FallThrough();
@@ -46,12 +52,13 @@
   bool SendError(DevToolsCommandId command_id,
                  const Response& response);
 
-  // Sends message to client, the caller is presumed to properly
+  // Sends notification to client, the caller is presumed to properly
   // format the message. Do not use unless you must.
-  void SendRawMessage(const std::string& message);
+  void SendRawNotification(const std::string& message);
 
-  explicit DevToolsProtocolClient(
-      const RawMessageCallback& raw_message_callback);
+  void SendMessage(int session_id, const base::DictionaryValue& message);
+
+  explicit DevToolsProtocolClient(DevToolsProtocolDelegate* notifier);
   virtual ~DevToolsProtocolClient();
 
  protected:
@@ -63,9 +70,7 @@
  private:
   friend class DevToolsProtocolDispatcher;
 
-  void SendMessage(const base::DictionaryValue& message);
-
-  RawMessageCallback raw_message_callback_;
+  DevToolsProtocolDelegate* notifier_;
   DISALLOW_COPY_AND_ASSIGN(DevToolsProtocolClient);
 };
 
diff --git a/content/browser/devtools/protocol/devtools_protocol_delegate.h b/content/browser/devtools/protocol/devtools_protocol_delegate.h
new file mode 100644
index 0000000..20c476bd
--- /dev/null
+++ b/content/browser/devtools/protocol/devtools_protocol_delegate.h
@@ -0,0 +1,22 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_DEVTOOLS_PROTOCOL_DEVTOOLS_PROTOCOL_DELEGATE_H_
+#define CONTENT_BROWSER_DEVTOOLS_PROTOCOL_DEVTOOLS_PROTOCOL_DELEGATE_H_
+
+#include "content/common/content_export.h"
+
+namespace content {
+
+class CONTENT_EXPORT DevToolsProtocolDelegate {
+public:
+  virtual ~DevToolsProtocolDelegate(){}
+  virtual void SendProtocolResponse(int session_id,
+                                    const std::string& message) = 0;
+  virtual void SendProtocolNotification(const std::string& message) = 0;
+};
+
+} // content
+
+#endif // CONTENT_BROWSER_DEVTOOLS_PROTOCOL_DEVTOOLS_PROTOCOL_DELEGATE_H_
diff --git a/content/browser/devtools/protocol/devtools_protocol_handler_generator.py b/content/browser/devtools/protocol/devtools_protocol_handler_generator.py
index 6bce71e..6377be6f 100755
--- a/content/browser/devtools/protocol/devtools_protocol_handler_generator.py
+++ b/content/browser/devtools/protocol/devtools_protocol_handler_generator.py
@@ -74,11 +74,11 @@
 
 class DevToolsProtocolDispatcher {
  public:
-  using Notifier = DevToolsProtocolClient::RawMessageCallback;
   using CommandHandler =
-      base::Callback<bool(int, scoped_ptr<base::DictionaryValue>)>;
+      base::Callback<bool(DevToolsCommandId,
+                          scoped_ptr<base::DictionaryValue>)>;
 
-  explicit DevToolsProtocolDispatcher(const Notifier& notifier);
+  explicit DevToolsProtocolDispatcher(DevToolsProtocolDelegate* notifier);
   ~DevToolsProtocolDispatcher();
 
   CommandHandler FindCommandHandler(const std::string& method);
@@ -91,7 +91,7 @@
 
 ${methods}\
 
-  Notifier notifier_;
+  DevToolsProtocolDelegate* notifier_;
   DevToolsProtocolClient client_;
   CommandHandlers command_handlers_;
 ${fields}\
@@ -208,7 +208,7 @@
 namespace ${domain} {
 class Client : public DevToolsProtocolClient {
  public:
-  explicit Client(const RawMessageCallback& raw_message_callback);
+  explicit Client(DevToolsProtocolDelegate* notifier);
   ~Client() override;
 
 ${methods}\
@@ -252,7 +252,7 @@
 namespace content {
 
 DevToolsProtocolDispatcher::DevToolsProtocolDispatcher(
-    const Notifier& notifier)
+    DevToolsProtocolDelegate* notifier)
     : notifier_(notifier),
       client_(notifier),
       ${fields_init} {
@@ -405,8 +405,8 @@
 tmpl_client_impl = string.Template("""\
 namespace ${domain} {
 
-Client::Client(const RawMessageCallback& raw_message_callback)
-    : DevToolsProtocolClient(raw_message_callback) {
+Client::Client(DevToolsProtocolDelegate* notifier)
+    : DevToolsProtocolClient(notifier) {
 }
 
 Client::~Client() {
diff --git a/content/browser/devtools/protocol/input_handler.cc b/content/browser/devtools/protocol/input_handler.cc
index 0b4bdcc3..c0def4e4 100644
--- a/content/browser/devtools/protocol/input_handler.cc
+++ b/content/browser/devtools/protocol/input_handler.cc
@@ -398,8 +398,8 @@
     DevToolsCommandId command_id) {
   if (!interaction_marker_name.empty()) {
     // TODO(alexclarke): Can we move this elsewhere? It doesn't really fit here.
-    TRACE_EVENT_COPY_ASYNC_BEGIN0("benchmark",
-                                  interaction_marker_name.c_str(), command_id);
+    TRACE_EVENT_COPY_ASYNC_BEGIN0("benchmark", interaction_marker_name.c_str(),
+                                  command_id.call_id);
   }
 
   host_->QueueSyntheticGesture(
@@ -417,8 +417,8 @@
     DevToolsCommandId command_id,
     SyntheticGesture::Result result) {
   if (!interaction_marker_name.empty()) {
-    TRACE_EVENT_COPY_ASYNC_END0("benchmark",
-                                interaction_marker_name.c_str(), command_id);
+    TRACE_EVENT_COPY_ASYNC_END0("benchmark", interaction_marker_name.c_str(),
+                                command_id.call_id);
   }
 
   if (repeat_count > 0) {
diff --git a/content/browser/devtools/protocol/tracing_handler.cc b/content/browser/devtools/protocol/tracing_handler.cc
index 3518ed5..2428041 100644
--- a/content/browser/devtools/protocol/tracing_handler.cc
+++ b/content/browser/devtools/protocol/tracing_handler.cc
@@ -113,7 +113,7 @@
   message.reserve(message.size() + trace_fragment.size() + messageSuffixSize);
   message += trace_fragment;
   message += "] } }";
-  client_->SendRawMessage(message);
+  client_->SendRawNotification(message);
 }
 
 void TracingHandler::OnTraceComplete() {
diff --git a/content/browser/devtools/render_frame_devtools_agent_host.cc b/content/browser/devtools/render_frame_devtools_agent_host.cc
index fb191fb..71ab308 100644
--- a/content/browser/devtools/render_frame_devtools_agent_host.cc
+++ b/content/browser/devtools/render_frame_devtools_agent_host.cc
@@ -86,7 +86,9 @@
   void Attach();
   void Reattach(FrameHostHolder* old);
   void Detach();
-  void DispatchProtocolMessage(int call_id, const std::string& message);
+  void DispatchProtocolMessage(int session_id,
+                               int call_id,
+                               const std::string& message);
   void InspectElement(int x, int y);
   void ProcessChunkedMessageFromAgent(const DevToolsMessageChunk& chunk);
   void Suspend();
@@ -95,15 +97,17 @@
  private:
   void GrantPolicy();
   void RevokePolicy();
-  void SendMessageToClient(const std::string& message);
+  void SendMessageToClient(int session_id, const std::string& message);
 
   RenderFrameDevToolsAgentHost* agent_;
   RenderFrameHostImpl* host_;
   bool attached_;
   bool suspended_;
   DevToolsMessageChunkProcessor chunk_processor_;
-  std::vector<std::string> pending_messages_;
-  std::map<int, std::string> sent_messages_;
+  // <session_id, message>
+  std::vector<std::pair<int, std::string>> pending_messages_;
+  // <call_id> -> <session_id, message>
+  std::map<int, std::pair<int, std::string>> sent_messages_;
 };
 
 RenderFrameDevToolsAgentHost::FrameHostHolder::FrameHostHolder(
@@ -126,7 +130,7 @@
 
 void RenderFrameDevToolsAgentHost::FrameHostHolder::Attach() {
   host_->Send(new DevToolsAgentMsg_Attach(
-      host_->GetRoutingID(), agent_->GetId()));
+      host_->GetRoutingID(), agent_->GetId(), agent_->session_id()));
   GrantPolicy();
   attached_ = true;
 }
@@ -136,10 +140,13 @@
   if (old)
     chunk_processor_.set_state_cookie(old->chunk_processor_.state_cookie());
   host_->Send(new DevToolsAgentMsg_Reattach(
-      host_->GetRoutingID(), agent_->GetId(), chunk_processor_.state_cookie()));
+      host_->GetRoutingID(), agent_->GetId(), agent_->session_id(),
+      chunk_processor_.state_cookie()));
   if (old) {
-    for (const auto& pair : old->sent_messages_)
-      DispatchProtocolMessage(pair.first, pair.second);
+    for (const auto& pair : old->sent_messages_) {
+      DispatchProtocolMessage(pair.second.first, pair.first,
+                              pair.second.second);
+    }
   }
   GrantPolicy();
   attached_ = true;
@@ -179,16 +186,18 @@
   }
 }
 void RenderFrameDevToolsAgentHost::FrameHostHolder::DispatchProtocolMessage(
-    int call_id, const std::string& message) {
+    int session_id,
+    int call_id,
+    const std::string& message) {
   host_->Send(new DevToolsAgentMsg_DispatchOnInspectorBackend(
-      host_->GetRoutingID(), message));
-  sent_messages_[call_id] = message;
+      host_->GetRoutingID(), session_id, message));
+  sent_messages_[call_id] = std::make_pair(session_id, message);
 }
 
 void RenderFrameDevToolsAgentHost::FrameHostHolder::InspectElement(
     int x, int y) {
   host_->Send(new DevToolsAgentMsg_InspectElement(
-      host_->GetRoutingID(), agent_->GetId(), x, y));
+      host_->GetRoutingID(), agent_->GetId(), agent_->session_id(), x, y));
 }
 
 void
@@ -198,12 +207,13 @@
 }
 
 void RenderFrameDevToolsAgentHost::FrameHostHolder::SendMessageToClient(
+    int session_id,
     const std::string& message) {
   sent_messages_.erase(chunk_processor_.last_call_id());
   if (suspended_)
-    pending_messages_.push_back(message);
+    pending_messages_.push_back(std::make_pair(session_id, message));
   else
-    agent_->SendMessageToClient(message);
+    agent_->SendMessageToClient(session_id, message);
 }
 
 void RenderFrameDevToolsAgentHost::FrameHostHolder::Suspend() {
@@ -212,9 +222,9 @@
 
 void RenderFrameDevToolsAgentHost::FrameHostHolder::Resume() {
   suspended_ = false;
-  for (const std::string& message : pending_messages_)
-    agent_->SendMessageToClient(message);
-  std::vector<std::string> empty;
+  for (const auto& pair : pending_messages_)
+    agent_->SendMessageToClient(pair.first, pair.second);
+  std::vector<std::pair<int, std::string>> empty;
   pending_messages_.swap(empty);
 }
 
@@ -325,10 +335,7 @@
           GetIOContext())),
       emulation_handler_(nullptr),
       frame_trace_recorder_(nullptr),
-      protocol_handler_(new DevToolsProtocolHandler(
-          this,
-          base::Bind(&RenderFrameDevToolsAgentHost::SendMessageToClient,
-                     base::Unretained(this)))),
+      protocol_handler_(new DevToolsProtocolHandler(this)),
       current_frame_crashed_(false) {
   DevToolsProtocolDispatcher* dispatcher = protocol_handler_->dispatcher();
   dispatcher->SetDOMHandler(dom_handler_.get());
@@ -423,13 +430,13 @@
 bool RenderFrameDevToolsAgentHost::DispatchProtocolMessage(
     const std::string& message) {
   int call_id = 0;
-  if (protocol_handler_->HandleOptionalMessage(message, &call_id))
+  if (protocol_handler_->HandleOptionalMessage(session_id(), message, &call_id))
     return true;
 
   if (current_)
-    current_->DispatchProtocolMessage(call_id, message);
+    current_->DispatchProtocolMessage(session_id(), call_id, message);
   if (pending_)
-    pending_->DispatchProtocolMessage(call_id, message);
+    pending_->DispatchProtocolMessage(session_id(), call_id, message);
   return true;
 }
 
diff --git a/content/browser/devtools/worker_devtools_agent_host.cc b/content/browser/devtools/worker_devtools_agent_host.cc
index 32cd668e..d7be60a 100644
--- a/content/browser/devtools/worker_devtools_agent_host.cc
+++ b/content/browser/devtools/worker_devtools_agent_host.cc
@@ -21,7 +21,8 @@
     AttachToWorker();
   }
   if (RenderProcessHost* host = RenderProcessHost::FromID(worker_id_.first))
-    host->Send(new DevToolsAgentMsg_Attach(worker_id_.second, GetId()));
+    host->Send(
+        new DevToolsAgentMsg_Attach(worker_id_.second, GetId(), session_id()));
   OnAttachedStateChanged(true);
   DevToolsAgentHostImpl::NotifyCallbacks(this, true);
 }
@@ -45,12 +46,12 @@
     return true;
 
   int call_id;
-  if (protocol_handler_->HandleOptionalMessage(message, &call_id))
+  if (protocol_handler_->HandleOptionalMessage(session_id(), message, &call_id))
     return true;
 
   if (RenderProcessHost* host = RenderProcessHost::FromID(worker_id_.first)) {
     host->Send(new DevToolsAgentMsg_DispatchOnInspectorBackend(
-        worker_id_.second, message));
+        worker_id_.second, session_id(), message));
   }
   return true;
 }
@@ -83,7 +84,8 @@
     AttachToWorker();
     if (RenderProcessHost* host = RenderProcessHost::FromID(worker_id_.first)) {
       host->Send(new DevToolsAgentMsg_Reattach(
-          worker_id_.second, GetId(), chunk_processor_.state_cookie()));
+          worker_id_.second, GetId(), session_id(),
+          chunk_processor_.state_cookie()));
     }
     OnAttachedStateChanged(true);
   }
@@ -101,10 +103,7 @@
   if (state_ == WORKER_INSPECTED) {
     DCHECK(IsAttached());
     // Client host is debugging this worker agent host.
-    base::Callback<void(const std::string&)> raw_message_callback(
-        base::Bind(&WorkerDevToolsAgentHost::SendMessageToClient,
-                base::Unretained(this)));
-    devtools::inspector::Client inspector(raw_message_callback);
+    devtools::inspector::Client inspector(this);
     inspector.TargetCrashed(
         devtools::inspector::TargetCrashedParams::Create());
     DetachFromWorker();
@@ -117,15 +116,10 @@
   return state_ == WORKER_TERMINATED;
 }
 
-WorkerDevToolsAgentHost::WorkerDevToolsAgentHost(
-    WorkerId worker_id)
-    : protocol_handler_(new DevToolsProtocolHandler(
-          this,
-          base::Bind(&WorkerDevToolsAgentHost::SendMessageToClient,
-                     base::Unretained(this)))),
-      chunk_processor_(
-          base::Bind(&WorkerDevToolsAgentHost::SendMessageToClient,
-                     base::Unretained(this))),
+WorkerDevToolsAgentHost::WorkerDevToolsAgentHost(WorkerId worker_id)
+    : protocol_handler_(new DevToolsProtocolHandler(this)),
+      chunk_processor_(base::Bind(&WorkerDevToolsAgentHost::SendMessageToClient,
+                                  base::Unretained(this))),
       state_(WORKER_UNINSPECTED),
       worker_id_(worker_id) {
   WorkerCreated();
diff --git a/content/browser/download/base_file_posix.cc b/content/browser/download/base_file_posix.cc
index b5d8e01..471fb93 100644
--- a/content/browser/download/base_file_posix.cc
+++ b/content/browser/download/base_file_posix.cc
@@ -4,6 +4,8 @@
 
 #include "content/browser/download/base_file.h"
 
+#include <errno.h>
+
 #include "base/files/file_util.h"
 #include "content/public/browser/download_interrupt_reasons.h"
 
diff --git a/content/browser/indexed_db/leveldb/leveldb_transaction.cc b/content/browser/indexed_db/leveldb/leveldb_transaction.cc
index 0878f0b..11a77c6 100644
--- a/content/browser/indexed_db/leveldb/leveldb_transaction.cc
+++ b/content/browser/indexed_db/leveldb/leveldb_transaction.cc
@@ -99,8 +99,8 @@
   base::TimeTicks begin_time = base::TimeTicks::Now();
   scoped_ptr<LevelDBWriteBatch> write_batch = LevelDBWriteBatch::Create();
 
-  auto it = data_.begin(), end = data_.end();
-  while (it != end) {
+  auto it = data_.begin();
+  while (it != data_.end()) {
     if (!it->second->deleted)
       write_batch->Put(it->first, it->second->value);
     else
diff --git a/content/browser/presentation/presentation_service_impl.cc b/content/browser/presentation/presentation_service_impl.cc
index dd5203dc..5d20a31 100644
--- a/content/browser/presentation/presentation_service_impl.cc
+++ b/content/browser/presentation/presentation_service_impl.cc
@@ -224,13 +224,6 @@
   screen_availability_listeners_.erase(listener_it);
 }
 
-void PresentationServiceImpl::ListenForDefaultSessionStart(
-    const DefaultSessionMojoCallback& callback) {
-  if (!default_session_start_context_.get())
-    default_session_start_context_.reset(new DefaultSessionStartContext);
-  default_session_start_context_->AddCallback(callback);
-}
-
 void PresentationServiceImpl::StartSession(
     const mojo::String& presentation_url,
     const NewSessionMojoCallback& callback) {
@@ -368,11 +361,12 @@
   const std::string& new_default_url = url.get();
   if (default_presentation_url_ == new_default_url)
     return;
-  delegate_->SetDefaultPresentationUrl(
-      render_process_id_,
-      render_frame_id_,
-      new_default_url);
+
   default_presentation_url_ = new_default_url;
+  delegate_->SetDefaultPresentationUrl(
+      render_process_id_, render_frame_id_, new_default_url,
+      base::Bind(&PresentationServiceImpl::OnDefaultPresentationStarted,
+                 weak_factory_.GetWeakPtr()));
 }
 
 void PresentationServiceImpl::SendSessionMessage(
@@ -521,8 +515,6 @@
 
   pending_join_session_cbs_.clear();
 
-  default_session_start_context_.reset();
-
   if (on_session_messages_callback_.get()) {
     on_session_messages_callback_->Run(
         mojo::Array<presentation::SessionMessagePtr>());
@@ -544,9 +536,10 @@
 }
 
 void PresentationServiceImpl::OnDefaultPresentationStarted(
-    const PresentationSessionInfo& session) {
-  if (default_session_start_context_.get())
-    default_session_start_context_->set_session(session);
+    const PresentationSessionInfo& session_info) {
+  DCHECK(client_.get());
+  client_->OnDefaultSessionStarted(
+      presentation::PresentationSessionInfo::From(session_info));
 }
 
 PresentationServiceImpl::ScreenAvailabilityListenerImpl
@@ -597,45 +590,4 @@
   callback_.reset();
 }
 
-PresentationServiceImpl::DefaultSessionStartContext
-::DefaultSessionStartContext() {
-}
-
-PresentationServiceImpl::DefaultSessionStartContext
-::~DefaultSessionStartContext() {
-  Reset();
-}
-
-void PresentationServiceImpl::DefaultSessionStartContext::AddCallback(
-    const DefaultSessionMojoCallback& callback) {
-  if (session_.get()) {
-    DCHECK(callbacks_.empty());
-    callback.Run(presentation::PresentationSessionInfo::From(*session_));
-    session_.reset();
-  } else {
-    callbacks_.push_back(new DefaultSessionMojoCallback(callback));
-  }
-}
-
-void PresentationServiceImpl::DefaultSessionStartContext::set_session(
-    const PresentationSessionInfo& session) {
-  if (callbacks_.empty()) {
-    session_.reset(new PresentationSessionInfo(session));
-  } else {
-    DCHECK(!session_.get());
-    ScopedVector<DefaultSessionMojoCallback> callbacks;
-    callbacks.swap(callbacks_);
-    for (const auto& callback : callbacks)
-      callback->Run(presentation::PresentationSessionInfo::From(session));
-  }
-}
-
-void PresentationServiceImpl::DefaultSessionStartContext::Reset() {
-  ScopedVector<DefaultSessionMojoCallback> callbacks;
-  callbacks.swap(callbacks_);
-  for (const auto& callback : callbacks)
-    callback->Run(presentation::PresentationSessionInfoPtr());
-  session_.reset();
-}
-
 }  // namespace content
diff --git a/content/browser/presentation/presentation_service_impl.h b/content/browser/presentation/presentation_service_impl.h
index 220c256..54e1a4c 100644
--- a/content/browser/presentation/presentation_service_impl.h
+++ b/content/browser/presentation/presentation_service_impl.h
@@ -94,7 +94,7 @@
   // Maximum number of pending JoinSession requests at any given time.
   static const int kMaxNumQueuedSessionRequests = 10;
 
-  using DefaultSessionMojoCallback =
+  using PresentationSessionMojoCallback =
       mojo::Callback<void(presentation::PresentationSessionInfoPtr)>;
   using SessionStateCallback =
       mojo::Callback<void(presentation::PresentationSessionInfoPtr,
@@ -125,27 +125,6 @@
     PresentationServiceImpl* const service_;
   };
 
-  class CONTENT_EXPORT DefaultSessionStartContext {
-   public:
-    DefaultSessionStartContext();
-    ~DefaultSessionStartContext();
-
-    // Adds a callback. May invoke the callback immediately if |session| using
-    // default presentation URL was already started.
-    void AddCallback(const DefaultSessionMojoCallback& callback);
-
-    // Sets the session info. Maybe invoke callbacks queued with AddCallback().
-    void set_session(const PresentationSessionInfo& session);
-
-   private:
-    // Flush all queued callbacks by invoking them with null
-    // PresentationSessionInfoPtr.
-    void Reset();
-
-    ScopedVector<DefaultSessionMojoCallback> callbacks_;
-    scoped_ptr<PresentationSessionInfo> session_;
-  };
-
   // Ensures the provided NewSessionMojoCallback is invoked exactly once
   // before it goes out of scope.
   class NewSessionMojoCallbackWrapper {
@@ -177,8 +156,6 @@
   void SetClient(presentation::PresentationServiceClientPtr client) override;
   void ListenForScreenAvailability(const mojo::String& url) override;
   void StopListeningForScreenAvailability(const mojo::String& url) override;
-  void ListenForDefaultSessionStart(
-      const DefaultSessionMojoCallback& callback) override;
   void StartSession(
       const mojo::String& presentation_url,
       const NewSessionMojoCallback& callback) override;
@@ -208,8 +185,11 @@
 
   // PresentationServiceDelegate::Observer
   void OnDelegateDestroyed() override;
-  void OnDefaultPresentationStarted(const PresentationSessionInfo& session)
-      override;
+
+  // Passed to embedder's implementation of PresentationServiceDelegate for
+  // later invocation when default presentation has started.
+  void OnDefaultPresentationStarted(
+      const PresentationSessionInfo& session_info);
 
   // Finds the callback from |pending_join_session_cbs_| using
   // |request_session_id|.
@@ -284,8 +264,6 @@
   base::hash_map<int, linked_ptr<NewSessionMojoCallbackWrapper>>
       pending_join_session_cbs_;
 
-  scoped_ptr<DefaultSessionStartContext> default_session_start_context_;
-
   // RAII binding of |this| to an Presentation interface request.
   // The binding is removed when binding_ is cleared or goes out of scope.
   scoped_ptr<mojo::Binding<presentation::PresentationService>> binding_;
diff --git a/content/browser/presentation/presentation_service_impl_unittest.cc b/content/browser/presentation/presentation_service_impl_unittest.cc
index 3716586eb..f1b4d0a 100644
--- a/content/browser/presentation/presentation_service_impl_unittest.cc
+++ b/content/browser/presentation/presentation_service_impl_unittest.cc
@@ -41,12 +41,6 @@
 const char *const kPresentationId = "presentationId";
 const char *const kPresentationUrl = "http://foo.com/index.html";
 
-bool ArePresentationSessionsEqual(
-    const presentation::PresentationSessionInfo& expected,
-    const presentation::PresentationSessionInfo& actual) {
-  return expected.url == actual.url && expected.id == actual.id;
-}
-
 bool ArePresentationSessionMessagesEqual(
     const presentation::SessionMessage* expected,
     const presentation::SessionMessage* actual) {
@@ -91,26 +85,24 @@
       void(
           int render_process_id,
           int routing_id));
-  MOCK_METHOD3(SetDefaultPresentationUrl,
-      void(
-          int render_process_id,
-          int routing_id,
-          const std::string& default_presentation_url));
+  MOCK_METHOD4(SetDefaultPresentationUrl,
+               void(int render_process_id,
+                    int routing_id,
+                    const std::string& default_presentation_url,
+                    const PresentationSessionStartedCallback& callback));
   MOCK_METHOD5(StartSession,
-      void(
-          int render_process_id,
-          int render_frame_id,
-          const std::string& presentation_url,
-          const PresentationSessionSuccessCallback& success_cb,
-          const PresentationSessionErrorCallback& error_cb));
+               void(int render_process_id,
+                    int render_frame_id,
+                    const std::string& presentation_url,
+                    const PresentationSessionStartedCallback& success_cb,
+                    const PresentationSessionErrorCallback& error_cb));
   MOCK_METHOD6(JoinSession,
-      void(
-          int render_process_id,
-          int render_frame_id,
-          const std::string& presentation_url,
-          const std::string& presentation_id,
-          const PresentationSessionSuccessCallback& success_cb,
-          const PresentationSessionErrorCallback& error_cb));
+               void(int render_process_id,
+                    int render_frame_id,
+                    const std::string& presentation_url,
+                    const std::string& presentation_id,
+                    const PresentationSessionStartedCallback& success_cb,
+                    const PresentationSessionErrorCallback& error_cb));
   MOCK_METHOD3(CloseSession,
                void(int render_process_id,
                     int render_frame_id,
@@ -172,6 +164,13 @@
   }
   MOCK_METHOD0(MessagesReceived, void());
 
+  void OnDefaultSessionStarted(
+      presentation::PresentationSessionInfoPtr session_info) override {
+    OnDefaultSessionStarted(*session_info);
+  }
+  MOCK_METHOD1(OnDefaultSessionStarted,
+               void(const presentation::PresentationSessionInfo& session_info));
+
   mojo::Array<presentation::SessionMessagePtr> messages_received_;
 };
 
@@ -257,7 +256,6 @@
     EXPECT_EQ(
         service_impl_->screen_availability_listeners_.find(kPresentationUrl),
         service_impl_->screen_availability_listeners_.end());
-    EXPECT_FALSE(service_impl_->default_session_start_context_.get());
     EXPECT_FALSE(service_impl_->on_session_messages_callback_.get());
   }
 
@@ -279,25 +277,6 @@
       run_loop_quit_closure_.Run();
   }
 
-  void ExpectDefaultSessionStarted(
-      const presentation::PresentationSessionInfo& expected_session,
-      presentation::PresentationSessionInfoPtr actual_session) {
-    ASSERT_TRUE(!actual_session.is_null());
-    EXPECT_TRUE(ArePresentationSessionsEqual(
-        expected_session, *actual_session));
-    ++default_session_started_count_;
-    if (!run_loop_quit_closure_.is_null())
-      run_loop_quit_closure_.Run();
-  }
-
-  void ExpectDefaultSessionNull(
-      presentation::PresentationSessionInfoPtr actual_session) {
-    EXPECT_TRUE(actual_session.is_null());
-    ++default_session_started_count_;
-    if (!run_loop_quit_closure_.is_null())
-      run_loop_quit_closure_.Run();
-  }
-
   void ExpectSessionMessages(
       const mojo::Array<presentation::SessionMessagePtr>& expected_msgs,
       const mojo::Array<presentation::SessionMessagePtr>& actual_msgs) {
@@ -450,24 +429,32 @@
 
 TEST_F(PresentationServiceImplTest, SetDefaultPresentationUrl) {
   std::string url1("http://fooUrl");
-  EXPECT_CALL(mock_delegate_,
-      SetDefaultPresentationUrl(_, _, Eq(url1)))
+  EXPECT_CALL(mock_delegate_, SetDefaultPresentationUrl(_, _, Eq(url1), _))
       .Times(1);
   service_impl_->SetDefaultPresentationURL(url1);
   EXPECT_EQ(url1, service_impl_->default_presentation_url_);
 
   std::string url2("http://barUrl");
   // Sets different DPU.
-  EXPECT_CALL(mock_delegate_,
-      SetDefaultPresentationUrl(_, _, Eq(url2)))
-      .Times(1);
+  content::PresentationSessionStartedCallback callback;
+  EXPECT_CALL(mock_delegate_, SetDefaultPresentationUrl(_, _, Eq(url2), _))
+      .WillOnce(SaveArg<3>(&callback));
   service_impl_->SetDefaultPresentationURL(url2);
   EXPECT_EQ(url2, service_impl_->default_presentation_url_);
+
+  presentation::PresentationSessionInfo session_info;
+  session_info.url = url2;
+  session_info.id = kPresentationId;
+  base::RunLoop run_loop;
+  EXPECT_CALL(mock_client_, OnDefaultSessionStarted(Equals(session_info)))
+      .WillOnce(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit));
+  callback.Run(content::PresentationSessionInfo(url2, kPresentationId));
+  run_loop.Run();
 }
 
 TEST_F(PresentationServiceImplTest, SetSameDefaultPresentationUrl) {
   EXPECT_CALL(mock_delegate_,
-      SetDefaultPresentationUrl(_, _, Eq(kPresentationUrl)))
+              SetDefaultPresentationUrl(_, _, Eq(kPresentationUrl), _))
       .Times(1);
   service_impl_->SetDefaultPresentationURL(kPresentationUrl);
   EXPECT_TRUE(Mock::VerifyAndClearExpectations(&mock_delegate_));
@@ -592,59 +579,6 @@
   SaveQuitClosureAndRunLoop();
 }
 
-TEST_F(PresentationServiceImplTest, ListenForDefaultSessionStart) {
-  presentation::PresentationSessionInfo expected_session;
-  expected_session.url = kPresentationUrl;
-  expected_session.id = kPresentationId;
-  service_ptr_->ListenForDefaultSessionStart(
-      base::Bind(&PresentationServiceImplTest::ExpectDefaultSessionStarted,
-                 base::Unretained(this),
-                 expected_session));
-  RunLoopFor(base::TimeDelta::FromMilliseconds(50));
-  service_impl_->OnDefaultPresentationStarted(
-      content::PresentationSessionInfo(kPresentationUrl, kPresentationId));
-  SaveQuitClosureAndRunLoop();
-  EXPECT_EQ(1, default_session_started_count_);
-}
-
-TEST_F(PresentationServiceImplTest, ListenForDefaultSessionStartAfterSet) {
-  // Note that the callback will only pick up presentation_url2/id2 since
-  // ListenForDefaultSessionStart wasn't called yet when the DPU was still
-  // presentation_url1.
-  std::string presentation_url1("http://fooUrl1");
-  std::string presentation_id1("presentationId1");
-  std::string presentation_url2("http://fooUrl2");
-  std::string presentation_id2("presentationId2");
-  service_impl_->OnDefaultPresentationStarted(
-      content::PresentationSessionInfo(presentation_url1, presentation_id1));
-
-  presentation::PresentationSessionInfo expected_session;
-  expected_session.url = presentation_url2;
-  expected_session.id = presentation_id2;
-  service_ptr_->ListenForDefaultSessionStart(
-      base::Bind(&PresentationServiceImplTest::ExpectDefaultSessionStarted,
-                 base::Unretained(this),
-                 expected_session));
-  RunLoopFor(base::TimeDelta::FromMilliseconds(50));
-  service_impl_->OnDefaultPresentationStarted(
-      content::PresentationSessionInfo(presentation_url2, presentation_id2));
-  SaveQuitClosureAndRunLoop();
-  EXPECT_EQ(1, default_session_started_count_);
-}
-
-TEST_F(PresentationServiceImplTest, DefaultSessionStartReset) {
-  service_ptr_->ListenForDefaultSessionStart(
-      base::Bind(&PresentationServiceImplTest::ExpectDefaultSessionNull,
-                 base::Unretained(this)));
-  RunLoopFor(TestTimeouts::tiny_timeout());
-
-  ExpectReset();
-  service_impl_->Reset();
-  ExpectCleanState();
-  SaveQuitClosureAndRunLoop();
-  EXPECT_EQ(1, default_session_started_count_);
-}
-
 TEST_F(PresentationServiceImplTest, SendStringMessage) {
   std::string message("Test presentation session message");
 
diff --git a/content/browser/renderer_host/render_message_filter.cc b/content/browser/renderer_host/render_message_filter.cc
index 9feac401..39034ec 100644
--- a/content/browser/renderer_host/render_message_filter.cc
+++ b/content/browser/renderer_host/render_message_filter.cc
@@ -4,6 +4,9 @@
 
 #include "content/browser/renderer_host/render_message_filter.h"
 
+#include <errno.h>
+#include <string.h>
+
 #include <map>
 
 #include "base/bind.h"
diff --git a/content/browser/webui/OWNERS b/content/browser/webui/OWNERS
index 06e8b6d..658a9f5 100644
--- a/content/browser/webui/OWNERS
+++ b/content/browser/webui/OWNERS
@@ -1,2 +1 @@
 estade@chromium.org
-jhawkins@chromium.org
diff --git a/content/browser/zygote_host/zygote_host_impl_linux.cc b/content/browser/zygote_host/zygote_host_impl_linux.cc
index b8e1b3be..a11d51f 100644
--- a/content/browser/zygote_host/zygote_host_impl_linux.cc
+++ b/content/browser/zygote_host/zygote_host_impl_linux.cc
@@ -4,6 +4,7 @@
 
 #include "content/browser/zygote_host/zygote_host_impl_linux.h"
 
+#include <errno.h>
 #include <string.h>
 #include <sys/socket.h>
 #include <sys/stat.h>
diff --git a/content/child/shared_worker_devtools_agent.cc b/content/child/shared_worker_devtools_agent.cc
index 26a51ed..9b1996f 100644
--- a/content/child/shared_worker_devtools_agent.cc
+++ b/content/child/shared_worker_devtools_agent.cc
@@ -44,6 +44,7 @@
 }
 
 void SharedWorkerDevToolsAgent::SendDevToolsMessage(
+    int session_id,
     int call_id,
     const blink::WebString& msg,
     const blink::WebString& state) {
@@ -55,6 +56,7 @@
 
   if (message.length() < kMaxMessageChunkSize) {
     chunk.data.swap(message);
+    chunk.session_id = session_id;
     chunk.call_id = call_id;
     chunk.post_state = post_state;
     chunk.is_last = true;
@@ -65,6 +67,7 @@
 
   for (size_t pos = 0; pos < message.length(); pos += kMaxMessageChunkSize) {
     chunk.is_last = pos + kMaxMessageChunkSize >= message.length();
+    chunk.session_id = chunk.is_last ? session_id : 0;
     chunk.call_id = chunk.is_last ? call_id : 0;
     chunk.post_state = chunk.is_last ? post_state : std::string();
     chunk.data = message.substr(pos, kMaxMessageChunkSize);
@@ -75,13 +78,15 @@
   }
 }
 
-void SharedWorkerDevToolsAgent::OnAttach(const std::string& host_id) {
-  webworker_->attachDevTools(WebString::fromUTF8(host_id));
+void SharedWorkerDevToolsAgent::OnAttach(const std::string& host_id,
+                                         int session_id) {
+  webworker_->attachDevTools(WebString::fromUTF8(host_id), session_id);
 }
 
 void SharedWorkerDevToolsAgent::OnReattach(const std::string& host_id,
+                                           int session_id,
                                            const std::string& state) {
-  webworker_->reattachDevTools(WebString::fromUTF8(host_id),
+  webworker_->reattachDevTools(WebString::fromUTF8(host_id), session_id,
                                WebString::fromUTF8(state));
 }
 
@@ -90,8 +95,9 @@
 }
 
 void SharedWorkerDevToolsAgent::OnDispatchOnInspectorBackend(
+    int session_id,
     const std::string& message) {
-  webworker_->dispatchDevToolsMessage(WebString::fromUTF8(message));
+  webworker_->dispatchDevToolsMessage(session_id, WebString::fromUTF8(message));
 }
 
 bool SharedWorkerDevToolsAgent::Send(IPC::Message* message) {
diff --git a/content/child/shared_worker_devtools_agent.h b/content/child/shared_worker_devtools_agent.h
index 2d6a732a..19b1ea9 100644
--- a/content/child/shared_worker_devtools_agent.h
+++ b/content/child/shared_worker_devtools_agent.h
@@ -27,15 +27,18 @@
 
   // Called on the Worker thread.
   bool OnMessageReceived(const IPC::Message& message);
-  void SendDevToolsMessage(int call_id,
+  void SendDevToolsMessage(int session_id,
+                           int call_id,
                            const blink::WebString& message,
                            const blink::WebString& post_state);
 
  private:
-  void OnAttach(const std::string& host_id);
-  void OnReattach(const std::string& host_id, const std::string& state);
+  void OnAttach(const std::string& host_id, int session_id);
+  void OnReattach(const std::string& host_id,
+                  int session_id,
+                  const std::string& state);
   void OnDetach();
-  void OnDispatchOnInspectorBackend(const std::string& message);
+  void OnDispatchOnInspectorBackend(int session_id, const std::string& message);
 
   bool Send(IPC::Message* message);
   const int route_id_;
diff --git a/content/common/devtools_messages.h b/content/common/devtools_messages.h
index a6e17ecd..cba6f54b 100644
--- a/content/common/devtools_messages.h
+++ b/content/common/devtools_messages.h
@@ -58,12 +58,14 @@
 // Agent -> Client message chunk.
 //   |is_first| marks the first chunk, comes with the |message_size| for
 //   total message size.
-//   |is_last| marks the last chunk. |call_id| and |post_state| are optional
-//    parameters passed with the last chunk of the protocol response.
+//   |is_last| marks the last chunk. |call_id|, |session_id| and |post_state|
+//   are optional parameters passed with the last chunk of the protocol
+//   response.
 IPC_STRUCT_BEGIN(DevToolsMessageChunk)
   IPC_STRUCT_MEMBER(bool, is_first)
   IPC_STRUCT_MEMBER(bool, is_last)
   IPC_STRUCT_MEMBER(int, message_size)
+  IPC_STRUCT_MEMBER(int, session_id)
   IPC_STRUCT_MEMBER(int, call_id)
   IPC_STRUCT_MEMBER(std::string, data)
   IPC_STRUCT_MEMBER(std::string, post_state)
@@ -77,25 +79,29 @@
 // These are messages sent from DevToolsClient to DevToolsAgent through the
 // browser.
 // Tells agent that there is a client host connected to it.
-IPC_MESSAGE_ROUTED1(DevToolsAgentMsg_Attach,
-                    std::string /* host_id */)
+IPC_MESSAGE_ROUTED2(DevToolsAgentMsg_Attach,
+                    std::string /* host_id */,
+                    int /* session_id */)
 
 // Tells agent that a client host was disconnected from another agent and
 // connected to this one.
-IPC_MESSAGE_ROUTED2(DevToolsAgentMsg_Reattach,
+IPC_MESSAGE_ROUTED3(DevToolsAgentMsg_Reattach,
                     std::string /* host_id */,
+                    int /* session_id */,
                     std::string /* agent_state */)
 
 // Tells agent that there is no longer a client host connected to it.
 IPC_MESSAGE_ROUTED0(DevToolsAgentMsg_Detach)
 
 // WebKit-level transport.
-IPC_MESSAGE_ROUTED1(DevToolsAgentMsg_DispatchOnInspectorBackend,
+IPC_MESSAGE_ROUTED2(DevToolsAgentMsg_DispatchOnInspectorBackend,
+                    int /* session_id */,
                     std::string /* message */)
 
 // Inspect element with the given coordinates.
-IPC_MESSAGE_ROUTED3(DevToolsAgentMsg_InspectElement,
+IPC_MESSAGE_ROUTED4(DevToolsAgentMsg_InspectElement,
                     std::string /* host_id */,
+                    int /* session_id */,
                     int /* x */,
                     int /* y */)
 
diff --git a/content/common/gpu/media/generic_v4l2_device.cc b/content/common/gpu/media/generic_v4l2_device.cc
index b784899..f795cb9 100644
--- a/content/common/gpu/media/generic_v4l2_device.cc
+++ b/content/common/gpu/media/generic_v4l2_device.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 //
 
+#include <errno.h>
 #include <fcntl.h>
 #include <libdrm/drm_fourcc.h>
 #include <linux/videodev2.h>
diff --git a/content/common/gpu/media/v4l2_image_processor.cc b/content/common/gpu/media/v4l2_image_processor.cc
index 115f605..ff2c1108 100644
--- a/content/common/gpu/media/v4l2_image_processor.cc
+++ b/content/common/gpu/media/v4l2_image_processor.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <errno.h>
 #include <fcntl.h>
 #include <linux/videodev2.h>
 #include <poll.h>
diff --git a/content/common/gpu/media/v4l2_jpeg_decode_accelerator.cc b/content/common/gpu/media/v4l2_jpeg_decode_accelerator.cc
index cf152a7..dbb03f3 100644
--- a/content/common/gpu/media/v4l2_jpeg_decode_accelerator.cc
+++ b/content/common/gpu/media/v4l2_jpeg_decode_accelerator.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <errno.h>
 #include <linux/videodev2.h>
 #include <sys/mman.h>
 
diff --git a/content/common/gpu/media/v4l2_slice_video_decode_accelerator.cc b/content/common/gpu/media/v4l2_slice_video_decode_accelerator.cc
index 4d98f2a..a682648b 100644
--- a/content/common/gpu/media/v4l2_slice_video_decode_accelerator.cc
+++ b/content/common/gpu/media/v4l2_slice_video_decode_accelerator.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <errno.h>
 #include <fcntl.h>
 #include <linux/videodev2.h>
 #include <poll.h>
diff --git a/content/common/presentation/presentation_service.mojom b/content/common/presentation/presentation_service.mojom
index 3256a965..422ae58 100644
--- a/content/common/presentation/presentation_service.mojom
+++ b/content/common/presentation/presentation_service.mojom
@@ -42,12 +42,14 @@
 };
 
 interface PresentationService {
-  // Called when the frame sets or changes the default presentation URL.
-  SetDefaultPresentationURL(string url);
-
   // Sets the PresentationServiceClient.
   SetClient(PresentationServiceClient client);
 
+  // Called when the frame sets or changes the default presentation URL.
+  // When the default presentation is started on this frame,
+  // PresentationServiceClient::OnDefaultSessionStarted will be invoked.
+  SetDefaultPresentationURL(string url);
+
   // Starts listening for screen availability for presentation of
   // |url|. Availability results will be returned to the client via
   // PresentationServiceClient::OnScreenAvailabilityUpdated.
@@ -58,13 +60,6 @@
   // |url|.
   StopListeningForScreenAvailability(string url);
 
-  // Called when the renderer is ready to receive the browser initiated
-  // session. If the default session is started by the embedder before this
-  // call, the embedder may queue it and run the callback when the call is
-  // performed.
-  ListenForDefaultSessionStart()
-      => (PresentationSessionInfo? defaultSessionInfo);
-
   // Called when startSession() is called by the frame. The result callback
   // will return a non-null and valid PresentationSessionInfo if starting the
   // session succeeded, or null with a PresentationError if starting the
@@ -89,7 +84,8 @@
   // The false in the result callback notifies the renderer to stop sending
   // the send requests and invalidate all pending requests. This occurs
   // for eg., when frame is deleted or navigated away.
-  SendSessionMessage(PresentationSessionInfo sessionInfo, SessionMessage message_request) => (bool success);
+  SendSessionMessage(PresentationSessionInfo sessionInfo,
+                     SessionMessage message_request) => (bool success);
 
   // Called when closeSession() is called by the frame.
   CloseSession(string presentation_url, string presentation_id);
@@ -125,5 +121,9 @@
                         PresentationConnectionState newState);
 
   // See PresentationService::ListenForSessionMessages.
-  OnSessionMessagesReceived(PresentationSessionInfo sessionInfo, array<SessionMessage> messages);
-}; 
+  OnSessionMessagesReceived(PresentationSessionInfo sessionInfo,
+                            array<SessionMessage> messages);
+
+  // See PresentationService::SetDefaultPresentationURL.
+  OnDefaultSessionStarted(PresentationSessionInfo sessionInfo);
+};
diff --git a/content/content_browser.gypi b/content/content_browser.gypi
index 569e2bd..0d46bbdd 100644
--- a/content/content_browser.gypi
+++ b/content/content_browser.gypi
@@ -544,6 +544,7 @@
       'browser/devtools/forwarding_agent_host.h',
       'browser/devtools/protocol/color_picker.cc',
       'browser/devtools/protocol/color_picker.h',
+      'browser/devtools/protocol/devtools_protocol_delegate.h',
       'browser/devtools/protocol/devtools_protocol_client.cc',
       'browser/devtools/protocol/devtools_protocol_client.h',
       'browser/devtools/protocol/dom_handler.cc',
diff --git a/content/content_tests.gypi b/content/content_tests.gypi
index 2eb0e09..7a72fdb 100644
--- a/content/content_tests.gypi
+++ b/content/content_tests.gypi
@@ -1893,6 +1893,7 @@
           ],
         },
         {
+          # GN: //content/shell/android:content_shell_browsertests_java
           'target_name': 'content_shell_browsertests_java',
           'type': 'none',
           'dependencies': [
diff --git a/content/gpu/gpu_watchdog_thread.cc b/content/gpu/gpu_watchdog_thread.cc
index 801c2fc..7f997bf 100644
--- a/content/gpu/gpu_watchdog_thread.cc
+++ b/content/gpu/gpu_watchdog_thread.cc
@@ -2,12 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "content/gpu/gpu_watchdog_thread.h"
+
+#include <errno.h>
+
 #if defined(OS_WIN)
 #include <windows.h>
 #endif
 
-#include "content/gpu/gpu_watchdog_thread.h"
-
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/command_line.h"
diff --git a/content/public/browser/presentation_service_delegate.h b/content/public/browser/presentation_service_delegate.h
index 5c4e5c8..ba0bf99d 100644
--- a/content/public/browser/presentation_service_delegate.h
+++ b/content/public/browser/presentation_service_delegate.h
@@ -19,6 +19,10 @@
 
 class PresentationScreenAvailabilityListener;
 
+using PresentationSessionStartedCallback =
+    base::Callback<void(const PresentationSessionInfo&)>;
+using PresentationSessionErrorCallback =
+    base::Callback<void(const PresentationError&)>;
 using SessionStateChangedCallback =
     base::Callback<void(const PresentationSessionInfo&,
                         PresentationConnectionState)>;
@@ -39,21 +43,10 @@
     // Called when the PresentationServiceDelegate is being destroyed.
     virtual void OnDelegateDestroyed() = 0;
 
-    // Called when the default presentation has been started outside of a
-    // Presentation API context (e.g., browser action). This will not be called
-    // if the session was created as a result of Presentation API's
-    // StartSession()/JoinSession().
-    virtual void OnDefaultPresentationStarted(
-        const PresentationSessionInfo& session) = 0;
-
    protected:
     virtual ~Observer() {}
   };
 
-  using PresentationSessionSuccessCallback =
-      base::Callback<void(const PresentationSessionInfo&)>;
-  using PresentationSessionErrorCallback =
-      base::Callback<void(const PresentationError&)>;
   using SendMessageCallback = base::Callback<void(bool)>;
 
   virtual ~PresentationServiceDelegate() {}
@@ -101,13 +94,16 @@
       int render_frame_id) = 0;
 
   // Sets the default presentation URL for frame given by |render_process_id|
-  // and |render_frame_id|.
+  // and |render_frame_id|. When the default presentation is started on this
+  // frame, |callback| will be invoked with the corresponding
+  // PresentationSessionInfo object.
   // If |default_presentation_url| is empty, the default presentation URL will
-  // be cleared.
+  // be cleared and the previously registered callback (if any) will be removed.
   virtual void SetDefaultPresentationUrl(
       int render_process_id,
       int render_frame_id,
-      const std::string& default_presentation_url) = 0;
+      const std::string& default_presentation_url,
+      const PresentationSessionStartedCallback& callback) = 0;
 
   // Starts a new presentation session. The presentation id of the session will
   // be the default presentation ID if any or a generated one otherwise.
@@ -123,7 +119,7 @@
       int render_process_id,
       int render_frame_id,
       const std::string& presentation_url,
-      const PresentationSessionSuccessCallback& success_cb,
+      const PresentationSessionStartedCallback& success_cb,
       const PresentationSessionErrorCallback& error_cb) = 0;
 
   // Joins an existing presentation session. Unlike StartSession(), this
@@ -139,7 +135,7 @@
       int render_frame_id,
       const std::string& presentation_url,
       const std::string& presentation_id,
-      const PresentationSessionSuccessCallback& success_cb,
+      const PresentationSessionStartedCallback& success_cb,
       const PresentationSessionErrorCallback& error_cb) = 0;
 
   // Close an existing presentation session.
diff --git a/content/renderer/devtools/devtools_agent.cc b/content/renderer/devtools/devtools_agent.cc
index d464b15b..a7d91cac 100644
--- a/content/renderer/devtools/devtools_agent.cc
+++ b/content/renderer/devtools/devtools_agent.cc
@@ -101,12 +101,12 @@
   ContinueProgram();
 }
 
-void DevToolsAgent::sendProtocolMessage(
-    int call_id,
-    const blink::WebString& message,
-    const blink::WebString& state_cookie) {
-  SendChunkedProtocolMessage(
-      this, routing_id(), call_id, message.utf8(), state_cookie.utf8());
+void DevToolsAgent::sendProtocolMessage(int session_id,
+                                        int call_id,
+                                        const blink::WebString& message,
+                                        const blink::WebString& state_cookie) {
+  SendChunkedProtocolMessage(this, routing_id(), session_id, call_id,
+                             message.utf8(), state_cookie.utf8());
 }
 
 blink::WebDevToolsAgentClient::WebKitClientMessageLoop*
@@ -151,18 +151,19 @@
 }
 
 // static
-void DevToolsAgent::SendChunkedProtocolMessage(
-    IPC::Sender* sender,
-    int routing_id,
-    int call_id,
-    const std::string& message,
-    const std::string& post_state) {
+void DevToolsAgent::SendChunkedProtocolMessage(IPC::Sender* sender,
+                                               int routing_id,
+                                               int session_id,
+                                               int call_id,
+                                               const std::string& message,
+                                               const std::string& post_state) {
   DevToolsMessageChunk chunk;
   chunk.message_size = message.size();
   chunk.is_first = true;
 
   if (message.length() < kMaxMessageChunkSize) {
     chunk.data = message;
+    chunk.session_id = session_id;
     chunk.call_id = call_id;
     chunk.post_state = post_state;
     chunk.is_last = true;
@@ -173,6 +174,7 @@
 
   for (size_t pos = 0; pos < message.length(); pos += kMaxMessageChunkSize) {
     chunk.is_last = pos + kMaxMessageChunkSize >= message.length();
+    chunk.session_id = chunk.is_last ? session_id : 0;
     chunk.call_id = chunk.is_last ? call_id : 0;
     chunk.post_state = chunk.is_last ? post_state : std::string();
     chunk.data = message.substr(pos, kMaxMessageChunkSize);
@@ -183,19 +185,20 @@
   }
 }
 
-void DevToolsAgent::OnAttach(const std::string& host_id) {
+void DevToolsAgent::OnAttach(const std::string& host_id, int session_id) {
   WebDevToolsAgent* web_agent = GetWebAgent();
   if (web_agent) {
-    web_agent->attach(WebString::fromUTF8(host_id));
+    web_agent->attach(WebString::fromUTF8(host_id), session_id);
     is_attached_ = true;
   }
 }
 
 void DevToolsAgent::OnReattach(const std::string& host_id,
+                               int session_id,
                                const std::string& agent_state) {
   WebDevToolsAgent* web_agent = GetWebAgent();
   if (web_agent) {
-    web_agent->reattach(WebString::fromUTF8(host_id),
+    web_agent->reattach(WebString::fromUTF8(host_id), session_id,
                         WebString::fromUTF8(agent_state));
     is_attached_ = true;
   }
@@ -209,18 +212,22 @@
   }
 }
 
-void DevToolsAgent::OnDispatchOnInspectorBackend(const std::string& message) {
+void DevToolsAgent::OnDispatchOnInspectorBackend(int session_id,
+                                                 const std::string& message) {
   TRACE_EVENT0("devtools", "DevToolsAgent::OnDispatchOnInspectorBackend");
   WebDevToolsAgent* web_agent = GetWebAgent();
   if (web_agent)
-    web_agent->dispatchOnInspectorBackend(WebString::fromUTF8(message));
+    web_agent->dispatchOnInspectorBackend(session_id,
+                                          WebString::fromUTF8(message));
 }
 
-void DevToolsAgent::OnInspectElement(
-    const std::string& host_id, int x, int y) {
+void DevToolsAgent::OnInspectElement(const std::string& host_id,
+                                     int session_id,
+                                     int x,
+                                     int y) {
   WebDevToolsAgent* web_agent = GetWebAgent();
   if (web_agent) {
-    web_agent->attach(WebString::fromUTF8(host_id));
+    web_agent->attach(WebString::fromUTF8(host_id), session_id);
     web_agent->inspectElementAt(WebPoint(x, y));
     is_attached_ = true;
   }
diff --git a/content/renderer/devtools/devtools_agent.h b/content/renderer/devtools/devtools_agent.h
index 7b1200b..865fc0fd8 100644
--- a/content/renderer/devtools/devtools_agent.h
+++ b/content/renderer/devtools/devtools_agent.h
@@ -33,12 +33,12 @@
   // Returns agent instance for its routing id.
   static DevToolsAgent* FromRoutingId(int routing_id);
 
-  static void SendChunkedProtocolMessage(
-      IPC::Sender* sender,
-      int routing_id,
-      int call_id,
-      const std::string& message,
-      const std::string& post_state);
+  static void SendChunkedProtocolMessage(IPC::Sender* sender,
+                                         int routing_id,
+                                         int session_id,
+                                         int call_id,
+                                         const std::string& message,
+                                         const std::string& post_state);
 
   blink::WebDevToolsAgent* GetWebAgent();
 
@@ -55,7 +55,8 @@
   void WidgetWillClose() override;
 
   // WebDevToolsAgentClient implementation.
-  void sendProtocolMessage(int call_id,
+  void sendProtocolMessage(int session_id,
+                           int call_id,
                            const blink::WebString& response,
                            const blink::WebString& state) override;
   blink::WebDevToolsAgentClient::WebKitClientMessageLoop*
@@ -66,12 +67,16 @@
   void enableTracing(const blink::WebString& category_filter) override;
   void disableTracing() override;
 
-  void OnAttach(const std::string& host_id);
+  void OnAttach(const std::string& host_id, int session_id);
   void OnReattach(const std::string& host_id,
+                  int session_id,
                   const std::string& agent_state);
   void OnDetach();
-  void OnDispatchOnInspectorBackend(const std::string& message);
-  void OnInspectElement(const std::string& host_id, int x, int y);
+  void OnDispatchOnInspectorBackend(int session_id, const std::string& message);
+  void OnInspectElement(const std::string& host_id,
+                        int session_id,
+                        int x,
+                        int y);
   void ContinueProgram();
   void OnSetupDevToolsClient(const std::string& compatibility_script);
 
diff --git a/content/renderer/devtools/devtools_agent_filter.cc b/content/renderer/devtools/devtools_agent_filter.cc
index e1b3af0..94b9e0d4 100644
--- a/content/renderer/devtools/devtools_agent_filter.cc
+++ b/content/renderer/devtools/devtools_agent_filter.cc
@@ -60,6 +60,7 @@
 DevToolsAgentFilter::~DevToolsAgentFilter() {}
 
 void DevToolsAgentFilter::OnDispatchOnInspectorBackend(
+    int session_id,
     const std::string& message) {
   if (embedded_worker_routes_.find(current_routing_id_) !=
       embedded_worker_routes_.end()) {
@@ -69,7 +70,7 @@
   if (WebDevToolsAgent::shouldInterruptForMessage(
           WebString::fromUTF8(message))) {
     WebDevToolsAgent::interruptAndDispatch(
-        new MessageImpl(message, current_routing_id_));
+        session_id, new MessageImpl(message, current_routing_id_));
   }
 
 }
diff --git a/content/renderer/devtools/devtools_agent_filter.h b/content/renderer/devtools/devtools_agent_filter.h
index c8ba687..9113ae2 100644
--- a/content/renderer/devtools/devtools_agent_filter.h
+++ b/content/renderer/devtools/devtools_agent_filter.h
@@ -43,7 +43,7 @@
   ~DevToolsAgentFilter() override;
 
  private:
-  void OnDispatchOnInspectorBackend(const std::string& message);
+  void OnDispatchOnInspectorBackend(int session_id, const std::string& message);
 
   // Called on IO thread
   void AddEmbeddedWorkerRoute(int32 routing_id);
diff --git a/content/renderer/presentation/presentation_dispatcher.cc b/content/renderer/presentation/presentation_dispatcher.cc
index 9eb9c6795..1a249e8 100644
--- a/content/renderer/presentation/presentation_dispatcher.cc
+++ b/content/renderer/presentation/presentation_dispatcher.cc
@@ -337,11 +337,6 @@
   if (!controller_)
     return;
 
-  // Reset the callback to get the next event.
-  presentation_service_->ListenForDefaultSessionStart(base::Bind(
-      &PresentationDispatcher::OnDefaultSessionStarted,
-      base::Unretained(this)));
-
   if (!session_info.is_null()) {
     controller_->didStartDefaultSession(
         new PresentationConnectionClient(session_info.Clone()));
@@ -426,9 +421,6 @@
   binding_.Bind(GetProxy(&client_ptr));
   presentation_service_->SetClient(client_ptr.Pass());
 
-  presentation_service_->ListenForDefaultSessionStart(base::Bind(
-      &PresentationDispatcher::OnDefaultSessionStarted,
-      base::Unretained(this)));
   presentation_service_->ListenForSessionStateChange();
 }
 
diff --git a/content/renderer/presentation/presentation_dispatcher.h b/content/renderer/presentation/presentation_dispatcher.h
index 54c259b..7311329 100644
--- a/content/renderer/presentation/presentation_dispatcher.h
+++ b/content/renderer/presentation/presentation_dispatcher.h
@@ -100,13 +100,13 @@
   void OnSessionMessagesReceived(
       presentation::PresentationSessionInfoPtr session_info,
       mojo::Array<presentation::SessionMessagePtr> messages) override;
+  void OnDefaultSessionStarted(
+      presentation::PresentationSessionInfoPtr session_info) override;
 
   void OnSessionCreated(
       blink::WebPresentationConnectionClientCallbacks* callback,
       presentation::PresentationSessionInfoPtr session_info,
       presentation::PresentationErrorPtr error);
-  void OnDefaultSessionStarted(
-      presentation::PresentationSessionInfoPtr session_info);
 
   // Call to PresentationService to send the message in |request|.
   // |session_info| and |message| of |reuqest| will be consumed.
diff --git a/content/renderer/render_view_browsertest.cc b/content/renderer/render_view_browsertest.cc
index 3783e905..90715c8 100644
--- a/content/renderer/render_view_browsertest.cc
+++ b/content/renderer/render_view_browsertest.cc
@@ -300,7 +300,7 @@
  public:
   void Attach() {
     std::string host_id = "host_id";
-    agent()->OnAttach(host_id);
+    agent()->OnAttach(host_id, 17);
   }
 
   void Detach() {
@@ -312,7 +312,7 @@
   }
 
   void DispatchDevToolsMessage(const std::string& message) {
-    agent()->OnDispatchOnInspectorBackend(message);
+    agent()->OnDispatchOnInspectorBackend(17, message);
   }
 
   void CloseWhilePaused() {
diff --git a/content/renderer/service_worker/embedded_worker_devtools_agent.cc b/content/renderer/service_worker/embedded_worker_devtools_agent.cc
index e1c640a..a099729 100644
--- a/content/renderer/service_worker/embedded_worker_devtools_agent.cc
+++ b/content/renderer/service_worker/embedded_worker_devtools_agent.cc
@@ -40,13 +40,15 @@
   return handled;
 }
 
-void EmbeddedWorkerDevToolsAgent::OnAttach(const std::string& host_id) {
-  webworker_->attachDevTools(WebString::fromUTF8(host_id));
+void EmbeddedWorkerDevToolsAgent::OnAttach(const std::string& host_id,
+                                           int session_id) {
+  webworker_->attachDevTools(WebString::fromUTF8(host_id), session_id);
 }
 
 void EmbeddedWorkerDevToolsAgent::OnReattach(const std::string& host_id,
+                                             int session_id,
                                              const std::string& state) {
-  webworker_->reattachDevTools(WebString::fromUTF8(host_id),
+  webworker_->reattachDevTools(WebString::fromUTF8(host_id), session_id,
                                WebString::fromUTF8(state));
 }
 
@@ -55,8 +57,9 @@
 }
 
 void EmbeddedWorkerDevToolsAgent::OnDispatchOnInspectorBackend(
+    int session_id,
     const std::string& message) {
-  webworker_->dispatchDevToolsMessage(WebString::fromUTF8(message));
+  webworker_->dispatchDevToolsMessage(session_id, WebString::fromUTF8(message));
 }
 
 }  // namespace content
diff --git a/content/renderer/service_worker/embedded_worker_devtools_agent.h b/content/renderer/service_worker/embedded_worker_devtools_agent.h
index 97c15824..c63081e 100644
--- a/content/renderer/service_worker/embedded_worker_devtools_agent.h
+++ b/content/renderer/service_worker/embedded_worker_devtools_agent.h
@@ -30,10 +30,12 @@
   bool OnMessageReceived(const IPC::Message& message) override;
 
  private:
-  void OnAttach(const std::string& host_id);
-  void OnReattach(const std::string& host_id, const std::string& state);
+  void OnAttach(const std::string& host_id, int session_id);
+  void OnReattach(const std::string& host_id,
+                  int session_id,
+                  const std::string& state);
   void OnDetach();
-  void OnDispatchOnInspectorBackend(const std::string& message);
+  void OnDispatchOnInspectorBackend(int session_id, const std::string& message);
 
   blink::WebEmbeddedWorker* webworker_;
   int route_id_;
diff --git a/content/renderer/service_worker/service_worker_context_client.cc b/content/renderer/service_worker/service_worker_context_client.cc
index f11338fb..8e556c0 100644
--- a/content/renderer/service_worker/service_worker_context_client.cc
+++ b/content/renderer/service_worker/service_worker_context_client.cc
@@ -468,12 +468,13 @@
 }
 
 void ServiceWorkerContextClient::sendDevToolsMessage(
+    int session_id,
     int call_id,
     const blink::WebString& message,
     const blink::WebString& state_cookie) {
   DevToolsAgent::SendChunkedProtocolMessage(
-      sender_.get(), worker_devtools_agent_route_id_,
-      call_id, message.utf8(), state_cookie.utf8());
+      sender_.get(), worker_devtools_agent_route_id_, session_id, call_id,
+      message.utf8(), state_cookie.utf8());
 }
 
 void ServiceWorkerContextClient::didHandleActivateEvent(
diff --git a/content/renderer/service_worker/service_worker_context_client.h b/content/renderer/service_worker/service_worker_context_client.h
index b3fd33d9..6223c7e 100644
--- a/content/renderer/service_worker/service_worker_context_client.h
+++ b/content/renderer/service_worker/service_worker_context_client.h
@@ -117,7 +117,8 @@
                             const blink::WebString& message,
                             int line_number,
                             const blink::WebString& source_url) override;
-  void sendDevToolsMessage(int call_id,
+  void sendDevToolsMessage(int session_id,
+                           int call_id,
                            const blink::WebString& message,
                            const blink::WebString& state) override;
   void didHandleActivateEvent(int request_id,
diff --git a/content/renderer/shared_worker/embedded_shared_worker_stub.cc b/content/renderer/shared_worker/embedded_shared_worker_stub.cc
index 934dade..975bab9 100644
--- a/content/renderer/shared_worker/embedded_shared_worker_stub.cc
+++ b/content/renderer/shared_worker/embedded_shared_worker_stub.cc
@@ -253,10 +253,12 @@
 }
 
 void EmbeddedSharedWorkerStub::sendDevToolsMessage(
+    int session_id,
     int call_id,
     const blink::WebString& message,
     const blink::WebString& state) {
-  worker_devtools_agent_->SendDevToolsMessage(call_id, message, state);
+  worker_devtools_agent_->SendDevToolsMessage(
+      session_id, call_id, message, state);
 }
 
 void EmbeddedSharedWorkerStub::Shutdown() {
diff --git a/content/renderer/shared_worker/embedded_shared_worker_stub.h b/content/renderer/shared_worker/embedded_shared_worker_stub.h
index 9f2c6c0..a7d62d0 100644
--- a/content/renderer/shared_worker/embedded_shared_worker_stub.h
+++ b/content/renderer/shared_worker/embedded_shared_worker_stub.h
@@ -70,7 +70,8 @@
       const blink::WebSecurityOrigin& origin) override;
   blink::WebServiceWorkerNetworkProvider* createServiceWorkerNetworkProvider(
       blink::WebDataSource*) override;
-  void sendDevToolsMessage(int call_id,
+  void sendDevToolsMessage(int session_id,
+                           int call_id,
                            const blink::WebString& message,
                            const blink::WebString& state) override;
 
diff --git a/content/shell/android/BUILD.gn b/content/shell/android/BUILD.gn
index ae88a8c..e51f9eb0 100644
--- a/content/shell/android/BUILD.gn
+++ b/content/shell/android/BUILD.gn
@@ -224,3 +224,16 @@
     ]
   }
 }
+
+# GYP: //content/content_tests.gypi:content_shell_browsertests_java"
+android_library("content_shell_browsertests_java") {
+  testonly = true
+  deps = [
+    ":content_shell_java",
+    "//base:base_java",
+    "//content/public/android:content_java",
+    "//testing/android/native_test:native_test_java",
+    "//ui/android:ui_java",
+  ]
+  DEPRECATED_java_in_dir = "browsertests/src"
+}
diff --git a/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.cc b/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.cc
index 49da15af..6b5bcd7 100644
--- a/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.cc
+++ b/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.cc
@@ -158,7 +158,7 @@
   else if (fake_adapter_name == "DelayedServicesDiscoveryAdapter")
     return GetDelayedServicesDiscoveryAdapter();
   else if (fake_adapter_name == "")
-    return NULL;
+    return nullptr;
 
   if (base::StartsWith(fake_adapter_name, "PowerValueAdapter",
                        base::CompareCase::SENSITIVE)) {
diff --git a/content/shell/browser/layout_test/layout_test_push_messaging_service.cc b/content/shell/browser/layout_test/layout_test_push_messaging_service.cc
index e108c03..78db934 100644
--- a/content/shell/browser/layout_test/layout_test_push_messaging_service.cc
+++ b/content/shell/browser/layout_test/layout_test_push_messaging_service.cc
@@ -16,15 +16,18 @@
 
 namespace {
 
-// P-256 public key made available to layout tests. Must be 32 bytes.
+// NIST P-256 public key made available to layout tests. Must be an uncompressed
+// point in accordance with SEC1 2.3.3.
 const uint8_t kTestP256Key[] = {
-  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B,
-  0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
-  0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F
+  0x04, 0x55, 0x52, 0x6A, 0xA5, 0x6E, 0x8E, 0xAA, 0x47, 0x97, 0x36, 0x10, 0xC1,
+  0x66, 0x3C, 0x1E, 0x65, 0xBF, 0xA1, 0x7B, 0xEE, 0x48, 0xC9, 0xC6, 0xBB, 0xBF,
+  0x02, 0x18, 0x53, 0x72, 0x1D, 0x0C, 0x7B, 0xA9, 0xE3, 0x11, 0xB7, 0x03, 0x52,
+  0x21, 0xD3, 0x71, 0x90, 0x13, 0xA8, 0xC1, 0xCF, 0xED, 0x20, 0xF7, 0x1F, 0xD1,
+  0x7F, 0xF2, 0x76, 0xB6, 0x01, 0x20, 0xD8, 0x35, 0xA5, 0xD9, 0x3C, 0x43, 0xFD
 };
 
-static_assert(sizeof(kTestP256Key) == 32,
-              "The fake public key must have the size of a real public key.");
+static_assert(sizeof(kTestP256Key) == 65,
+              "The fake public key must be a valid P-256 uncompressed point.");
 
 blink::WebPushPermissionStatus ToWebPushPermissionStatus(
     PermissionStatus status) {
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 2e0102e..5a35915 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -418,7 +418,7 @@
       "//testing/android/native_test:native_test_support",
     ]
 
-    use_launcher = false
+    use_default_launcher = false
   }
 
   if (is_mac) {
diff --git a/content/test/test_blink_web_unit_test_support.cc b/content/test/test_blink_web_unit_test_support.cc
index 6f060587..836e1aa 100644
--- a/content/test/test_blink_web_unit_test_support.cc
+++ b/content/test/test_blink_web_unit_test_support.cc
@@ -222,6 +222,8 @@
       return base::ASCIIToUTF16("<<ThisMonthLabel>>");
     case blink::WebLocalizedString::ThisWeekButtonLabel:
       return base::ASCIIToUTF16("<<ThisWeekLabel>>");
+    case blink::WebLocalizedString::ValidationValueMissing:
+      return base::ASCIIToUTF16("<<ValidationValueMissing>>");
     case blink::WebLocalizedString::WeekFormatTemplate:
       return base::ASCIIToUTF16("Week $2, $1");
     default:
diff --git a/content/zygote/zygote_linux.cc b/content/zygote/zygote_linux.cc
index 7d107a0..929527e 100644
--- a/content/zygote/zygote_linux.cc
+++ b/content/zygote/zygote_linux.cc
@@ -4,6 +4,7 @@
 
 #include "content/zygote/zygote_linux.h"
 
+#include <errno.h>
 #include <fcntl.h>
 #include <poll.h>
 #include <signal.h>
diff --git a/docs/android_test_instructions.md b/docs/android_test_instructions.md
index 522b237..008c7cca 100644
--- a/docs/android_test_instructions.md
+++ b/docs/android_test_instructions.md
@@ -51,6 +51,8 @@
 Use an emulator (i.e. Android Virtual Device, AVD): Enabling Intel's
 Virtualizaton support provides the fastest, most reliable emulator configuration
 available (i.e. x86 emulator with GPU acceleration and KVM support).
+Remember to build with `target_arch=ia32` for x86. Otherwise installing the APKs
+will fail with `INSTALL_FAILED_NO_MATCHING_ABIS`.
 
 1.  Enable Intel Virtualization support in the BIOS.
 
@@ -63,7 +65,7 @@
 3.  Install emulator deps:
 
     ```shell
-    build/android/install_emulator_deps.py --api-level=19
+    build/android/install_emulator_deps.py --api-level=23
     ```
 
     This script will download Android SDK and place it a directory called
@@ -76,7 +78,7 @@
     --abi.
 
     ```shell
-    build/android/avd.py --api-level=19
+    build/android/avd.py --api-level=23
     ```
 
     This script will attempt to use GPU emulation, so you must be running the
@@ -138,11 +140,11 @@
 
 ```shell
 # Resize userdata partition to be 1G
-resize2fs android_emulator_sdk/sdk/system-images/android-19/x86/userdata.img 1G
+resize2fs android_emulator_sdk/sdk/system-images/android-23/x86/userdata.img 1G
 
 # Set filesystem parameter to continue on errors; Android doesn't like some
 # things e2fsprogs does.
-tune2fs -e continue android_emulator_sdk/sdk/system-images/android-19/x86/userdata.img
+tune2fs -e continue android_emulator_sdk/sdk/system-images/android-23/x86/userdata.img
 ```
 
 ## Symbolizing Crashes
diff --git a/extensions/browser/updater/update_service_unittest.cc b/extensions/browser/updater/update_service_unittest.cc
index f570303..fe2aefe 100644
--- a/extensions/browser/updater/update_service_unittest.cc
+++ b/extensions/browser/updater/update_service_unittest.cc
@@ -46,6 +46,7 @@
     return false;
   }
   bool IsUpdating(const std::string& id) const override { return false; }
+  void Stop() override {}
 
  protected:
   friend class base::RefCounted<FakeUpdateClient>;
diff --git a/extensions/common/permissions/permissions_data.cc b/extensions/common/permissions/permissions_data.cc
index ea66b6cc..c904af7 100644
--- a/extensions/common/permissions/permissions_data.cc
+++ b/extensions/common/permissions/permissions_data.cc
@@ -23,7 +23,7 @@
 
 namespace {
 
-PermissionsData::PolicyDelegate* g_policy_delegate = NULL;
+PermissionsData::PolicyDelegate* g_policy_delegate = nullptr;
 
 class AutoLockOnValidThread {
  public:
@@ -149,7 +149,7 @@
           ? static_cast<const PermissionSet&>(PermissionSet())
           : *iter->second,
       permissions);
-  tab_specific_permissions_.set(tab_id, new_permissions.Pass());
+  tab_specific_permissions_[tab_id] = new_permissions.Pass();
 }
 
 void PermissionsData::ClearTabSpecificPermissions(int tab_id) const {
@@ -304,7 +304,7 @@
   runtime_lock_.AssertAcquired();
   TabPermissionsMap::const_iterator iter =
       tab_specific_permissions_.find(tab_id);
-  return (iter != tab_specific_permissions_.end()) ? iter->second : nullptr;
+  return iter != tab_specific_permissions_.end() ? iter->second.get() : nullptr;
 }
 
 bool PermissionsData::HasTabSpecificPermissionToExecuteScript(
diff --git a/extensions/common/permissions/permissions_data.h b/extensions/common/permissions/permissions_data.h
index 5de25c2..650c0ef4 100644
--- a/extensions/common/permissions/permissions_data.h
+++ b/extensions/common/permissions/permissions_data.h
@@ -9,8 +9,8 @@
 #include <string>
 #include <vector>
 
-#include "base/containers/scoped_ptr_map.h"
 #include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/strings/string16.h"
 #include "base/synchronization/lock.h"
 #include "base/threading/thread_checker.h"
@@ -45,8 +45,7 @@
                      // the given page.
   };
 
-  using TabPermissionsMap =
-      base::ScopedPtrMap<int, scoped_ptr<const PermissionSet>>;
+  using TabPermissionsMap = std::map<int, scoped_ptr<const PermissionSet>>;
 
   // Delegate class to allow different contexts (e.g. browser vs renderer) to
   // have control over policy decisions.
diff --git a/extensions/renderer/event_bindings.cc b/extensions/renderer/event_bindings.cc
index 95f758036..7544f74b 100644
--- a/extensions/renderer/event_bindings.cc
+++ b/extensions/renderer/event_bindings.cc
@@ -9,7 +9,6 @@
 
 #include "base/basictypes.h"
 #include "base/bind.h"
-#include "base/containers/scoped_ptr_map.h"
 #include "base/lazy_instance.h"
 #include "base/memory/scoped_ptr.h"
 #include "components/crx_file/id_util.h"
@@ -44,7 +43,7 @@
 // we transition between 0 and 1.
 using FilteredEventListenerKey = std::pair<std::string, std::string>;
 using FilteredEventListenerCounts =
-    base::ScopedPtrMap<FilteredEventListenerKey, scoped_ptr<ValueCounter>>;
+    std::map<FilteredEventListenerKey, scoped_ptr<ValueCounter>>;
 base::LazyInstance<FilteredEventListenerCounts> g_filtered_listener_counts =
     LAZY_INSTANCE_INITIALIZER;
 
@@ -124,7 +123,9 @@
   FilteredEventListenerCounts& all_counts = g_filtered_listener_counts.Get();
   FilteredEventListenerCounts::const_iterator counts = all_counts.find(key);
   if (counts == all_counts.end()) {
-    counts = all_counts.insert(key, make_scoped_ptr(new ValueCounter())).first;
+    counts = all_counts.insert(std::make_pair(
+                                   key, make_scoped_ptr(new ValueCounter())))
+                 .first;
   }
   return counts->second->Add(filter);
 }
diff --git a/media/media_options.gni b/media/media_options.gni
index 466b6c54..81469aa 100644
--- a/media/media_options.gni
+++ b/media/media_options.gni
@@ -3,6 +3,7 @@
 # found in the LICENSE file.
 
 import("//build/config/chromecast_build.gni")
+import("//build/config/headless_build.gni")
 
 declare_args() {
   # Allows distributions to link pulseaudio directly (DT_NEEDED) instead of
@@ -40,7 +41,7 @@
 
   # Alsa should be used on non-Android, non-Mac POSIX systems, and Chromecast
   # builds for desktop Linux.
-  if (is_posix && !is_android && !is_mac &&
+  if (is_posix && !is_headless && !is_android && !is_mac &&
       (!is_chromecast || target_cpu != "arm")) {
     use_alsa = true
     if (!use_cras) {
diff --git a/net/BUILD.gn b/net/BUILD.gn
index 6d9c9bc..6daea5a0 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -26,9 +26,9 @@
                           "scope",
                           [ "net.gypi" ])
 
-# Disable Kerberos on ChromeOS, iOS, and Chromecast, at least for now.
+# Disable Kerberos on ChromeOS, iOS, Chromecast and headless, at least for now.
 # It needs configuration (krb5.conf and so on).
-use_kerberos = !is_chromeos && !is_ios && !is_chromecast
+use_kerberos = !is_chromeos && !is_ios && !is_chromecast && !is_headless
 
 # The way the cache uses mmap() is inefficient on some Android devices. If
 # this flag is set, we hackily avoid using mmap() in the disk cache. We are
diff --git a/net/cert/ct_log_response_parser.cc b/net/cert/ct_log_response_parser.cc
index 0c006cc..628eef2 100644
--- a/net/cert/ct_log_response_parser.cc
+++ b/net/cert/ct_log_response_parser.cc
@@ -164,6 +164,13 @@
     return false;
   }
 
+  const base::DictionaryValue* dict_value = NULL;
+  if (!json_consistency_proof.GetAsDictionary(&dict_value) ||
+      !dict_value->HasKey("consistency")) {
+    DVLOG(1) << "Missing consistency field.";
+    return false;
+  }
+
   consistency_proof->reserve(parsed_proof.proof_nodes.size());
   for (std::string* proof_node : parsed_proof.proof_nodes) {
     consistency_proof->push_back(*proof_node);
diff --git a/net/cert/ct_log_response_parser_unittest.cc b/net/cert/ct_log_response_parser_unittest.cc
index d2c192e7..dc6b37e 100644
--- a/net/cert/ct_log_response_parser_unittest.cc
+++ b/net/cert/ct_log_response_parser_unittest.cc
@@ -126,6 +126,12 @@
   scoped_ptr<base::Value> not_a_string =
       ParseJson(std::string("{\"consistency\": [42, 16]}"));
   EXPECT_FALSE(FillConsistencyProof(*badly_encoded.get(), &output));
+
+  scoped_ptr<base::Value> missing_consistency = ParseJson(std::string("{}"));
+  EXPECT_FALSE(FillConsistencyProof(*missing_consistency.get(), &output));
+
+  scoped_ptr<base::Value> not_a_dict = ParseJson(std::string("[]"));
+  EXPECT_FALSE(FillConsistencyProof(*not_a_dict.get(), &output));
 }
 
 TEST(CTLogResponseParserTest, ParsesProofJsonWithExtraFields) {
diff --git a/net/spdy/hpack/hpack_encoder.cc b/net/spdy/hpack/hpack_encoder.cc
index 1059b6a9..59198a7 100644
--- a/net/spdy/hpack/hpack_encoder.cc
+++ b/net/spdy/hpack/hpack_encoder.cc
@@ -40,7 +40,8 @@
       // a map.
       found_cookie = true;
       CookieToCrumbs(header, &regular_headers);
-    } else if (header.first[0] == kPseudoHeaderPrefix) {
+    } else if (!header.first.empty() &&
+               header.first[0] == kPseudoHeaderPrefix) {
       DecomposeRepresentation(header, &pseudo_headers);
     } else {
       DecomposeRepresentation(header, &regular_headers);
diff --git a/remoting/android/java/src/org/chromium/chromoting/DesktopView.java b/remoting/android/java/src/org/chromium/chromoting/DesktopView.java
index 7d840a4b..d517f4a2 100644
--- a/remoting/android/java/src/org/chromium/chromoting/DesktopView.java
+++ b/remoting/android/java/src/org/chromium/chromoting/DesktopView.java
@@ -38,7 +38,7 @@
     private static final String TAG = "Chromoting";
 
     private final RenderData mRenderData;
-    private TouchInputHandler mInputHandler;
+    private TouchInputHandlerInterface mInputHandler;
 
     /** The parent Desktop activity. */
     private Desktop mDesktop;
@@ -130,7 +130,7 @@
         setFocusableInTouchMode(true);
 
         mRenderData = new RenderData();
-        mInputHandler = new TrackingInputHandler(this, context, mRenderData);
+        mInputHandler = new TouchInputHandler(this, context, mRenderData);
         mRepaintPending = false;
 
         getHolder().addCallback(this);
diff --git a/remoting/android/java/src/org/chromium/chromoting/TouchInputHandler.java b/remoting/android/java/src/org/chromium/chromoting/TouchInputHandler.java
index 190396f..421c58c 100644
--- a/remoting/android/java/src/org/chromium/chromoting/TouchInputHandler.java
+++ b/remoting/android/java/src/org/chromium/chromoting/TouchInputHandler.java
@@ -4,52 +4,488 @@
 
 package org.chromium.chromoting;
 
+import android.content.Context;
+import android.graphics.Matrix;
+import android.graphics.PointF;
 import android.graphics.Rect;
+import android.graphics.RectF;
+import android.view.GestureDetector;
 import android.view.MotionEvent;
+import android.view.ScaleGestureDetector;
+import android.widget.Scroller;
 
 /**
- * This interface allows multiple styles of touchscreen UI to be implemented and dynamically
- * switched. The DesktopView passes the low-level touchscreen events and other events via this
- * interface. The implementation recognizes and processes the touchscreen gestures, and then
- * performs actions on the DesktopView (such as panning/zooming the display, injecting input, or
- * showing/hiding UI elements). All methods are called on the main UI thread.
+ * This class implements the cursor-tracking behavior and gestures.
  */
-public interface TouchInputHandler {
-    // These constants must match those in the generated struct protoc::MouseEvent_MouseButton.
-    int BUTTON_UNDEFINED = 0;
-    int BUTTON_LEFT = 1;
-    int BUTTON_MIDDLE = 2;
-    int BUTTON_RIGHT = 3;
+public class TouchInputHandler implements TouchInputHandlerInterface {
+    /**
+     * Minimum change to the scaling factor to be recognized as a zoom gesture. Setting lower
+     * values here will result in more frequent canvas redraws during zooming.
+     */
+    private static final double MIN_ZOOM_DELTA = 0.05;
 
     /**
-     * Processes a touch event. This should be called by the View in its onTouchEvent() handler.
+     * Maximum allowed zoom level - see {@link #repositionImageWithZoom()}.
      */
-    boolean onTouchEvent(MotionEvent event);
+    private static final float MAX_ZOOM_FACTOR = 100.0f;
+
+    private DesktopViewInterface mViewer;
+    private final RenderData mRenderData;
+
+    private GestureDetector mScroller;
+    private ScaleGestureDetector mZoomer;
+    private TapGestureDetector mTapDetector;
+
+    /** Used to calculate the physics for flinging the cursor. */
+    private Scroller mFlingScroller;
+
+    /** Used to disambiguate a 2-finger gesture as a swipe or a pinch. */
+    private SwipePinchDetector mSwipePinchDetector;
 
     /**
-     * Called whenever the client display area changes size. The caller will handle repainting
-     * after this method returns.
+     * The current cursor position is stored here as floats, so that the desktop image can be
+     * positioned with sub-pixel accuracy, to give a smoother panning animation at high zoom levels.
      */
-    void onClientSizeChanged(int width, int height);
+    private PointF mCursorPosition;
 
     /**
-     * Called when the host screen size is changed. The caller will handle repainting after this
-     * method returns.
+     * Used for tracking swipe gestures. Only the Y-direction is needed for responding to swipe-up
+     * or swipe-down.
      */
-    void onHostSizeChanged(int width, int height);
+    private float mTotalMotionY = 0;
 
     /**
-     * Called when the visibility of the soft input method has changed.
-     * The innerBounds parameter describes the amount of space used by SystemUI along each edge of
-     * the screen.  The status bar is typically shown along the top, soft input UI is generally
-     * shown at the bottom.  The navigation bar is shown along the bottom for tablets and along the
-     * right side for phones in landscape mode (it shown at the bottom in portrait mode).
+     * Distance in pixels beyond which a motion gesture is considered to be a swipe. This is
+     * initialized using the Context passed into the ctor.
      */
-    void onSoftInputMethodVisibilityChanged(boolean inputMethodVisible, Rect innerBounds);
+    private float mSwipeThreshold;
+
+    /** Mouse-button currently held down, or BUTTON_UNDEFINED otherwise. */
+    private int mHeldButton = BUTTON_UNDEFINED;
 
     /**
-     * Whilst an animation is in progress, this method is called repeatedly until the animation is
-     * cancelled. After this method returns, the DesktopView will schedule a repaint.
+     * Set to true to prevent any further movement of the cursor, for example, when showing the
+     * keyboard to prevent the cursor wandering from the area where keystrokes should be sent.
      */
-    void processAnimation();
+    private boolean mSuppressCursorMovement = false;
+
+    /**
+     * Set to true to suppress the fling animation at the end of a gesture, for example, when
+     * dragging whilst a button is held down.
+     */
+    private boolean mSuppressFling = false;
+
+    /**
+     * Set to true when 3-finger swipe gesture is complete, so that further movement doesn't
+     * trigger more swipe actions.
+     */
+    private boolean mSwipeCompleted = false;
+
+    /**
+     * Represents the amount of vertical space in pixels used by the soft input device and
+     * accompanying system UI.
+     */
+    private int mInputMethodOffsetY = 0;
+
+    /**
+     * Represents the amount of horizontal space in pixels used by the soft input device and
+     * accompanying system UI.
+     */
+    private int mInputMethodOffsetX = 0;
+
+    public TouchInputHandler(DesktopViewInterface viewer, Context context, RenderData renderData) {
+        mViewer = viewer;
+        mRenderData = renderData;
+
+        GestureListener listener = new GestureListener();
+        mScroller = new GestureDetector(context, listener, null, false);
+
+        // If long-press is enabled, the gesture-detector will not emit any further onScroll
+        // notifications after the onLongPress notification. Since onScroll is being used for
+        // moving the cursor, it means that the cursor would become stuck if the finger were held
+        // down too long.
+        mScroller.setIsLongpressEnabled(false);
+
+        mZoomer = new ScaleGestureDetector(context, listener);
+        mTapDetector = new TapGestureDetector(context, listener);
+        mFlingScroller = new Scroller(context);
+        mSwipePinchDetector = new SwipePinchDetector(context);
+
+        mCursorPosition = new PointF();
+
+        // The threshold needs to be bigger than the ScaledTouchSlop used by the gesture-detectors,
+        // so that a gesture cannot be both a tap and a swipe. It also needs to be small enough so
+        // that intentional swipes are usually detected.
+        float density = context.getResources().getDisplayMetrics().density;
+        mSwipeThreshold = 40 * density;
+    }
+
+    /**
+     * Moves the mouse-cursor, injects a mouse-move event and repositions the image.
+     */
+    private void moveCursor(float newX, float newY) {
+        synchronized (mRenderData) {
+            // Constrain cursor to the image area.
+            if (newX < 0) newX = 0;
+            if (newY < 0) newY = 0;
+            if (newX > mRenderData.imageWidth) newX = mRenderData.imageWidth;
+            if (newY > mRenderData.imageHeight) newY = mRenderData.imageHeight;
+            mCursorPosition.set(newX, newY);
+            repositionImage();
+        }
+
+        mViewer.injectMouseEvent((int) newX, (int) newY, BUTTON_UNDEFINED, false);
+    }
+
+    /**
+     * Repositions the image by translating it (without affecting the zoom level) to place the
+     * cursor close to the center of the screen.
+     */
+    private void repositionImage() {
+        synchronized (mRenderData) {
+            float adjustedScreenWidth = mRenderData.screenWidth - mInputMethodOffsetX;
+            float adjustedScreenHeight = mRenderData.screenHeight - mInputMethodOffsetY;
+
+            // Get the current cursor position in screen coordinates.
+            float[] cursorScreen = {mCursorPosition.x, mCursorPosition.y};
+            mRenderData.transform.mapPoints(cursorScreen);
+
+            // Translate so the cursor is displayed in the middle of the screen.
+            mRenderData.transform.postTranslate(
+                    (float) adjustedScreenWidth / 2 - cursorScreen[0],
+                    (float) adjustedScreenHeight / 2 - cursorScreen[1]);
+
+            // Now the cursor is displayed in the middle of the screen, see if the image can be
+            // panned so that more of it is visible. The primary goal is to show as much of the
+            // image as possible. The secondary goal is to keep the cursor in the middle.
+
+            // Get the coordinates of the desktop rectangle (top-left/bottom-right corners) in
+            // screen coordinates. Order is: left, top, right, bottom.
+            RectF rectScreen = new RectF(0, 0, mRenderData.imageWidth, mRenderData.imageHeight);
+            mRenderData.transform.mapRect(rectScreen);
+
+            float leftDelta = rectScreen.left;
+            float rightDelta = rectScreen.right - mRenderData.screenWidth + mInputMethodOffsetX;
+            float topDelta = rectScreen.top;
+            float bottomDelta = rectScreen.bottom - mRenderData.screenHeight + mInputMethodOffsetY;
+            float xAdjust = 0;
+            float yAdjust = 0;
+
+            if (rectScreen.right - rectScreen.left < adjustedScreenWidth) {
+                // Image is narrower than the screen, so center it.
+                xAdjust = -(rightDelta + leftDelta) / 2;
+            } else if (leftDelta > 0 && rightDelta > 0) {
+                // Panning the image left will show more of it.
+                xAdjust = -Math.min(leftDelta, rightDelta);
+            } else if (leftDelta < 0 && rightDelta < 0) {
+                // Pan the image right.
+                xAdjust = Math.min(-leftDelta, -rightDelta);
+            }
+
+            // Apply similar logic for yAdjust.
+            if (rectScreen.bottom - rectScreen.top < adjustedScreenHeight) {
+                yAdjust = -(bottomDelta + topDelta) / 2;
+            } else if (topDelta > 0 && bottomDelta > 0) {
+                yAdjust = -Math.min(topDelta, bottomDelta);
+            } else if (topDelta < 0 && bottomDelta < 0) {
+                yAdjust = Math.min(-topDelta, -bottomDelta);
+            }
+
+            mRenderData.transform.postTranslate(xAdjust, yAdjust);
+        }
+        mViewer.transformationChanged();
+    }
+
+    /**
+     * Repositions the image by translating and zooming it, to keep the zoom level within sensible
+     * limits. The minimum zoom level is chosen to avoid black space around all 4 sides. The
+     * maximum zoom level is set arbitrarily, so that the user can zoom out again in a reasonable
+     * time, and to prevent arithmetic overflow problems from displaying the image.
+     */
+    private void repositionImageWithZoom() {
+        synchronized (mRenderData) {
+            // Avoid division by zero in case this gets called before the image size is initialized.
+            if (mRenderData.imageWidth == 0 || mRenderData.imageHeight == 0) {
+                return;
+            }
+
+            // Zoom out if the zoom level is too high.
+            float currentZoomLevel = mRenderData.transform.mapRadius(1.0f);
+            if (currentZoomLevel > MAX_ZOOM_FACTOR) {
+                mRenderData.transform.setScale(MAX_ZOOM_FACTOR, MAX_ZOOM_FACTOR);
+            }
+
+            // Get image size scaled to screen coordinates.
+            float[] imageSize = {mRenderData.imageWidth, mRenderData.imageHeight};
+            mRenderData.transform.mapVectors(imageSize);
+
+            if (imageSize[0] < mRenderData.screenWidth && imageSize[1] < mRenderData.screenHeight) {
+                // Displayed image is too small in both directions, so apply the minimum zoom
+                // level needed to fit either the width or height.
+                float scale = Math.min((float) mRenderData.screenWidth / mRenderData.imageWidth,
+                                       (float) mRenderData.screenHeight / mRenderData.imageHeight);
+                mRenderData.transform.setScale(scale, scale);
+            }
+
+            repositionImage();
+        }
+    }
+
+    /** Injects a button event using the current cursor location. */
+    private void injectButtonEvent(int button, boolean pressed) {
+        mViewer.injectMouseEvent((int) mCursorPosition.x, (int) mCursorPosition.y, button, pressed);
+    }
+
+    /** Processes a (multi-finger) swipe gesture. */
+    private boolean onSwipe() {
+        if (mTotalMotionY > mSwipeThreshold) {
+            // Swipe down occurred.
+            mViewer.showActionBar();
+        } else if (mTotalMotionY < -mSwipeThreshold) {
+            // Swipe up occurred.
+            mViewer.showKeyboard();
+        } else {
+            return false;
+        }
+
+        mSuppressCursorMovement = true;
+        mSuppressFling = true;
+        mSwipeCompleted = true;
+        return true;
+    }
+
+    /** Injects a button-up event if the button is currently held down (during a drag event). */
+    private void releaseAnyHeldButton() {
+        if (mHeldButton != BUTTON_UNDEFINED) {
+            injectButtonEvent(mHeldButton, false);
+            mHeldButton = BUTTON_UNDEFINED;
+        }
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        // Avoid short-circuit logic evaluation - ensure all gesture detectors see all events so
+        // that they generate correct notifications.
+        boolean handled = mScroller.onTouchEvent(event);
+        handled |= mZoomer.onTouchEvent(event);
+        handled |= mTapDetector.onTouchEvent(event);
+        mSwipePinchDetector.onTouchEvent(event);
+
+        switch (event.getActionMasked()) {
+            case MotionEvent.ACTION_DOWN:
+                mViewer.setAnimationEnabled(false);
+                mSuppressCursorMovement = false;
+                mSuppressFling = false;
+                mSwipeCompleted = false;
+                break;
+
+            case MotionEvent.ACTION_POINTER_DOWN:
+                mTotalMotionY = 0;
+                break;
+
+            case MotionEvent.ACTION_UP:
+                releaseAnyHeldButton();
+                break;
+
+            default:
+                break;
+        }
+        return handled;
+    }
+
+    @Override
+    public void onClientSizeChanged(int width, int height) {
+        repositionImageWithZoom();
+    }
+
+    @Override
+    public void onHostSizeChanged(int width, int height) {
+        moveCursor((float) width / 2, (float) height / 2);
+        repositionImageWithZoom();
+    }
+
+    @Override
+    public void onSoftInputMethodVisibilityChanged(boolean inputMethodVisible, Rect bounds) {
+        synchronized (mRenderData) {
+            if (inputMethodVisible) {
+                mInputMethodOffsetY = mRenderData.screenHeight - bounds.bottom;
+                mInputMethodOffsetX = mRenderData.screenWidth - bounds.right;
+            } else {
+                mInputMethodOffsetY = 0;
+                mInputMethodOffsetX = 0;
+            }
+        }
+
+        repositionImageWithZoom();
+    }
+
+    @Override
+    public void processAnimation() {
+        int previousX = mFlingScroller.getCurrX();
+        int previousY = mFlingScroller.getCurrY();
+        if (!mFlingScroller.computeScrollOffset()) {
+            mViewer.setAnimationEnabled(false);
+            return;
+        }
+        int deltaX = mFlingScroller.getCurrX() - previousX;
+        int deltaY = mFlingScroller.getCurrY() - previousY;
+        float[] delta = {deltaX, deltaY};
+        synchronized (mRenderData) {
+            Matrix canvasToImage = new Matrix();
+            mRenderData.transform.invert(canvasToImage);
+            canvasToImage.mapVectors(delta);
+        }
+
+        moveCursor(mCursorPosition.x + delta[0], mCursorPosition.y + delta[1]);
+    }
+
+    /** Responds to touch events filtered by the gesture detectors. */
+    private class GestureListener extends GestureDetector.SimpleOnGestureListener
+            implements ScaleGestureDetector.OnScaleGestureListener,
+                       TapGestureDetector.OnTapListener {
+        /**
+         * Called when the user drags one or more fingers across the touchscreen.
+         */
+        @Override
+        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
+            int pointerCount = e2.getPointerCount();
+            if (pointerCount == 3 && !mSwipeCompleted) {
+                // Note that distance values are reversed. For example, dragging a finger in the
+                // direction of increasing Y coordinate (downwards) results in distanceY being
+                // negative.
+                mTotalMotionY -= distanceY;
+                return onSwipe();
+            }
+
+            if (pointerCount == 2 && mSwipePinchDetector.isSwiping()) {
+                mViewer.injectMouseWheelDeltaEvent(-(int) distanceX, -(int) distanceY);
+
+                // Prevent the cursor being moved or flung by the gesture.
+                mSuppressCursorMovement = true;
+                return true;
+            }
+
+            if (pointerCount != 1 || mSuppressCursorMovement) {
+                return false;
+            }
+
+            float[] delta = {distanceX, distanceY};
+            synchronized (mRenderData) {
+                Matrix canvasToImage = new Matrix();
+                mRenderData.transform.invert(canvasToImage);
+                canvasToImage.mapVectors(delta);
+            }
+
+            moveCursor(mCursorPosition.x - delta[0], mCursorPosition.y - delta[1]);
+            return true;
+        }
+
+        /**
+         * Called when a fling gesture is recognized.
+         */
+        @Override
+        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
+            // If cursor movement is suppressed, fling also needs to be suppressed, as the
+            // gesture-detector will still generate onFling() notifications based on movement of
+            // the fingers, which would result in unwanted cursor movement.
+            if (mSuppressCursorMovement || mSuppressFling) {
+                return false;
+            }
+
+            // The fling physics calculation is based on screen coordinates, so that it will
+            // behave consistently at different zoom levels (and will work nicely at high zoom
+            // levels, since |mFlingScroller| outputs integer coordinates). However, the desktop
+            // will usually be panned as the cursor is moved across the desktop, which means the
+            // transformation mapping from screen to desktop coordinates will change. To deal with
+            // this, the cursor movement is computed from relative coordinate changes from
+            // |mFlingScroller|. This means the fling can be started at (0, 0) with no bounding
+            // constraints - the cursor is already constrained by the desktop size.
+            mFlingScroller.fling(0, 0, (int) velocityX, (int) velocityY, Integer.MIN_VALUE,
+                    Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE);
+            // Initialize the scroller's current offset coordinates, since they are used for
+            // calculating the delta values.
+            mFlingScroller.computeScrollOffset();
+            mViewer.setAnimationEnabled(true);
+            return true;
+        }
+
+        /** Called when the user is in the process of pinch-zooming. */
+        @Override
+        public boolean onScale(ScaleGestureDetector detector) {
+            if (!mSwipePinchDetector.isPinching()) {
+                return false;
+            }
+
+            if (Math.abs(detector.getScaleFactor() - 1) < MIN_ZOOM_DELTA) {
+                return false;
+            }
+
+            float scaleFactor = detector.getScaleFactor();
+            synchronized (mRenderData) {
+                mRenderData.transform.postScale(
+                        scaleFactor, scaleFactor, detector.getFocusX(), detector.getFocusY());
+            }
+            repositionImageWithZoom();
+            return true;
+        }
+
+        /** Called whenever a gesture starts. Always accepts the gesture so it isn't ignored. */
+        @Override
+        public boolean onDown(MotionEvent e) {
+            return true;
+        }
+
+        /**
+         * Called when the user starts to zoom. Always accepts the zoom so that
+         * onScale() can decide whether to respond to it.
+         */
+        @Override
+        public boolean onScaleBegin(ScaleGestureDetector detector) {
+            return true;
+        }
+
+        /** Called when the user is done zooming. Defers to onScale()'s judgement. */
+        @Override
+        public void onScaleEnd(ScaleGestureDetector detector) {
+            onScale(detector);
+        }
+
+        /** Maps the number of fingers in a tap or long-press gesture to a mouse-button. */
+        private int mouseButtonFromPointerCount(int pointerCount) {
+            switch (pointerCount) {
+                case 1:
+                    return BUTTON_LEFT;
+                case 2:
+                    return BUTTON_RIGHT;
+                case 3:
+                    return BUTTON_MIDDLE;
+                default:
+                    return BUTTON_UNDEFINED;
+            }
+        }
+
+        /** Called when the user taps the screen with one or more fingers. */
+        @Override
+        public boolean onTap(int pointerCount) {
+            int button = mouseButtonFromPointerCount(pointerCount);
+            if (button == BUTTON_UNDEFINED) {
+                return false;
+            } else {
+                injectButtonEvent(button, true);
+                injectButtonEvent(button, false);
+                return true;
+            }
+        }
+
+        /** Called when a long-press is triggered for one or more fingers. */
+        @Override
+        public void onLongPress(int pointerCount) {
+            mHeldButton = mouseButtonFromPointerCount(pointerCount);
+            if (mHeldButton != BUTTON_UNDEFINED) {
+                injectButtonEvent(mHeldButton, true);
+                mViewer.showLongPressFeedback();
+                mSuppressFling = true;
+            }
+        }
+    }
 }
diff --git a/remoting/android/java/src/org/chromium/chromoting/TouchInputHandlerInterface.java b/remoting/android/java/src/org/chromium/chromoting/TouchInputHandlerInterface.java
new file mode 100644
index 0000000..8bba3287
--- /dev/null
+++ b/remoting/android/java/src/org/chromium/chromoting/TouchInputHandlerInterface.java
@@ -0,0 +1,55 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chromoting;
+
+import android.graphics.Rect;
+import android.view.MotionEvent;
+
+/**
+ * This interface allows multiple styles of touchscreen UI to be implemented and dynamically
+ * switched. The DesktopView passes the low-level touchscreen events and other events via this
+ * interface. The implementation recognizes and processes the touchscreen gestures, and then
+ * performs actions on the DesktopView (such as panning/zooming the display, injecting input, or
+ * showing/hiding UI elements). All methods are called on the main UI thread.
+ */
+public interface TouchInputHandlerInterface {
+    // These constants must match those in the generated struct protoc::MouseEvent_MouseButton.
+    int BUTTON_UNDEFINED = 0;
+    int BUTTON_LEFT = 1;
+    int BUTTON_MIDDLE = 2;
+    int BUTTON_RIGHT = 3;
+
+    /**
+     * Processes a touch event. This should be called by the View in its onTouchEvent() handler.
+     */
+    boolean onTouchEvent(MotionEvent event);
+
+    /**
+     * Called whenever the client display area changes size. The caller will handle repainting
+     * after this method returns.
+     */
+    void onClientSizeChanged(int width, int height);
+
+    /**
+     * Called when the host screen size is changed. The caller will handle repainting after this
+     * method returns.
+     */
+    void onHostSizeChanged(int width, int height);
+
+    /**
+     * Called when the visibility of the soft input method has changed.
+     * The innerBounds parameter describes the amount of space used by SystemUI along each edge of
+     * the screen.  The status bar is typically shown along the top, soft input UI is generally
+     * shown at the bottom.  The navigation bar is shown along the bottom for tablets and along the
+     * right side for phones in landscape mode (it shown at the bottom in portrait mode).
+     */
+    void onSoftInputMethodVisibilityChanged(boolean inputMethodVisible, Rect innerBounds);
+
+    /**
+     * Whilst an animation is in progress, this method is called repeatedly until the animation is
+     * cancelled. After this method returns, the DesktopView will schedule a repaint.
+     */
+    void processAnimation();
+}
diff --git a/remoting/android/java/src/org/chromium/chromoting/TrackingInputHandler.java b/remoting/android/java/src/org/chromium/chromoting/TrackingInputHandler.java
deleted file mode 100644
index 5558e57..0000000
--- a/remoting/android/java/src/org/chromium/chromoting/TrackingInputHandler.java
+++ /dev/null
@@ -1,492 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chromoting;
-
-import android.content.Context;
-import android.graphics.Matrix;
-import android.graphics.PointF;
-import android.graphics.Rect;
-import android.graphics.RectF;
-import android.view.GestureDetector;
-import android.view.MotionEvent;
-import android.view.ScaleGestureDetector;
-import android.widget.Scroller;
-
-/**
- * This class implements the cursor-tracking behavior and gestures.
- */
-public class TrackingInputHandler implements TouchInputHandler {
-    /**
-     * Minimum change to the scaling factor to be recognized as a zoom gesture. Setting lower
-     * values here will result in more frequent canvas redraws during zooming.
-     */
-    private static final double MIN_ZOOM_DELTA = 0.05;
-
-    /**
-     * Maximum allowed zoom level - see {@link #repositionImageWithZoom()}.
-     */
-    private static final float MAX_ZOOM_FACTOR = 100.0f;
-
-    private DesktopViewInterface mViewer;
-    private final RenderData mRenderData;
-
-    private GestureDetector mScroller;
-    private ScaleGestureDetector mZoomer;
-    private TapGestureDetector mTapDetector;
-
-    /** Used to calculate the physics for flinging the cursor. */
-    private Scroller mFlingScroller;
-
-    /** Used to disambiguate a 2-finger gesture as a swipe or a pinch. */
-    private SwipePinchDetector mSwipePinchDetector;
-
-    /**
-     * The current cursor position is stored here as floats, so that the desktop image can be
-     * positioned with sub-pixel accuracy, to give a smoother panning animation at high zoom levels.
-     */
-    private PointF mCursorPosition;
-
-    /**
-     * Used for tracking swipe gestures. Only the Y-direction is needed for responding to swipe-up
-     * or swipe-down.
-     */
-    private float mTotalMotionY = 0;
-
-    /**
-     * Distance in pixels beyond which a motion gesture is considered to be a swipe. This is
-     * initialized using the Context passed into the ctor.
-     */
-    private float mSwipeThreshold;
-
-    /** Mouse-button currently held down, or BUTTON_UNDEFINED otherwise. */
-    private int mHeldButton = BUTTON_UNDEFINED;
-
-    /**
-     * Set to true to prevent any further movement of the cursor, for example, when showing the
-     * keyboard to prevent the cursor wandering from the area where keystrokes should be sent.
-     */
-    private boolean mSuppressCursorMovement = false;
-
-    /**
-     * Set to true to suppress the fling animation at the end of a gesture, for example, when
-     * dragging whilst a button is held down.
-     */
-    private boolean mSuppressFling = false;
-
-    /**
-     * Set to true when 3-finger swipe gesture is complete, so that further movement doesn't
-     * trigger more swipe actions.
-     */
-    private boolean mSwipeCompleted = false;
-
-    /**
-     * Represents the amount of vertical space in pixels used by the soft input device and
-     * accompanying system UI.
-     */
-    private int mInputMethodOffsetY = 0;
-
-    /**
-     * Represents the amount of horizontal space in pixels used by the soft input device and
-     * accompanying system UI.
-     */
-    private int mInputMethodOffsetX = 0;
-
-    public TrackingInputHandler(DesktopViewInterface viewer, Context context,
-                                RenderData renderData) {
-        mViewer = viewer;
-        mRenderData = renderData;
-
-        GestureListener listener = new GestureListener();
-        mScroller = new GestureDetector(context, listener, null, false);
-
-        // If long-press is enabled, the gesture-detector will not emit any further onScroll
-        // notifications after the onLongPress notification. Since onScroll is being used for
-        // moving the cursor, it means that the cursor would become stuck if the finger were held
-        // down too long.
-        mScroller.setIsLongpressEnabled(false);
-
-        mZoomer = new ScaleGestureDetector(context, listener);
-        mTapDetector = new TapGestureDetector(context, listener);
-        mFlingScroller = new Scroller(context);
-        mSwipePinchDetector = new SwipePinchDetector(context);
-
-        mCursorPosition = new PointF();
-
-        // The threshold needs to be bigger than the ScaledTouchSlop used by the gesture-detectors,
-        // so that a gesture cannot be both a tap and a swipe. It also needs to be small enough so
-        // that intentional swipes are usually detected.
-        float density = context.getResources().getDisplayMetrics().density;
-        mSwipeThreshold = 40 * density;
-    }
-
-    /**
-     * Moves the mouse-cursor, injects a mouse-move event and repositions the image.
-     */
-    private void moveCursor(float newX, float newY) {
-        synchronized (mRenderData) {
-            // Constrain cursor to the image area.
-            if (newX < 0) newX = 0;
-            if (newY < 0) newY = 0;
-            if (newX > mRenderData.imageWidth) newX = mRenderData.imageWidth;
-            if (newY > mRenderData.imageHeight) newY = mRenderData.imageHeight;
-            mCursorPosition.set(newX, newY);
-            repositionImage();
-        }
-
-        mViewer.injectMouseEvent((int) newX, (int) newY, BUTTON_UNDEFINED, false);
-    }
-
-    /**
-     * Repositions the image by translating it (without affecting the zoom level) to place the
-     * cursor close to the center of the screen.
-     */
-    private void repositionImage() {
-        synchronized (mRenderData) {
-            float adjustedScreenWidth = mRenderData.screenWidth - mInputMethodOffsetX;
-            float adjustedScreenHeight = mRenderData.screenHeight - mInputMethodOffsetY;
-
-            // Get the current cursor position in screen coordinates.
-            float[] cursorScreen = {mCursorPosition.x, mCursorPosition.y};
-            mRenderData.transform.mapPoints(cursorScreen);
-
-            // Translate so the cursor is displayed in the middle of the screen.
-            mRenderData.transform.postTranslate(
-                    (float) adjustedScreenWidth / 2 - cursorScreen[0],
-                    (float) adjustedScreenHeight / 2 - cursorScreen[1]);
-
-            // Now the cursor is displayed in the middle of the screen, see if the image can be
-            // panned so that more of it is visible. The primary goal is to show as much of the
-            // image as possible. The secondary goal is to keep the cursor in the middle.
-
-            // Get the coordinates of the desktop rectangle (top-left/bottom-right corners) in
-            // screen coordinates. Order is: left, top, right, bottom.
-            RectF rectScreen = new RectF(0, 0, mRenderData.imageWidth, mRenderData.imageHeight);
-            mRenderData.transform.mapRect(rectScreen);
-
-            float leftDelta = rectScreen.left;
-            float rightDelta = rectScreen.right - mRenderData.screenWidth + mInputMethodOffsetX;
-            float topDelta = rectScreen.top;
-            float bottomDelta = rectScreen.bottom - mRenderData.screenHeight + mInputMethodOffsetY;
-            float xAdjust = 0;
-            float yAdjust = 0;
-
-            if (rectScreen.right - rectScreen.left < adjustedScreenWidth) {
-                // Image is narrower than the screen, so center it.
-                xAdjust = -(rightDelta + leftDelta) / 2;
-            } else if (leftDelta > 0 && rightDelta > 0) {
-                // Panning the image left will show more of it.
-                xAdjust = -Math.min(leftDelta, rightDelta);
-            } else if (leftDelta < 0 && rightDelta < 0) {
-                // Pan the image right.
-                xAdjust = Math.min(-leftDelta, -rightDelta);
-            }
-
-            // Apply similar logic for yAdjust.
-            if (rectScreen.bottom - rectScreen.top < adjustedScreenHeight) {
-                yAdjust = -(bottomDelta + topDelta) / 2;
-            } else if (topDelta > 0 && bottomDelta > 0) {
-                yAdjust = -Math.min(topDelta, bottomDelta);
-            } else if (topDelta < 0 && bottomDelta < 0) {
-                yAdjust = Math.min(-topDelta, -bottomDelta);
-            }
-
-            mRenderData.transform.postTranslate(xAdjust, yAdjust);
-        }
-        mViewer.transformationChanged();
-    }
-
-    /**
-     * Repositions the image by translating and zooming it, to keep the zoom level within sensible
-     * limits. The minimum zoom level is chosen to avoid black space around all 4 sides. The
-     * maximum zoom level is set arbitrarily, so that the user can zoom out again in a reasonable
-     * time, and to prevent arithmetic overflow problems from displaying the image.
-     */
-    private void repositionImageWithZoom() {
-        synchronized (mRenderData) {
-            // Avoid division by zero in case this gets called before the image size is initialized.
-            if (mRenderData.imageWidth == 0 || mRenderData.imageHeight == 0) {
-                return;
-            }
-
-            // Zoom out if the zoom level is too high.
-            float currentZoomLevel = mRenderData.transform.mapRadius(1.0f);
-            if (currentZoomLevel > MAX_ZOOM_FACTOR) {
-                mRenderData.transform.setScale(MAX_ZOOM_FACTOR, MAX_ZOOM_FACTOR);
-            }
-
-            // Get image size scaled to screen coordinates.
-            float[] imageSize = {mRenderData.imageWidth, mRenderData.imageHeight};
-            mRenderData.transform.mapVectors(imageSize);
-
-            if (imageSize[0] < mRenderData.screenWidth && imageSize[1] < mRenderData.screenHeight) {
-                // Displayed image is too small in both directions, so apply the minimum zoom
-                // level needed to fit either the width or height.
-                float scale = Math.min((float) mRenderData.screenWidth / mRenderData.imageWidth,
-                                       (float) mRenderData.screenHeight / mRenderData.imageHeight);
-                mRenderData.transform.setScale(scale, scale);
-            }
-
-            repositionImage();
-        }
-    }
-
-    /** Injects a button event using the current cursor location. */
-    private void injectButtonEvent(int button, boolean pressed) {
-        mViewer.injectMouseEvent((int) mCursorPosition.x, (int) mCursorPosition.y, button, pressed);
-    }
-
-    /** Processes a (multi-finger) swipe gesture. */
-    private boolean onSwipe() {
-        if (mTotalMotionY > mSwipeThreshold) {
-            // Swipe down occurred.
-            mViewer.showActionBar();
-        } else if (mTotalMotionY < -mSwipeThreshold) {
-            // Swipe up occurred.
-            mViewer.showKeyboard();
-        } else {
-            return false;
-        }
-
-        mSuppressCursorMovement = true;
-        mSuppressFling = true;
-        mSwipeCompleted = true;
-        return true;
-    }
-
-    /** Injects a button-up event if the button is currently held down (during a drag event). */
-    private void releaseAnyHeldButton() {
-        if (mHeldButton != BUTTON_UNDEFINED) {
-            injectButtonEvent(mHeldButton, false);
-            mHeldButton = BUTTON_UNDEFINED;
-        }
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent event) {
-        // Avoid short-circuit logic evaluation - ensure all gesture detectors see all events so
-        // that they generate correct notifications.
-        boolean handled = mScroller.onTouchEvent(event);
-        handled |= mZoomer.onTouchEvent(event);
-        handled |= mTapDetector.onTouchEvent(event);
-        mSwipePinchDetector.onTouchEvent(event);
-
-        switch (event.getActionMasked()) {
-            case MotionEvent.ACTION_DOWN:
-                mViewer.setAnimationEnabled(false);
-                mSuppressCursorMovement = false;
-                mSuppressFling = false;
-                mSwipeCompleted = false;
-                break;
-
-            case MotionEvent.ACTION_POINTER_DOWN:
-                mTotalMotionY = 0;
-                break;
-
-            case MotionEvent.ACTION_UP:
-                releaseAnyHeldButton();
-                break;
-
-            default:
-                break;
-        }
-        return handled;
-    }
-
-    @Override
-    public void onClientSizeChanged(int width, int height) {
-        repositionImageWithZoom();
-    }
-
-    @Override
-    public void onHostSizeChanged(int width, int height) {
-        moveCursor((float) width / 2, (float) height / 2);
-        repositionImageWithZoom();
-    }
-
-    @Override
-    public void onSoftInputMethodVisibilityChanged(boolean inputMethodVisible, Rect bounds) {
-        synchronized (mRenderData) {
-            if (inputMethodVisible) {
-                mInputMethodOffsetY = mRenderData.screenHeight - bounds.bottom;
-                mInputMethodOffsetX = mRenderData.screenWidth - bounds.right;
-            } else {
-                mInputMethodOffsetY = 0;
-                mInputMethodOffsetX = 0;
-            }
-        }
-
-        repositionImageWithZoom();
-    }
-
-    @Override
-    public void processAnimation() {
-        int previousX = mFlingScroller.getCurrX();
-        int previousY = mFlingScroller.getCurrY();
-        if (!mFlingScroller.computeScrollOffset()) {
-            mViewer.setAnimationEnabled(false);
-            return;
-        }
-        int deltaX = mFlingScroller.getCurrX() - previousX;
-        int deltaY = mFlingScroller.getCurrY() - previousY;
-        float[] delta = {deltaX, deltaY};
-        synchronized (mRenderData) {
-            Matrix canvasToImage = new Matrix();
-            mRenderData.transform.invert(canvasToImage);
-            canvasToImage.mapVectors(delta);
-        }
-
-        moveCursor(mCursorPosition.x + delta[0], mCursorPosition.y + delta[1]);
-    }
-
-    /** Responds to touch events filtered by the gesture detectors. */
-    private class GestureListener extends GestureDetector.SimpleOnGestureListener
-            implements ScaleGestureDetector.OnScaleGestureListener,
-                       TapGestureDetector.OnTapListener {
-        /**
-         * Called when the user drags one or more fingers across the touchscreen.
-         */
-        @Override
-        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
-            int pointerCount = e2.getPointerCount();
-            if (pointerCount == 3 && !mSwipeCompleted) {
-                // Note that distance values are reversed. For example, dragging a finger in the
-                // direction of increasing Y coordinate (downwards) results in distanceY being
-                // negative.
-                mTotalMotionY -= distanceY;
-                return onSwipe();
-            }
-
-            if (pointerCount == 2 && mSwipePinchDetector.isSwiping()) {
-                mViewer.injectMouseWheelDeltaEvent(-(int) distanceX, -(int) distanceY);
-
-                // Prevent the cursor being moved or flung by the gesture.
-                mSuppressCursorMovement = true;
-                return true;
-            }
-
-            if (pointerCount != 1 || mSuppressCursorMovement) {
-                return false;
-            }
-
-            float[] delta = {distanceX, distanceY};
-            synchronized (mRenderData) {
-                Matrix canvasToImage = new Matrix();
-                mRenderData.transform.invert(canvasToImage);
-                canvasToImage.mapVectors(delta);
-            }
-
-            moveCursor(mCursorPosition.x - delta[0], mCursorPosition.y - delta[1]);
-            return true;
-        }
-
-        /**
-         * Called when a fling gesture is recognized.
-         */
-        @Override
-        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
-            // If cursor movement is suppressed, fling also needs to be suppressed, as the
-            // gesture-detector will still generate onFling() notifications based on movement of
-            // the fingers, which would result in unwanted cursor movement.
-            if (mSuppressCursorMovement || mSuppressFling) {
-                return false;
-            }
-
-            // The fling physics calculation is based on screen coordinates, so that it will
-            // behave consistently at different zoom levels (and will work nicely at high zoom
-            // levels, since |mFlingScroller| outputs integer coordinates). However, the desktop
-            // will usually be panned as the cursor is moved across the desktop, which means the
-            // transformation mapping from screen to desktop coordinates will change. To deal with
-            // this, the cursor movement is computed from relative coordinate changes from
-            // |mFlingScroller|. This means the fling can be started at (0, 0) with no bounding
-            // constraints - the cursor is already constrained by the desktop size.
-            mFlingScroller.fling(0, 0, (int) velocityX, (int) velocityY, Integer.MIN_VALUE,
-                    Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE);
-            // Initialize the scroller's current offset coordinates, since they are used for
-            // calculating the delta values.
-            mFlingScroller.computeScrollOffset();
-            mViewer.setAnimationEnabled(true);
-            return true;
-        }
-
-        /** Called when the user is in the process of pinch-zooming. */
-        @Override
-        public boolean onScale(ScaleGestureDetector detector) {
-            if (!mSwipePinchDetector.isPinching()) {
-                return false;
-            }
-
-            if (Math.abs(detector.getScaleFactor() - 1) < MIN_ZOOM_DELTA) {
-                return false;
-            }
-
-            float scaleFactor = detector.getScaleFactor();
-            synchronized (mRenderData) {
-                mRenderData.transform.postScale(
-                        scaleFactor, scaleFactor, detector.getFocusX(), detector.getFocusY());
-            }
-            repositionImageWithZoom();
-            return true;
-        }
-
-        /** Called whenever a gesture starts. Always accepts the gesture so it isn't ignored. */
-        @Override
-        public boolean onDown(MotionEvent e) {
-            return true;
-        }
-
-        /**
-         * Called when the user starts to zoom. Always accepts the zoom so that
-         * onScale() can decide whether to respond to it.
-         */
-        @Override
-        public boolean onScaleBegin(ScaleGestureDetector detector) {
-            return true;
-        }
-
-        /** Called when the user is done zooming. Defers to onScale()'s judgement. */
-        @Override
-        public void onScaleEnd(ScaleGestureDetector detector) {
-            onScale(detector);
-        }
-
-        /** Maps the number of fingers in a tap or long-press gesture to a mouse-button. */
-        private int mouseButtonFromPointerCount(int pointerCount) {
-            switch (pointerCount) {
-                case 1:
-                    return BUTTON_LEFT;
-                case 2:
-                    return BUTTON_RIGHT;
-                case 3:
-                    return BUTTON_MIDDLE;
-                default:
-                    return BUTTON_UNDEFINED;
-            }
-        }
-
-        /** Called when the user taps the screen with one or more fingers. */
-        @Override
-        public boolean onTap(int pointerCount) {
-            int button = mouseButtonFromPointerCount(pointerCount);
-            if (button == BUTTON_UNDEFINED) {
-                return false;
-            } else {
-                injectButtonEvent(button, true);
-                injectButtonEvent(button, false);
-                return true;
-            }
-        }
-
-        /** Called when a long-press is triggered for one or more fingers. */
-        @Override
-        public void onLongPress(int pointerCount) {
-            mHeldButton = mouseButtonFromPointerCount(pointerCount);
-            if (mHeldButton != BUTTON_UNDEFINED) {
-                injectButtonEvent(mHeldButton, true);
-                mViewer.showLongPressFeedback();
-                mSuppressFling = true;
-            }
-        }
-    }
-}
diff --git a/skia/BUILD.gn b/skia/BUILD.gn
index f3fd404..e6fc643 100644
--- a/skia/BUILD.gn
+++ b/skia/BUILD.gn
@@ -520,7 +520,7 @@
       "//build/config/compiler:no_chromium_code",
     ]
   }
-  source_set("skia_opts_sse4") {
+  source_set("skia_opts_sse41") {
     sources = gypi_skia_opts.sse41_sources
     if (!is_win || is_clang) {
       cflags = [ "-msse4.1" ]
@@ -536,6 +536,54 @@
       "//build/config/compiler:no_chromium_code",
     ]
   }
+  source_set("skia_opts_sse42") {
+    sources = gypi_skia_opts.sse42_sources
+    if (!is_win || is_clang) {
+      cflags = [ "-msse4.2" ]
+    }
+    if (is_win) {
+      defines = [ "SK_CPU_SSE_LEVEL=42" ]
+    }
+    visibility = [ ":skia_opts" ]
+    configs -= [ "//build/config/compiler:chromium_code" ]
+    configs += [
+      ":skia_config",
+      ":skia_library_config",
+      "//build/config/compiler:no_chromium_code",
+    ]
+  }
+  source_set("skia_opts_avx") {
+    sources = gypi_skia_opts.avx_sources
+    if (!is_win || is_clang) {
+      cflags = [ "-mavx" ]
+    }
+    if (is_win) {
+      cflags = [ "/arch:AVX" ]
+    }
+    visibility = [ ":skia_opts" ]
+    configs -= [ "//build/config/compiler:chromium_code" ]
+    configs += [
+      ":skia_config",
+      ":skia_library_config",
+      "//build/config/compiler:no_chromium_code",
+    ]
+  }
+  source_set("skia_opts_avx2") {
+    sources = gypi_skia_opts.avx2_sources
+    if (!is_win || is_clang) {
+      cflags = [ "-mavx2" ]
+    }
+    if (is_win) {
+      cflags = [ "/arch:AVX2" ]
+    }
+    visibility = [ ":skia_opts" ]
+    configs -= [ "//build/config/compiler:chromium_code" ]
+    configs += [
+      ":skia_config",
+      ":skia_library_config",
+      "//build/config/compiler:no_chromium_code",
+    ]
+  }
 }
 source_set("skia_opts") {
   cflags = []
@@ -549,7 +597,10 @@
     sources = gypi_skia_opts.sse2_sources
     deps += [
       ":skia_opts_sse3",
-      ":skia_opts_sse4",
+      ":skia_opts_sse41",
+      ":skia_opts_sse42",
+      ":skia_opts_avx",
+      ":skia_opts_avx2",
     ]
   } else if (current_cpu == "arm") {
     # The assembly uses the frame pointer register (r7 in Thumb/r11 in
diff --git a/skia/skia_library_opts.gyp b/skia/skia_library_opts.gyp
index 85fdcb3..e1627e0 100644
--- a/skia/skia_library_opts.gyp
+++ b/skia/skia_library_opts.gyp
@@ -29,7 +29,7 @@
       'target_name': 'skia_opts',
       'type': 'static_library',
       # The optimize: 'max' scattered throughout are particularly
-      # important when compiled by MSVC 2013, which seems 
+      # important when compiled by MSVC 2013, which seems
       # to mis-link-time-compile code that's built with
       # different optimization levels. http://crbug.com/543583
       'variables': {
@@ -55,6 +55,9 @@
           'dependencies': [
             'skia_opts_ssse3',
             'skia_opts_sse41',
+            'skia_opts_sse42',
+            'skia_opts_avx',
+            'skia_opts_avx2',
           ],
         }],
         [ 'target_arch == "arm"', {
@@ -110,7 +113,7 @@
       'target_name': 'skia_opts_ssse3',
       'type': 'static_library',
       # The optimize: 'max' scattered throughout are particularly
-      # important when compiled by MSVC 2013, which seems 
+      # important when compiled by MSVC 2013, which seems
       # to mis-link-time-compile code that's built with
       # different optimization levels. http://crbug.com/543583
       'variables': {
@@ -154,7 +157,7 @@
       'target_name': 'skia_opts_sse41',
       'type': 'static_library',
       # The optimize: 'max' scattered throughout are particularly
-      # important when compiled by MSVC 2013, which seems 
+      # important when compiled by MSVC 2013, which seems
       # to mis-link-time-compile code that's built with
       # different optimization levels. http://crbug.com/543583
       'variables': {
@@ -188,10 +191,107 @@
       ],
     },
     {
+      'target_name': 'skia_opts_sse42',
+      'type': 'static_library',
+      # The optimize: 'max' scattered throughout are particularly
+      # important when compiled by MSVC 2013, which seems
+      # to mis-link-time-compile code that's built with
+      # different optimization levels. http://crbug.com/543583
+      'variables': {
+        'optimize': 'max',
+      },
+      'includes': [
+        'skia_common.gypi',
+        '../build/android/increase_size_for_speed.gypi',
+      ],
+      'include_dirs': [ '<@(include_dirs)' ],
+      'sources': [ '<@(sse42_sources)' ],
+      'conditions': [
+        [ 'OS in ["linux", "freebsd", "openbsd", "solaris", "android"]', {
+          'cflags': [ '-msse4.2' ],
+        }],
+        [ 'OS == "mac"', {
+          'xcode_settings': {
+            'GCC_ENABLE_SSE42_EXTENSIONS': 'YES',
+          },
+        }],
+        [ 'OS == "win" and clang == 1', {
+          # cl.exe's /arch flag doesn't have a setting for SSE4.2, and cl.exe
+          # doesn't need it for intrinsics. clang-cl does need it, though.
+          'msvs_settings': {
+            'VCCLCompilerTool': { 'AdditionalOptions': [ '-msse4.2' ] },
+          },
+        }],
+        [ 'OS == "win"', {
+          'defines' : [ 'SK_CPU_SSE_LEVEL=42' ],
+        }],
+      ],
+    },
+    {
+      'target_name': 'skia_opts_avx',
+      'type': 'static_library',
+      # The optimize: 'max' scattered throughout are particularly
+      # important when compiled by MSVC 2013, which seems
+      # to mis-link-time-compile code that's built with
+      # different optimization levels. http://crbug.com/543583
+      'variables': {
+        'optimize': 'max',
+      },
+      'includes': [
+        'skia_common.gypi',
+        '../build/android/increase_size_for_speed.gypi',
+      ],
+      'include_dirs': [ '<@(include_dirs)' ],
+      'sources': [ '<@(avx_sources)' ],
+      'conditions': [
+        [ 'OS in ["linux", "freebsd", "openbsd", "solaris", "android"]', {
+          'cflags': [ '-mavx' ],
+        }],
+        [ 'OS == "mac"', {
+          'xcode_settings': {
+            'OTHER_CFLAGS': [ '-mavx' ],
+          },
+        }],
+        [ 'OS == "win"', {
+          'msvs_settings': { 'VCCLCompilerTool': { 'EnableEnhancedInstructionSet': '3' } },
+        }],
+      ],
+    },
+    {
+      'target_name': 'skia_opts_avx2',
+      'type': 'static_library',
+      # The optimize: 'max' scattered throughout are particularly
+      # important when compiled by MSVC 2013, which seems
+      # to mis-link-time-compile code that's built with
+      # different optimization levels. http://crbug.com/543583
+      'variables': {
+        'optimize': 'max',
+      },
+      'includes': [
+        'skia_common.gypi',
+        '../build/android/increase_size_for_speed.gypi',
+      ],
+      'include_dirs': [ '<@(include_dirs)' ],
+      'sources': [ '<@(avx2_sources)' ],
+      'conditions': [
+        [ 'OS in ["linux", "freebsd", "openbsd", "solaris", "android"]', {
+          'cflags': [ '-mavx2' ],
+        }],
+        [ 'OS == "mac"', {
+          'xcode_settings': {
+            'OTHER_CFLAGS': [ '-mavx2' ],
+          },
+        }],
+        [ 'OS == "win"', {
+          'msvs_settings': { 'VCCLCompilerTool': { 'EnableEnhancedInstructionSet': '5' } },
+        }],
+      ],
+    },
+    {
       'target_name': 'skia_opts_none',
       'type': 'static_library',
       # The optimize: 'max' scattered throughout are particularly
-      # important when compiled by MSVC 2013, which seems 
+      # important when compiled by MSVC 2013, which seems
       # to mis-link-time-compile code that's built with
       # different optimization levels. http://crbug.com/543583
       'variables': {
diff --git a/sync/android/java/src/org/chromium/sync/signin/AccountManagerHelper.java b/sync/android/java/src/org/chromium/sync/signin/AccountManagerHelper.java
index 6fd2bb4..761447e8d 100644
--- a/sync/android/java/src/org/chromium/sync/signin/AccountManagerHelper.java
+++ b/sync/android/java/src/org/chromium/sync/signin/AccountManagerHelper.java
@@ -152,8 +152,8 @@
 
     /**
      * Use the asynchronous version below instead. See http://crbug.com/517697.
+     * @deprecated
      */
-    @Deprecated
     public List<String> getGoogleAccountNames() {
         List<String> accountNames = new ArrayList<String>();
         for (Account account : getGoogleAccounts()) {
@@ -180,8 +180,8 @@
 
     /**
      * Use the asynchronous version below instead. See http://crbug.com/517697.
+     * @deprecated
      */
-    @Deprecated
     public Account[] getGoogleAccounts() {
         return mAccountManager.getAccountsByType(GOOGLE_ACCOUNT_TYPE);
     }
@@ -195,8 +195,8 @@
 
     /**
      * Use the asynchronous version below instead. See http://crbug.com/517697.
+     * @deprecated
      */
-    @Deprecated
     public boolean hasGoogleAccounts() {
         return getGoogleAccounts().length > 0;
     }
@@ -228,8 +228,8 @@
 
     /**
      * Use the asynchronous version below instead. See http://crbug.com/517697.
+     * @deprecated
      */
-    @Deprecated
     public Account getAccountFromName(String accountName) {
         String canonicalName = canonicalizeName(accountName);
         Account[] accounts = getGoogleAccounts();
@@ -263,8 +263,8 @@
 
     /**
      * Use the asynchronous version below instead. See http://crbug.com/517697.
+     * @deprecated
      */
-    @Deprecated
     public boolean hasAccountForName(String accountName) {
         return getAccountFromName(accountName) != null;
     }
diff --git a/testing/android/native_test.gyp b/testing/android/native_test.gyp
index 5c30a50..b6fed862 100644
--- a/testing/android/native_test.gyp
+++ b/testing/android/native_test.gyp
@@ -51,6 +51,7 @@
           ],
         },
         {
+          # GN: //testing/android/native_test:native_test_java
           'target_name': 'native_test_java',
           'type': 'none',
           'dependencies': [
diff --git a/testing/android/native_test/BUILD.gn b/testing/android/native_test/BUILD.gn
index 0e8ffcb..34c5906 100644
--- a/testing/android/native_test/BUILD.gn
+++ b/testing/android/native_test/BUILD.gn
@@ -35,6 +35,19 @@
   ]
 }
 
+# GYP: //testing/android/native_test.gyp:native_test_java
+android_library("native_test_java") {
+  testonly = true
+  deps = [
+    "//base:base_java",
+    "//testing/android/appurify_support:appurify_support_java",
+    "//testing/android/reporter:reporter_java",
+  ]
+  srcjar_deps = [ "//base:base_native_libraries_gen" ]
+  DEPRECATED_java_in_dir = "java/src"
+  jar_excluded_patterns = [ "*/NativeLibraries.class" ]
+}
+
 # GYP: //testing/android/native_test.gyp:native_test_jni_headers
 generate_jni("native_test_jni_headers") {
   sources = [
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index ed7b9d2..25b01660 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -4413,19 +4413,10 @@
       }
     ]
   },
-  "Linux ARM Cross-Compile": {
+  "Linux ARM": {
     "gtest_tests": [
       {
         "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "sandbox_linux_unittests"
-      },
-      {
-        "args": [
           "--gtest_filter=*NaCl*.*"
         ],
         "swarming": {
@@ -4444,6 +4435,15 @@
           "can_use_on_swarming_builders": true
         },
         "test": "nacl_loader_unittests"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "sandbox_linux_unittests"
       }
     ]
   },
diff --git a/testing/test.gni b/testing/test.gni
index 449abd8f..a6daf7e 100644
--- a/testing/test.gni
+++ b/testing/test.gni
@@ -54,7 +54,8 @@
                              ])
 
       deps = []
-      if (!defined(invoker.use_launcher) || invoker.use_launcher) {
+      if (!defined(invoker.use_default_launcher) ||
+          invoker.use_default_launcher) {
         deps += [ "//testing/android/native_test:native_test_native_code" ]
       }
       if (defined(invoker.deps)) {
@@ -81,6 +82,9 @@
       if (defined(invoker.android_manifest)) {
         android_manifest = invoker.android_manifest
       }
+      if (defined(invoker.use_default_launcher)) {
+        use_default_launcher = invoker.use_default_launcher
+      }
     }
 
     _test_name = main_target_name
diff --git a/testing/variations/fieldtrial_testing_config_android.json b/testing/variations/fieldtrial_testing_config_android.json
index 91a73699..a756e4a 100644
--- a/testing/variations/fieldtrial_testing_config_android.json
+++ b/testing/variations/fieldtrial_testing_config_android.json
@@ -176,6 +176,14 @@
             "group_name": "Enabled"
         }
     ],
+    "ProgressBarAnimationAndroid": [
+        {
+            "group_name": "SmoothAnimation",
+            "params": {
+                "progress-bar-animation": "smooth"
+            }
+        }
+    ],
     "QUIC": [
         {
             "group_name": "Enabled",
diff --git a/third_party/WebKit/LayoutTests/bluetooth/requestDevice.html b/third_party/WebKit/LayoutTests/bluetooth/requestDevice.html
index 258e10b2..b1ce848b 100644
--- a/third_party/WebKit/LayoutTests/bluetooth/requestDevice.html
+++ b/third_party/WebKit/LayoutTests/bluetooth/requestDevice.html
@@ -192,7 +192,7 @@
   });
 
   // The adapter finds nothing, so we just see discovery start and stop.
-  getBluetoothManualChooserEvents(3).then(events => {
+  return getBluetoothManualChooserEvents(3).then(events => {
     assert_array_equals(events,
                         ['chooser-opened(file:///)',
                          'discovering',
diff --git a/third_party/WebKit/LayoutTests/fast/backgrounds/background-position-zoomed-expected.html b/third_party/WebKit/LayoutTests/fast/backgrounds/background-position-zoomed-expected.html
new file mode 100644
index 0000000..0e76edd6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/backgrounds/background-position-zoomed-expected.html
@@ -0,0 +1 @@
+<!DOCTYPE html>
diff --git a/third_party/WebKit/LayoutTests/fast/backgrounds/background-position-zoomed.html b/third_party/WebKit/LayoutTests/fast/backgrounds/background-position-zoomed.html
new file mode 100644
index 0000000..a963a618
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/backgrounds/background-position-zoomed.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<style>
+  div {
+      zoom: 0.5;
+      width: 25px;
+      height: 25px;
+      background-image: url('resources/bg_position_larger.gif');
+      background-position: 35px 35px;
+  }
+</style>
+<div></div>
diff --git a/third_party/WebKit/LayoutTests/fast/events/resources/tabindex-focus-blur-all-frame1.html b/third_party/WebKit/LayoutTests/fast/events/resources/tabindex-focus-blur-all-frame1.html
index e5ec013..91e4d959 100644
--- a/third_party/WebKit/LayoutTests/fast/events/resources/tabindex-focus-blur-all-frame1.html
+++ b/third_party/WebKit/LayoutTests/fast/events/resources/tabindex-focus-blur-all-frame1.html
@@ -154,6 +154,7 @@
 <input type="checkbox" id="checkbox1"><br>
 <input type="radio" id="radioChoice1a" name="radio1" tabindex="0"><br>
 <label id="label1" tabindex="-1"><input type="radio" name="radio1">label for radioChoice B</label><br>
+<label id="label2"><input type="radio" name="radio1">label for radioChoice C</label><br>
 <input type="file" id="file1" tabindex="2"><br>
 input type="hidden"<input type="hidden" id="hidden1" tabindex="-1"><br>
 input type="image"<input type="image" id="inputImage1" src="abe.png" tabindex="3"><br>
diff --git a/third_party/WebKit/LayoutTests/fast/events/resources/tabindex-focus-blur-all-frame2.html b/third_party/WebKit/LayoutTests/fast/events/resources/tabindex-focus-blur-all-frame2.html
index 015f97ee..1c51e10 100644
--- a/third_party/WebKit/LayoutTests/fast/events/resources/tabindex-focus-blur-all-frame2.html
+++ b/third_party/WebKit/LayoutTests/fast/events/resources/tabindex-focus-blur-all-frame2.html
@@ -154,6 +154,7 @@
 <input type="checkbox" id="checkbox3" tabindex="0"><br>
 <input type="radio" id="radioChoice3a" name="radio3"><br>
 <label id="label3" tabindex="2"><input type="radio" name="radio3" tabindex="0">label for radio button</label><br>
+<label id="label4"><input type="radio" name="radio3" tabindex="0">another label for radio button</label><br>
 <input type="file" id="file3" tabindex="-1"><br>
 input type="hidden"<input type="hidden" id="hidden3" tabindex="3"><br>
 input type="image"<input type="image" id="inputImage3" src="abe.png" tabindex="-1"><br>
diff --git a/third_party/WebKit/LayoutTests/fast/events/resources/tabindex-focus-blur-all.js b/third_party/WebKit/LayoutTests/fast/events/resources/tabindex-focus-blur-all.js
index 9493ed2..a51dbbd 100644
--- a/third_party/WebKit/LayoutTests/fast/events/resources/tabindex-focus-blur-all.js
+++ b/third_party/WebKit/LayoutTests/fast/events/resources/tabindex-focus-blur-all.js
@@ -53,7 +53,7 @@
     var homeBase = window.frames[1].document.getElementsByClassName('homebase');
     homeBase[0].focus();
 
-    var resultSummary = focusCount+" focus / "+blurCount+" blur events dispatched, and should be 333 / 333 ";
+    var resultSummary = focusCount+" focus / "+blurCount+" blur events dispatched, and should be 336 / 336 ";
     resultSummary += (focusCount==blurCount) ? "<span style='color:green'>PASSED</span><br>" : "<span style='color:red'>FAILED</span><br>";
     resultSummary += "Total of "+failedTestCount+" focus test(s) failed.";
     if (failedTestCount)
@@ -99,7 +99,7 @@
 function testProgrammaticFocus(elem)
 {
     var elemThatShouldFocus = null;
-    var OKtoFocusOtherElement = false;
+    var shouldFocusOtherElement = false;
     focusedElem = null;
 
     if (elem.tabIndex == elem.getAttribute("tabindex")) // this means tabindex was explicitly set
@@ -115,13 +115,11 @@
     if (elem.tabIndex == -1 && elem.tagName == "AREA")
         elemThatShouldFocus = null;
 
-    if (tagNamesTransferFocused.find(elem.tagName)) {
-        elemThatShouldFocus = null;
-        OKtoFocusOtherElement = true;
-    }
+    if (tagNamesTransferFocused.find(elem.tagName) && elemThatShouldFocus == null)
+        shouldFocusOtherElement = true;
 
     elem.focus();
-    if (elemThatShouldFocus == focusedElem || (!elemThatShouldFocus && OKtoFocusOtherElement))
+    if ((!shouldFocusOtherElement && elemThatShouldFocus == focusedElem) || (shouldFocusOtherElement && elem != focusedElem))
         printToConsole("<"+elem.tagName+"> "+elem.id+" PASSED focus test");
     else {
         failedTestCount++;
diff --git a/third_party/WebKit/LayoutTests/fast/events/tabindex-focus-blur-all-expected.txt b/third_party/WebKit/LayoutTests/fast/events/tabindex-focus-blur-all-expected.txt
index aa91061c2..6b8410f5 100644
--- a/third_party/WebKit/LayoutTests/fast/events/tabindex-focus-blur-all-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/events/tabindex-focus-blur-all-expected.txt
@@ -1,2 +1,2 @@
-333 focus / 333 blur events dispatched, and should be 333 / 333 PASSED
+336 focus / 336 blur events dispatched, and should be 336 / 336 PASSED
 Total of 0 focus test(s) failed. PASSED
diff --git a/third_party/WebKit/LayoutTests/http/tests/push_messaging/subscribe-encryption-public-key.html b/third_party/WebKit/LayoutTests/http/tests/push_messaging/subscribe-encryption-public-key.html
index 06ae806..d8ff774 100644
--- a/third_party/WebKit/LayoutTests/http/tests/push_messaging/subscribe-encryption-public-key.html
+++ b/third_party/WebKit/LayoutTests/http/tests/push_messaging/subscribe-encryption-public-key.html
@@ -23,8 +23,11 @@
                 var workerScope = 'resources/scope/' + location.pathname;
                 var swRegistration, encryptionKey;
 
-                // Size of an ECDH p256 public key, in bytes.
-                var EXPECTED_KEY_LENGTH = 32;
+                // Length of a NIST P-256 point in uncompressed form per SEC1 2.3.3.
+                var EXPECTED_KEY_LENGTH = 65;
+
+                // The first byte in an uncompressed P-256 point per SEC1 2.3.3.
+                var UNCOMPRESSED_POINT_FORM = 0x04;
 
                 service_worker_unregister_and_register(test, workerUrl, workerScope)
                     .then(function(serviceWorkerRegistration) {
@@ -39,16 +42,22 @@
                     })
                     .then(function(pushSubscription) {
                         assert_own_property(PushSubscription.prototype, 'getKey');
-                        assert_not_equals(pushSubscription.getKey('p256dh'), null);
-                        assert_equals(pushSubscription.getKey('p256dh').byteLength, EXPECTED_KEY_LENGTH);
 
-                        // The returned ArrayBuffers are expected to be the same.
-                        assert_equals(pushSubscription.getKey('p256dh'), pushSubscription.getKey('p256dh'));
+                        var key = pushSubscription.getKey('p256dh');
+
+                        assert_not_equals(key, null);
+                        assert_equals(key.byteLength, EXPECTED_KEY_LENGTH);
+
+                        // The same ArrayBuffer instance should be returned on multiple calls.
+                        assert_equals(key, pushSubscription.getKey('p256dh'));
+
+                        // The first byte of the key should be the uncompressed point form indicator.
+                        assert_equals(new Uint8Array(key)[0], UNCOMPRESSED_POINT_FORM);
 
                         // Getting a key with an unsupported algorithm should throw an exception.
                         assert_throws(TypeError(), () => pushSubscription.getKey('petercurve9001'));
 
-                        encryptionKey = SerializeArrayBuffer(pushSubscription.getKey('p256dh'));
+                        encryptionKey = SerializeArrayBuffer(key);
 
                         return swRegistration.pushManager.getSubscription();
                     })
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/css/css-get-background-colors-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/css/css-get-background-colors-expected.txt
new file mode 100644
index 0000000..83cd3146
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/css/css-get-background-colors-expected.txt
@@ -0,0 +1,130 @@
+Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
+Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
+Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
+Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
+Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
+Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
+Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
+Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
+Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
+Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
+Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
+Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
+Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
+Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
+Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
+Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
+Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
+Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
+Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
+Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
+Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
+Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
+Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
+Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
+Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
+
+Running test: testNoText
+No text: should be null
+{}
+
+Running test: testNoBgColor
+No background color: should be white
+{"backgroundColors":["rgb(255, 255, 255)"]}
+
+Running test: testOpaqueBgColor
+Opaque background color: should be red
+{"backgroundColors":["rgb(255, 0, 0)"]}
+
+Running test: testLayeredOpaqueBgColors
+Opaque background color in front of another opaque background color: should be blue
+{"backgroundColors":["rgb(0, 0, 255)"]}
+
+Running test: testOneSemitransparentBgColor
+Semi-transparent background color: should be light red
+{"backgroundColors":["rgb(255, 128, 128)"]}
+
+Running test: testTwoSemitransparentBgColors
+Two layered semi-transparent background colors: should be medium red
+{"backgroundColors":["rgb(255, 64, 64)"]}
+
+Running test: testOpaqueGradientBackground
+Opaque gradient: should be red and black
+{"backgroundColors":["rgb(255, 0, 0)","rgb(0, 0, 0)"]}
+
+Running test: testOpaqueGradientBackgroundBehindScrim
+Opaque gradient behind semi-transparent color: should be light red and 50% grey
+{"backgroundColors":["rgb(255, 127, 127)","rgb(127, 127, 127)"]}
+
+Running test: testOpaqueGradientBackgroundWithColorBackground
+Opaque gradient and solid color background on same element: should be red and black
+{"backgroundColors":["rgb(255, 0, 0)","rgb(0, 0, 0)"]}
+
+Running test: testPartiallyTransparentGradientBackground
+Semi-transparent gradient: should be light red and 50% grey
+{"backgroundColors":["rgb(255, 128, 128)","rgb(128, 128, 128)"]}
+
+Running test: testPartiallyTransparentGradientAndColorBackground
+Semi-transparent gradient and solid color on same element: should be dark red and 50% grey
+{"backgroundColors":["rgb(127, 0, 0)","rgb(127, 127, 127)"]}
+
+Running test: testTwoPartiallyTransparentGradientBackgrounds
+Layered semi-transparent gradients: should be empty array
+{"backgroundColors":[]}
+
+Running test: testPartiallyOverlappingBackground
+Partially overlapping background: should be empty array
+{"backgroundColors":[]}
+
+Running test: smallerBackground
+Background smaller than text: should be empty array
+{"backgroundColors":[]}
+
+Running test: testObscuredPartiallyOverlappingBackground
+Red background obscuring partially overlapping blue background: should be red only
+{"backgroundColors":["rgb(255, 0, 0)"]}
+
+Running test: testBackgroundImage
+Background image: should be empty array
+{"backgroundColors":[]}
+
+Running test: testBackgroundImageAndBgColor
+Background image with background color: should be empty array
+{"backgroundColors":[]}
+
+Running test: testBackgroundImageBehindScrim
+Background image behind scrim: should be semi-transparent white
+{"backgroundColors":["rgba(255, 255, 255, 0.498039)"]}
+
+Running test: testForegroundImage
+Image behind text: should be empty array
+{"backgroundColors":[]}
+
+Running test: testForegroundImageBehindScrim
+Image behind scrim: should be semi-transparent white
+{"backgroundColors":["rgba(255, 255, 255, 0.498039)"]}
+
+Running test: testForegroundCanvas
+Canvas behind text: should be empty array
+{"backgroundColors":[]}
+
+Running test: testForegroundEmbed
+Embed behind text: should be empty array
+{"backgroundColors":[]}
+
+Running test: testForegroundObject
+Object behind text: should be empty array
+{"backgroundColors":[]}
+
+Running test: testForegroundPicture
+Picture behind text: should be empty array
+{"backgroundColors":[]}
+
+Running test: testForegroundSVG
+SVG behind text: should be empty array
+{"backgroundColors":[]}
+
+Running test: testForegroundVideo
+Video behind text: should be empty array
+{"backgroundColors":[]}
+
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/css/css-get-background-colors.html b/third_party/WebKit/LayoutTests/inspector-protocol/css/css-get-background-colors.html
new file mode 100644
index 0000000..2540fa6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/css/css-get-background-colors.html
@@ -0,0 +1,539 @@
+<html>
+<head>
+<script type="text/javascript" src="../../http/tests/inspector-protocol/inspector-test.js"></script>
+<script type="text/javascript" src="../../http/tests/inspector-protocol/inspector-protocol-test.js"></script>
+<script type="text/javascript" src="../../http/tests/inspector-protocol/dom-protocol-test.js"></script>
+<script type="text/javascript" src="../../http/tests/inspector-protocol/css-protocol-test.js"></script>
+<script>
+function test() {
+    if (!InspectorTest)
+        return;
+
+    InspectorTest.requestDocumentNodeId(onDocumentNodeId);
+
+    var documentNodeId;
+    var textLayerId;
+
+    function testGetBgColors(querySelector, done) {
+        function onNodeId(nodeId) {
+            function onGotBackgroundColors(response) {
+                InspectorTest.log(JSON.stringify(response));
+                done();
+            }
+
+            InspectorTest.sendCommandOrDie("CSS.getBackgroundColors", { nodeId: nodeId }, onGotBackgroundColors);
+        }
+
+
+        InspectorTest.requestNodeId(documentNodeId, querySelector, onNodeId);
+    }
+
+    function onDocumentNodeId(nodeId)
+    {
+        documentNodeId = nodeId;
+        InspectorTest.runTestSuite([
+            function testNoText(done) {
+                InspectorTest.log("No text: should be null");
+                testGetBgColors(".noText > p", done);
+            },
+            function testNoBgColor(done) {
+                InspectorTest.log("No background color: should be white");
+                testGetBgColors(".noBgColor > p", done);
+            },
+            function testOpaqueBgColor(done) {
+                InspectorTest.log("Opaque background color: should be red");
+                testGetBgColors(".opaqueBgColor > p", done);
+            },
+            function testLayeredOpaqueBgColors(done) {
+                InspectorTest.log("Opaque background color in front of another opaque background color: should be blue");
+                testGetBgColors(".layeredOpaqueBgColors > p", done);
+            },
+            function testOneSemitransparentBgColor(done) {
+                InspectorTest.log("Semi-transparent background color: should be light red");
+                testGetBgColors(".semitransparentBgColor > p", done);
+            },
+            function testTwoSemitransparentBgColors(done) {
+                InspectorTest.log("Two layered semi-transparent background colors: should be medium red");
+                testGetBgColors(".twoSemitransparentBgColors > p", done);
+            },
+            function testOpaqueGradientBackground(done) {
+                InspectorTest.log("Opaque gradient: should be red and black");
+                testGetBgColors(".opaqueGradientBg > p", done);
+            },
+            function testOpaqueGradientBackgroundBehindScrim(done)
+            {
+                InspectorTest.log("Opaque gradient behind semi-transparent color: should be light red and 50% grey");
+                testGetBgColors(".opaqueGradientBehindScrim > p", done);
+            },
+            function testOpaqueGradientBackgroundWithColorBackground(done)
+            {
+                InspectorTest.log("Opaque gradient and solid color background on same element: should be red and black");
+                testGetBgColors(".opaqueGradientAndColorBg > p", done);
+            },
+            function testPartiallyTransparentGradientBackground(done)
+            {
+                InspectorTest.log("Semi-transparent gradient: should be light red and 50% grey");
+                testGetBgColors(".semitransparentGradientBg > p", done);
+            },
+            function testPartiallyTransparentGradientAndColorBackground(done)
+            {
+                InspectorTest.log("Semi-transparent gradient and solid color on same element: should be dark red and 50% grey");
+                testGetBgColors(".semitransparentGradientAndColorBg > p", done);
+            },
+            function testTwoPartiallyTransparentGradientBackgrounds(done)
+            {
+                InspectorTest.log("Layered semi-transparent gradients: should be empty array");
+                testGetBgColors(".twoSemitransparentGradientBgs > p", done);
+            },
+            function testPartiallyOverlappingBackground(done)
+            {
+                InspectorTest.log("Partially overlapping background: should be empty array");
+                testGetBgColors(".partiallyOverlappingBackground > p", done);
+            },
+            function smallerBackground(done)
+            {
+                InspectorTest.log("Background smaller than text: should be empty array");
+                testGetBgColors(".smallerBackground > p", done);
+            },
+            function testObscuredPartiallyOverlappingBackground(done)
+            {
+                InspectorTest.log("Red background obscuring partially overlapping blue background: should be red only");
+                testGetBgColors(".obscuredPartiallyOverlappingBackground > p", done);
+            },
+            function testBackgroundImage(done)
+            {
+                InspectorTest.log("Background image: should be empty array");
+                testGetBgColors(".backgroundImage > p", done);
+            },
+            function testBackgroundImageAndBgColor(done)
+            {
+                InspectorTest.log("Background image with background color: should be empty array");
+                testGetBgColors(".backgroundImageAndBgColor > p", done);
+            },
+
+            function testBackgroundImageBehindScrim(done)
+            {
+                InspectorTest.log("Background image behind scrim: should be semi-transparent white");
+                testGetBgColors(".backgroundImageBehindScrim > p", done);
+            },
+            function testForegroundImage(done)
+            {
+                InspectorTest.log("Image behind text: should be empty array");
+                testGetBgColors(".foregroundImage > p", done);
+            },
+            function testForegroundImageBehindScrim(done)
+            {
+                InspectorTest.log("Image behind scrim: should be semi-transparent white");
+                testGetBgColors(".foregroundImageBehindScrim > p", done);
+            },
+            function testForegroundCanvas(done)
+            {
+                InspectorTest.log("Canvas behind text: should be empty array");
+                testGetBgColors(".canvas > p", done);
+            },
+            function testForegroundEmbed(done)
+            {
+                InspectorTest.log("Embed behind text: should be empty array");
+                testGetBgColors(".embed > p", done);
+            },
+            function testForegroundObject(done)
+            {
+                InspectorTest.log("Object behind text: should be empty array");
+                testGetBgColors(".object > p", done);
+            },
+            function testForegroundPicture(done)
+            {
+                InspectorTest.log("Picture behind text: should be empty array");
+                testGetBgColors(".picture > p", done);
+            },
+            function testForegroundSVG(done)
+            {
+                InspectorTest.log("SVG behind text: should be empty array");
+                testGetBgColors(".svg > p", done);
+            },
+            function testForegroundVideo(done)
+            {
+                InspectorTest.log("Video behind text: should be empty array");
+                testGetBgColors(".video > p", done);
+            },
+        ]);
+    }
+}
+</script>
+<style>
+.testCase {
+   position: relative;
+}
+.layer, .testCase {
+   width: 200px;
+   height: 200px;
+}
+.background {
+   overflow: hidden;
+}
+.background, p {
+   position: absolute;
+   top: 0;
+   left: 0;
+}
+p {
+   color: black;
+}
+</style>
+</head>
+<body onload="runTest()">
+<!-- No text -->
+<div class="testCase noText">
+  <p class="layer">
+  </p>
+</div>
+
+<!-- No background color -->
+<div class="testCase noBgColor">
+  <p class="layer">
+    Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
+  </p>
+</div>
+
+
+<!-- Opaque background color -->
+<style>
+.opaqueBgColor > .background {
+  background-color: red;
+}
+</style>
+<div class="testCase opaqueBgColor">
+  <div class="background layer"></div>
+  <p class="layer">
+    Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
+  </p>
+</div>
+
+<!-- Layered opaque background colors -->
+<style>
+.layeredOpaqueBgColors,
+.layeredOpaqueBgColors > .background.obscured {
+  height: 300px;
+  width: 300px;
+}
+.layeredOpaqueBgColors > .background.obscured {
+  background-color: red;
+}
+.layeredOpaqueBgColors > .background.obscuring {
+  background-color: blue;
+}
+.layeredOpaqueBgColors > .background.obscuring,
+.layeredOpaqueBgColors > p {
+  top: 50px;
+  left: 50px;
+}
+
+</style>
+<div class="testCase layeredOpaqueBgColors">
+  <div class="background layer obscured"></div>
+  <div class="background layer obscuring"></div>
+  <p class="layer">
+    Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
+  </p>
+</div>
+
+<!-- Semi-transparent background color -->
+<style>
+.semitransparentBgColor > .background {
+  background-color: rgba(255, 0, 0, 0.5);
+}
+</style>
+<div class="testCase semitransparentBgColor">
+  <div class="background layer"></div>
+  <p class="layer">
+    Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
+  </p>
+</div>
+
+<!-- Two layered semi-transparent background colors -->
+<style>
+.twoSemitransparentBgColors > .background {
+  background-color: rgba(255, 0, 0, 0.5);
+}
+</style>
+<div class="testCase twoSemitransparentBgColors">
+  <div class="background layer"></div>
+  <div class="background layer"></div>
+  <p class="layer">
+    Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
+  </p>
+</div>
+
+<!-- Opaque gradient background -->
+<style>
+.opaqueGradientBg > .background {
+  background: linear-gradient(45deg, red, black);
+}
+</style>
+<div class="testCase opaqueGradientBg">
+  <div class="background layer"></div>
+  <p class="layer">
+    Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
+  </p>
+</div>
+
+<!-- Opaque gradient background behind scrim-->
+<style>
+.opaqueGradientBehindScrim > .background.gradient {
+  background: linear-gradient(45deg, red, black);
+}
+.opaqueGradientBehindScrim > .background.scrim {
+  background: rgba(255, 255, 255, 0.5);
+}
+</style>
+<div class="testCase opaqueGradientBehindScrim">
+  <div class="background layer gradient"></div>
+  <div class="background layer scrim"></div>
+  <p class="layer">
+    Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
+  </p>
+</div>
+
+<!-- Opaque gradient background and color background -->
+<style>
+.opaqueGradientAndColorBg > .background {
+  background-image: linear-gradient(45deg, red, black);
+  background-color: blue;
+}
+</style>
+<div class="testCase opaqueGradientAndColorBg">
+  <div class="background layer"></div>
+  <p class="layer">
+    Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
+  </p>
+</div>
+
+<!-- Semi-transparent gradient background -->
+<style>
+.semitransparentGradientBg > .background {
+  background: linear-gradient(45deg, rgba(255, 0, 0, 0.5), rgba(0, 0, 0, 0.5));
+}
+</style>
+<div class="testCase semitransparentGradientBg">
+  <div class="background layer"></div>
+  <p class="layer">
+    Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
+  </p>
+</div>
+
+<!-- Semi-transparent gradient background and color background -->
+<style>
+.semitransparentGradientAndColorBg > .background {
+  background-image: linear-gradient(45deg, rgba(255, 0, 0, 0.5), rgba(255, 255, 255, 0.5));
+  background-color: black;
+}
+</style>
+<div class="testCase semitransparentGradientAndColorBg">
+  <div class="background layer"></div>
+  <p class="layer">
+    Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
+  </p>
+</div>
+
+<!-- Layered semi-transparent gradient backgrounds -->
+<style>
+.twoSemitransparentGradientBgs > .background {
+  background: linear-gradient(45deg, rgba(255, 0, 0, 0.5), rgba(0, 0, 0, 0.5));
+}
+</style>
+<div class="testCase twoSemitransparentGradientBgs">
+  <div class="background layer"></div>
+  <div class="background layer"></div>
+  <p class="layer">
+    Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
+  </p>
+</div>
+
+<!-- Partially overlapping background element -->
+<style>
+.partiallyOverlappingBackground > .background {
+  background-color: red;
+  left: 150px;
+}
+</style>
+<div class="testCase partiallyOverlappingBackground">
+  <div class="background layer"></div>
+  <p class="layer">
+    Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
+  </p>
+</div>
+
+<!-- Smaller background element -->
+<style>
+.smallerBackground > .background {
+  background-color: red;
+  width: 100px;
+  height: 100px;
+}
+</style>
+<div class="testCase smallerBackground">
+  <div class="background layer"></div>
+  <p class="layer">
+    Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
+  </p>
+</div>
+
+<!-- Partially overlapping background element which is overlapped by opaque element -->
+<style>
+.obscuredPartiallyOverlappingBackground > .background.partiallyOverlapping {
+  background-color: blue;
+  left: 150px;
+}
+
+.obscuredPartiallyOverlappingBackground > .background.obscuring {
+  background-color: red;
+}
+</style>
+<div class="testCase obscuredPartiallyOverlappingBackground">
+  <div class="background layer partiallyOverlapping"></div>
+  <div class="background layer obscuring"></div>
+  <p class="layer">
+    Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
+  </p>
+</div>
+
+<!-- Background image -->
+<style>
+.backgroundImage > .background {
+  background-image: url(../../media/content/abe.png);
+}
+</style>
+<div class="testCase backgroundImage">
+  <div class="background layer"></div>
+  <p class="layer">
+    Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
+  </p>
+</div>
+
+<!-- Background image and background color -->
+<style>
+.backgroundImageAndBgColor > .background {
+  background-image: url(../../media/content/abe.png);
+  background-color: red;
+}
+</style>
+<div class="testCase backgroundImageAndBgColor">
+  <div class="background layer"></div>
+  <p class="layer">
+    Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
+  </p>
+</div>
+
+<!-- Background image behind semi-opaque scrim -->
+<style>
+.backgroundImageBehindScrim > .backgroundImage {
+  background-image: url(../../media/content/abe.png);
+}
+
+.backgroundImageBehindScrim > .scrim {
+  background-color: rgba(255, 255, 255, 0.5);
+}
+</style>
+<div class="testCase backgroundImageBehindScrim">
+  <div class="background layer backgroundImage"></div>
+  <div class="background layer scrim"></div>
+  <p class="layer">
+    Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
+  </p>
+</div>
+
+<!-- Image behind text -->
+<div class="testCase foregroundImage">
+  <div class="background layer">
+    <img width="200" height="200" src="../../media/content/abe.png" alt="Abraham Lincoln">
+  </div>
+  <p class="layer">
+    Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
+  </p>
+</div>
+
+<!-- Image behind scrim -->
+<style>
+.foregroundImageBehindScrim > .scrim {
+  background-color: rgba(255, 255, 255, 0.5);
+}
+</style>
+<div class="testCase foregroundImageBehindScrim">
+  <div class="background layer">
+    <img width="200" height="200" src="../../media/content/abe.png" alt="Abraham Lincoln">
+  </div>
+  <div class="background layer scrim"></div>
+  <p class="layer">
+    Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
+  </p>
+</div>
+
+<!-- Canvas behind text -->
+<div class="testCase canvas">
+  <div class="background layer">
+    <canvas width="200" height="200"></canvas>
+    <img width="200" height="200" style="visibility: hidden;" src="../../media/content/abe.png"></img>
+  </div>
+  <p class="layer">
+    Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
+  </p>
+</div>
+<script type="text/javascript">
+  var image = document.querySelector(".canvas img");
+  var canvas = document.querySelector(".canvas canvas");
+  var context = canvas.getContext('2d');
+  context.drawImage(image, 0, 0, 200, 200);
+</script>
+
+<!-- Embed behind text -->
+<div class="testCase embed">
+  <div class="background layer">
+    <embed width="200" height="200" src="../../media/content/abe.png"></embed>
+  </div>
+  <p class="layer">
+    Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
+  </p>
+</div>
+
+<!-- Object behind text -->
+<div class="testCase object">
+  <div class="background layer">
+    <object width="200" height="200" data="../../media/content/abe.png"></object>
+  </div>
+  <p class="layer">
+    Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
+  </p>
+</div>
+
+<!-- Picture behind text -->
+<div class="testCase picture">
+  <div class="background layer">
+    <picture><source type="image/webp" srcset="../../fast/images/resources/test.webp"><img src="../../media/content/abe.png" height="200" width="200"></picture>
+  </div>
+  <p class="layer">
+    Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
+  </p>
+</div>
+
+<!-- SVG behind text -->
+<div class="testCase svg">
+  <div class="background layer">
+    <svg width="100%" height="100%" viewBox="0 0 400 400"><circle r="200" cx="200" cy="200" stroke="red" stroke-width="1" fill="yellow" /><ellipse cx="120" cy="180" rx="18" ry="33" fill="black"/><ellipse cx="280" cy="120" rx="18" ry="33" fill="black"/><ellipse cx="200" cy="220" rx="8" ry="15" fill="black"/><path stroke-width="10" stroke="black" fill="none" stroke-linecap="round" d="M120,280 Q200,330 290,280"/></svg>
+  </div>
+  <p class="layer">
+    Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
+  </p>
+</div>
+
+<!-- Video behind text -->
+<div class="testCase video">
+  <div class="background layer">
+    <video src="../../media/content/test.ogv" height="200"></video>
+  </div>
+  <p class="layer">
+    Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
+  </p>
+</div>
+
+</body>
+</html>
diff --git a/third_party/WebKit/Source/core/css/CSSGradientValue.cpp b/third_party/WebKit/Source/core/css/CSSGradientValue.cpp
index e96e061..cd3e3fd5 100644
--- a/third_party/WebKit/Source/core/css/CSSGradientValue.cpp
+++ b/third_party/WebKit/Source/core/css/CSSGradientValue.cpp
@@ -572,6 +572,16 @@
     return true;
 }
 
+void CSSGradientValue::getStopColors(WillBeHeapVector<Color>& stopColors, const LayoutObject* object) const
+{
+    ASSERT(object);
+    for (auto& stop : m_stops) {
+        if (!stop.isHint())
+            stopColors.append(resolveStopColor(*stop.m_color, *object));
+    }
+
+}
+
 DEFINE_TRACE_AFTER_DISPATCH(CSSGradientValue)
 {
 #if ENABLE(OILPAN)
diff --git a/third_party/WebKit/Source/core/css/CSSGradientValue.h b/third_party/WebKit/Source/core/css/CSSGradientValue.h
index c425efa..48b54363 100644
--- a/third_party/WebKit/Source/core/css/CSSGradientValue.h
+++ b/third_party/WebKit/Source/core/css/CSSGradientValue.h
@@ -33,6 +33,7 @@
 
 namespace blink {
 
+class Color;
 class FloatPoint;
 class Gradient;
 
@@ -51,6 +52,8 @@
 // stack scanning. When allocated as part of Vectors in heap-allocated
 // objects its members are visited via the containing object's
 // (CSSGradientValue) traceAfterDispatch method.
+//
+// http://www.w3.org/TR/css3-images/#color-stop-syntax
 struct CSSGradientColorStop {
     DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
 public:
@@ -108,6 +111,8 @@
 
     void loadSubimages(Document*) { }
 
+    void getStopColors(WillBeHeapVector<Color>& stopColors, const LayoutObject*) const;
+
     DECLARE_TRACE_AFTER_DISPATCH();
 
 protected:
diff --git a/third_party/WebKit/Source/core/dom/TreeScope.cpp b/third_party/WebKit/Source/core/dom/TreeScope.cpp
index 4e41d75..fe8f2ff 100644
--- a/third_party/WebKit/Source/core/dom/TreeScope.cpp
+++ b/third_party/WebKit/Source/core/dom/TreeScope.cpp
@@ -293,19 +293,10 @@
     return toElement(node);
 }
 
-WillBeHeapVector<RawPtrWillBeMember<Element>> TreeScope::elementsFromPoint(int x, int y) const
+WillBeHeapVector<RawPtrWillBeMember<Element>> TreeScope::elementsFromHitTestResult(HitTestResult& result) const
 {
     WillBeHeapVector<RawPtrWillBeMember<Element>> elements;
 
-    Document& document = rootNode().document();
-    IntPoint hitPoint(x, y);
-    if (!pointWithScrollAndZoomIfPossible(document, hitPoint))
-        return elements;
-
-    HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::ListBased | HitTestRequest::PenetratingList);
-    HitTestResult result(request, hitPoint);
-    document.layoutView()->hitTest(result);
-
     Node* lastNode = nullptr;
     for (const auto rectBasedNode : result.listBasedTestResult()) {
         Node* node = rectBasedNode.get();
@@ -337,6 +328,20 @@
     return elements;
 }
 
+WillBeHeapVector<RawPtrWillBeMember<Element>> TreeScope::elementsFromPoint(int x, int y) const
+{
+    Document& document = rootNode().document();
+    IntPoint hitPoint(x, y);
+    if (!pointWithScrollAndZoomIfPossible(document, hitPoint))
+        return WillBeHeapVector<RawPtrWillBeMember<Element>>();
+
+    HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::ListBased | HitTestRequest::PenetratingList);
+    HitTestResult result(request, hitPoint);
+    document.layoutView()->hitTest(result);
+
+    return elementsFromHitTestResult(result);
+}
+
 void TreeScope::addLabel(const AtomicString& forAttributeValue, HTMLLabelElement* element)
 {
     ASSERT(m_labelsByForAttribute);
diff --git a/third_party/WebKit/Source/core/dom/TreeScope.h b/third_party/WebKit/Source/core/dom/TreeScope.h
index 7ccfe0f..88a3a756 100644
--- a/third_party/WebKit/Source/core/dom/TreeScope.h
+++ b/third_party/WebKit/Source/core/dom/TreeScope.h
@@ -79,6 +79,7 @@
     Element* elementFromPoint(int x, int y) const;
     Element* hitTestPoint(int x, int y, const HitTestRequest&) const;
     WillBeHeapVector<RawPtrWillBeMember<Element>> elementsFromPoint(int x, int y) const;
+    WillBeHeapVector<RawPtrWillBeMember<Element>> elementsFromHitTestResult(HitTestResult&) const;
 
     // For accessibility.
     bool shouldCacheLabelsByForAttribute() const { return m_labelsByForAttribute; }
diff --git a/third_party/WebKit/Source/core/fetch/MemoryCacheTest.cpp b/third_party/WebKit/Source/core/fetch/MemoryCacheTest.cpp
index 4e5f2158..fc41bf8 100644
--- a/third_party/WebKit/Source/core/fetch/MemoryCacheTest.cpp
+++ b/third_party/WebKit/Source/core/fetch/MemoryCacheTest.cpp
@@ -233,7 +233,7 @@
 
     private:
         ResourcePtr<Resource> m_live;
-        Resource* m_dead;
+        RawPtrWillBePersistent<Resource> m_dead;
     };
 
     class Task2 : public WebTaskRunner::Task {
diff --git a/third_party/WebKit/Source/core/fetch/MockImageResourceClient.h b/third_party/WebKit/Source/core/fetch/MockImageResourceClient.h
index e802be3..914e126 100644
--- a/third_party/WebKit/Source/core/fetch/MockImageResourceClient.h
+++ b/third_party/WebKit/Source/core/fetch/MockImageResourceClient.h
@@ -32,6 +32,7 @@
 #define MockImageResourceClient_h
 
 #include "core/fetch/ImageResourceClient.h"
+#include "platform/heap/Handle.h"
 
 namespace blink {
 
@@ -58,7 +59,8 @@
     void removeAsClient();
 
 private:
-    Resource* m_resource;
+    // TODO(Oilpan): properly trace when ImageResourceClient is on the heap.
+    RawPtrWillBeUntracedMember<Resource> m_resource;
     int m_imageChangedCount;
     bool m_notifyFinishedCalled;
 };
diff --git a/third_party/WebKit/Source/core/html/HTMLInputElementTest.cpp b/third_party/WebKit/Source/core/html/HTMLInputElementTest.cpp
index fb76476..c3dd8a6 100644
--- a/third_party/WebKit/Source/core/html/HTMLInputElementTest.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLInputElementTest.cpp
@@ -48,4 +48,16 @@
     document.body()->removeChild(document.body()->firstChild());
 }
 
+TEST(HTMLInputElementTest, DefaultToolTip)
+{
+    RefPtrWillBeRawPtr<Document> document = Document::create();
+    RefPtrWillBeRawPtr<HTMLHtmlElement> html = HTMLHtmlElement::create(*document);
+    html->appendChild(HTMLBodyElement::create(*document));
+    RefPtrWillBeRawPtr<HTMLInputElement> input = HTMLInputElement::create(*document, nullptr, false);
+    input->setBooleanAttribute(HTMLNames::requiredAttr, true);
+    toHTMLBodyElement(html->firstChild())->appendChild(input.get());
+    document->appendChild(html.release());
+    EXPECT_EQ("<<ValidationValueMissing>>", input->defaultToolTip());
+}
+
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/html/HTMLLabelElement.cpp b/third_party/WebKit/Source/core/html/HTMLLabelElement.cpp
index c32e3b8..c09f432 100644
--- a/third_party/WebKit/Source/core/html/HTMLLabelElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLLabelElement.cpp
@@ -55,12 +55,6 @@
     return labelElement.release();
 }
 
-bool HTMLLabelElement::layoutObjectIsFocusable() const
-{
-    HTMLLabelElement* that = const_cast<HTMLLabelElement*>(this);
-    return that->isContentEditable();
-}
-
 LabelableElement* HTMLLabelElement::control() const
 {
     const AtomicString& controlId = getAttribute(forAttr);
@@ -210,11 +204,13 @@
 
 void HTMLLabelElement::focus(const FocusParams& params)
 {
-    // to match other browsers, always restore previous selection
+    if (isFocusable()) {
+        HTMLElement::focus(params);
+        return;
+    }
+    // To match other browsers, always restore previous selection.
     if (HTMLElement* element = control())
         element->focus(FocusParams(SelectionBehaviorOnFocus::Restore, params.type, params.sourceCapabilities));
-    if (isFocusable())
-        HTMLElement::focus(params);
 }
 
 void HTMLLabelElement::accessKeyAction(bool sendMouseEvents)
diff --git a/third_party/WebKit/Source/core/html/HTMLLabelElement.h b/third_party/WebKit/Source/core/html/HTMLLabelElement.h
index 9c9fd06..49833bde 100644
--- a/third_party/WebKit/Source/core/html/HTMLLabelElement.h
+++ b/third_party/WebKit/Source/core/html/HTMLLabelElement.h
@@ -54,7 +54,6 @@
     explicit HTMLLabelElement(Document&, HTMLFormElement*);
     bool isInInteractiveContent(Node*) const;
 
-    bool layoutObjectIsFocusable() const override;
     bool isInteractiveContent() const override;
     void accessKeyAction(bool sendMouseEvents) override;
 
diff --git a/third_party/WebKit/Source/core/html/forms/InputType.cpp b/third_party/WebKit/Source/core/html/forms/InputType.cpp
index 5feee4b7..785e9c8 100644
--- a/third_party/WebKit/Source/core/html/forms/InputType.cpp
+++ b/third_party/WebKit/Source/core/html/forms/InputType.cpp
@@ -689,7 +689,7 @@
 
 String InputType::defaultToolTip() const
 {
-    return String();
+    return validationMessage();
 }
 
 Decimal InputType::findClosestTickMarkValue(const Decimal&)
diff --git a/third_party/WebKit/Source/core/inspector/CodeGeneratorInspector.py b/third_party/WebKit/Source/core/inspector/CodeGeneratorInspector.py
index 446a2ea9..8a707bccc 100755
--- a/third_party/WebKit/Source/core/inspector/CodeGeneratorInspector.py
+++ b/third_party/WebKit/Source/core/inspector/CodeGeneratorInspector.py
@@ -1705,7 +1705,7 @@
 
         Generator.method_name_enum_list.append("        %s," % cmd_enum_name)
         Generator.method_handler_list.append("            &InspectorBackendDispatcherImpl::%s_%s," % (domain_name, json_command_name))
-        Generator.backend_method_declaration_list.append("    void %s_%s(int callId, JSONObject* requestMessageObject, JSONArray* protocolErrors);" % (domain_name, json_command_name))
+        Generator.backend_method_declaration_list.append("    void %s_%s(int sessionId, int callId, JSONObject* requestMessageObject, JSONArray* protocolErrors);" % (domain_name, json_command_name))
 
         backend_agent_interface_list = [] if "redirect" in json_command else Generator.backend_agent_interface_list
 
@@ -1786,7 +1786,7 @@
 
             callback_writer.newline("class " + callback_name + " : public CallbackBase {\n")
             callback_writer.newline("public:\n")
-            callback_writer.newline("    " + callback_name + "(PassRefPtrWillBeRawPtr<InspectorBackendDispatcherImpl>, int id);\n")
+            callback_writer.newline("    " + callback_name + "(PassRefPtrWillBeRawPtr<InspectorBackendDispatcherImpl>, int sessionId, int id);\n")
             callback_writer.newline("    CORE_EXPORT void sendSuccess(" + ", ".join(decl_parameter_list) + ");\n")
             error_part_writer = callback_writer.insert_writer("")
             callback_writer.newline("};\n")
@@ -1807,7 +1807,7 @@
 
             ad_hoc_type_output.append(callback_output)
 
-            method_out_code += "    RefPtrWillBeRawPtr<" + agent_interface_name + "::" + callback_name + "> callback = adoptRefWillBeNoop(new " + agent_interface_name + "::" + callback_name + "(this, callId));\n"
+            method_out_code += "    RefPtrWillBeRawPtr<" + agent_interface_name + "::" + callback_name + "> callback = adoptRefWillBeNoop(new " + agent_interface_name + "::" + callback_name + "(this, sessionId, callId));\n"
             agent_call_param_list.append("callback")
             normal_response_cook_text += "    if (!error.length()) \n"
             normal_response_cook_text += "        return;\n"
diff --git a/third_party/WebKit/Source/core/inspector/CodeGeneratorInspectorStrings.py b/third_party/WebKit/Source/core/inspector/CodeGeneratorInspectorStrings.py
index e20c806b..03e46f91 100644
--- a/third_party/WebKit/Source/core/inspector/CodeGeneratorInspectorStrings.py
+++ b/third_party/WebKit/Source/core/inspector/CodeGeneratorInspectorStrings.py
@@ -43,19 +43,19 @@
 """)
 
 backend_method = (
-"""void InspectorBackendDispatcherImpl::${domainName}_$methodName(int callId, JSONObject*$requestMessageObject, JSONArray* protocolErrors)
+"""void InspectorBackendDispatcherImpl::${domainName}_$methodName(int sessionId, int callId, JSONObject*$requestMessageObject, JSONArray* protocolErrors)
 {
     if (!$agentField)
         protocolErrors->pushString("${domainName} handler is not available.");
 $methodCode
     if (protocolErrors->length()) {
-        reportProtocolError(callId, InvalidParams, String::format(InvalidParamsFormatString, commandName($commandNameIndex)), protocolErrors);
+        reportProtocolError(sessionId, callId, InvalidParams, String::format(InvalidParamsFormatString, commandName($commandNameIndex)), protocolErrors);
         return;
     }
 $agentCallParamsDeclaration
     $agentField->$methodName($agentCallParams);
 $responseCook
-    sendResponse(callId, $sendResponseCallParams);
+    sendResponse(sessionId, callId, $sendResponseCallParams);
 }
 """)
 
@@ -69,7 +69,7 @@
 """)
 
 callback_main_methods = (
-"""InspectorBackendDispatcher::$agentName::$callbackName::$callbackName(PassRefPtrWillBeRawPtr<InspectorBackendDispatcherImpl> backendImpl, int id) : CallbackBase(backendImpl, id) {}
+"""InspectorBackendDispatcher::$agentName::$callbackName::$callbackName(PassRefPtrWillBeRawPtr<InspectorBackendDispatcherImpl> backendImpl, int sessionId, int id) : CallbackBase(backendImpl, sessionId, id) {}
 
 void InspectorBackendDispatcher::$agentName::$callbackName::sendSuccess($parameters)
 {
@@ -150,7 +150,7 @@
 
     class CORE_EXPORT CallbackBase: public RefCountedWillBeGarbageCollectedFinalized<CallbackBase> {
     public:
-        CallbackBase(PassRefPtrWillBeRawPtr<InspectorBackendDispatcherImpl> backendImpl, int id);
+        CallbackBase(PassRefPtrWillBeRawPtr<InspectorBackendDispatcherImpl> backendImpl, int sessionId, int id);
         virtual ~CallbackBase();
         DECLARE_VIRTUAL_TRACE();
         void sendFailure(const ErrorString&);
@@ -163,6 +163,7 @@
         void disable() { m_alreadySent = true; }
 
         RefPtrWillBeMember<InspectorBackendDispatcherImpl> m_backendImpl;
+        int m_sessionId;
         int m_id;
         bool m_alreadySent;
 
@@ -184,9 +185,9 @@
         LastEntry,
     };
 
-    void reportProtocolError(int callId, CommonErrorCode, const String& errorMessage) const;
-    virtual void reportProtocolError(int callId, CommonErrorCode, const String& errorMessage, PassRefPtr<JSONValue> data) const = 0;
-    virtual void dispatch(const String& message) = 0;
+    void reportProtocolError(int sessionId, int callId, CommonErrorCode, const String& errorMessage) const;
+    virtual void reportProtocolError(int sessionId, int callId, CommonErrorCode, const String& errorMessage, PassRefPtr<JSONValue> data) const = 0;
+    virtual void dispatch(int sessionId, const String& message) = 0;
     static bool getCommandName(const String& message, String* result);
 
     enum MethodNames {
@@ -258,16 +259,16 @@
     }
 
     virtual void clearFrontend() { m_inspectorFrontendChannel = 0; }
-    virtual void dispatch(const String& message);
-    virtual void reportProtocolError(int callId, CommonErrorCode, const String& errorMessage, PassRefPtr<JSONValue> data) const;
+    virtual void dispatch(int sessionId, const String& message);
+    virtual void reportProtocolError(int sessionId, int callId, CommonErrorCode, const String& errorMessage, PassRefPtr<JSONValue> data) const;
     using InspectorBackendDispatcher::reportProtocolError;
 
-    void sendResponse(int callId, const ErrorString& invocationError, PassRefPtr<JSONValue> errorData, PassRefPtr<JSONObject> result);
+    void sendResponse(int sessionId, int callId, const ErrorString& invocationError, PassRefPtr<JSONValue> errorData, PassRefPtr<JSONObject> result);
     bool isActive() { return m_inspectorFrontendChannel; }
 
 $setters
 private:
-    using CallHandler = void (InspectorBackendDispatcherImpl::*)(int callId, JSONObject* messageObject, JSONArray* protocolErrors);
+    using CallHandler = void (InspectorBackendDispatcherImpl::*)(int sessionId, int callId, JSONObject* messageObject, JSONArray* protocolErrors);
     using DispatchMap = HashMap<String, CallHandler>;
 
 $methodDeclarations
@@ -285,13 +286,13 @@
     static PassRefPtr<JSONObject> getObject(JSONObject* object, const char* name, bool* valueFound, JSONArray* protocolErrors);
     static PassRefPtr<JSONArray> getArray(JSONObject* object, const char* name, bool* valueFound, JSONArray* protocolErrors);
 
-    void sendResponse(int callId, ErrorString invocationError, PassRefPtr<JSONObject> result)
+    void sendResponse(int sessionId, int callId, ErrorString invocationError, PassRefPtr<JSONObject> result)
     {
-        sendResponse(callId, invocationError, RefPtr<JSONValue>(), result);
+        sendResponse(sessionId, callId, invocationError, RefPtr<JSONValue>(), result);
     }
-    void sendResponse(int callId, ErrorString invocationError)
+    void sendResponse(int sessionId, int callId, ErrorString invocationError)
     {
-        sendResponse(callId, invocationError, RefPtr<JSONValue>(), JSONObject::create());
+        sendResponse(sessionId, callId, invocationError, RefPtr<JSONValue>(), JSONObject::create());
     }
     static const char InvalidParamsFormatString[];
 
@@ -309,7 +310,7 @@
 }
 
 
-void InspectorBackendDispatcherImpl::dispatch(const String& message)
+void InspectorBackendDispatcherImpl::dispatch(int sessionId, const String& message)
 {
     RefPtrWillBeRawPtr<InspectorBackendDispatcher> protect(this);
     int callId = 0;
@@ -329,18 +330,18 @@
 
     HashMap<String, CallHandler>::iterator it = m_dispatchMap.find(method);
     if (it == m_dispatchMap.end()) {
-        reportProtocolError(callId, MethodNotFound, "'" + method + "' wasn't found");
+        reportProtocolError(sessionId, callId, MethodNotFound, "'" + method + "' wasn't found");
         return;
     }
 
     RefPtr<JSONArray> protocolErrors = JSONArray::create();
-    ((*this).*it->value)(callId, messageObject.get(), protocolErrors.get());
+    ((*this).*it->value)(sessionId, callId, messageObject.get(), protocolErrors.get());
 }
 
-void InspectorBackendDispatcherImpl::sendResponse(int callId, const ErrorString& invocationError, PassRefPtr<JSONValue> errorData, PassRefPtr<JSONObject> result)
+void InspectorBackendDispatcherImpl::sendResponse(int sessionId, int callId, const ErrorString& invocationError, PassRefPtr<JSONValue> errorData, PassRefPtr<JSONObject> result)
 {
     if (invocationError.length()) {
-        reportProtocolError(callId, ServerError, invocationError, errorData);
+        reportProtocolError(sessionId, callId, ServerError, invocationError, errorData);
         return;
     }
 
@@ -348,15 +349,15 @@
     responseMessage->setNumber("id", callId);
     responseMessage->setObject("result", result);
     if (m_inspectorFrontendChannel)
-        m_inspectorFrontendChannel->sendProtocolResponse(callId, responseMessage.release());
+        m_inspectorFrontendChannel->sendProtocolResponse(sessionId, callId, responseMessage.release());
 }
 
-void InspectorBackendDispatcher::reportProtocolError(int callId, CommonErrorCode code, const String& errorMessage) const
+void InspectorBackendDispatcher::reportProtocolError(int sessionId, int callId, CommonErrorCode code, const String& errorMessage) const
 {
-    reportProtocolError(callId, code, errorMessage, PassRefPtr<JSONValue>());
+    reportProtocolError(sessionId, callId, code, errorMessage, PassRefPtr<JSONValue>());
 }
 
-void InspectorBackendDispatcherImpl::reportProtocolError(int callId, CommonErrorCode code, const String& errorMessage, PassRefPtr<JSONValue> data) const
+void InspectorBackendDispatcherImpl::reportProtocolError(int sessionId, int callId, CommonErrorCode code, const String& errorMessage, PassRefPtr<JSONValue> data) const
 {
     ASSERT(code >=0);
     ASSERT((unsigned)code < m_commonErrors.size());
@@ -371,7 +372,7 @@
     message->setObject("error", error);
     message->setNumber("id", callId);
     if (m_inspectorFrontendChannel)
-        m_inspectorFrontendChannel->sendProtocolResponse(callId, message.release());
+        m_inspectorFrontendChannel->sendProtocolResponse(sessionId, callId, message.release());
 }
 
 template<typename R, typename V, typename V0>
@@ -464,8 +465,8 @@
     return true;
 }
 
-InspectorBackendDispatcher::CallbackBase::CallbackBase(PassRefPtrWillBeRawPtr<InspectorBackendDispatcherImpl> backendImpl, int id)
-    : m_backendImpl(backendImpl), m_id(id), m_alreadySent(false) {}
+InspectorBackendDispatcher::CallbackBase::CallbackBase(PassRefPtrWillBeRawPtr<InspectorBackendDispatcherImpl> backendImpl, int sessionId, int id)
+    : m_backendImpl(backendImpl), m_sessionId(sessionId), m_id(id), m_alreadySent(false) {}
 
 InspectorBackendDispatcher::CallbackBase::~CallbackBase() {}
 
@@ -489,7 +490,7 @@
 {
     if (m_alreadySent)
         return;
-    m_backendImpl->sendResponse(m_id, invocationError, errorData, partialMessage);
+    m_backendImpl->sendResponse(m_sessionId, m_id, invocationError, errorData, partialMessage);
     m_alreadySent = true;
 }
 
diff --git a/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.cpp b/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.cpp
index 9eb7a10..4c39e02 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.cpp
+++ b/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.cpp
@@ -30,8 +30,10 @@
 #include "core/CSSPropertyNames.h"
 #include "core/InspectorTypeBuilder.h"
 #include "core/StylePropertyShorthand.h"
+#include "core/css/CSSColorValue.h"
 #include "core/css/CSSComputedStyleDeclaration.h"
 #include "core/css/CSSDefaultStyleSheets.h"
+#include "core/css/CSSGradientValue.h"
 #include "core/css/CSSImportRule.h"
 #include "core/css/CSSKeyframeRule.h"
 #include "core/css/CSSMediaRule.h"
@@ -52,7 +54,9 @@
 #include "core/dom/Node.h"
 #include "core/dom/StyleEngine.h"
 #include "core/dom/Text.h"
+#include "core/frame/FrameView.h"
 #include "core/frame/LocalFrame.h"
+#include "core/html/HTMLFrameOwnerElement.h"
 #include "core/html/HTMLHeadElement.h"
 #include "core/html/VoidCallback.h"
 #include "core/inspector/IdentifiersFactory.h"
@@ -62,13 +66,18 @@
 #include "core/inspector/InspectorResourceContentLoader.h"
 #include "core/inspector/InspectorState.h"
 #include "core/inspector/InstrumentingAgents.h"
+#include "core/layout/HitTestResult.h"
 #include "core/layout/LayoutObject.h"
 #include "core/layout/LayoutObjectInlines.h"
 #include "core/layout/LayoutText.h"
 #include "core/layout/LayoutTextFragment.h"
+#include "core/layout/LayoutView.h"
 #include "core/layout/line/InlineTextBox.h"
 #include "core/loader/DocumentLoader.h"
 #include "core/page/Page.h"
+#include "core/style/StyleGeneratedImage.h"
+#include "core/style/StyleImage.h"
+#include "core/svg/SVGElement.h"
 #include "platform/fonts/Font.h"
 #include "platform/fonts/FontCache.h"
 #include "platform/fonts/GlyphBuffer.h"
@@ -129,6 +138,132 @@
     return uniqRuleList.release();
 }
 
+// Get the elements which overlap the given rectangle.
+WillBeHeapVector<RawPtrWillBeMember<Element>> elementsFromRect(LayoutRect rect, Document& document)
+{
+    HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::ListBased | HitTestRequest::PenetratingList | HitTestRequest::IgnoreClipping);
+
+    LayoutPoint center = rect.center();
+    unsigned leftPadding, rightPadding, topPadding, bottomPadding;
+    leftPadding = rightPadding = rect.width() / 2;
+    topPadding = bottomPadding = rect.height() / 2;
+    HitTestResult result(request, center, topPadding, rightPadding, bottomPadding, leftPadding);
+    document.frame()->contentLayoutObject()->hitTest(result);
+    return document.elementsFromHitTestResult(result);
+}
+
+// Blends the colors from the given gradient with the existing colors.
+void blendWithColorsFromGradient(CSSGradientValue* gradient, WillBeHeapVector<Color>& colors, bool& foundNonTransparentColor, bool& foundOpaqueColor, const LayoutObject* layoutObject)
+{
+    WillBeHeapVector<Color> stopColors;
+    gradient->getStopColors(stopColors, layoutObject);
+
+    if (colors.isEmpty()) {
+        colors.appendRange(stopColors.begin(), stopColors.end());
+    } else {
+        if (colors.size() > 1) {
+            // Gradient on gradient is too complicated, bail out
+            colors.clear();
+            return;
+        }
+
+        Color existingColor = colors.first();
+        colors.clear();
+        for (auto stopColor : stopColors) {
+            foundNonTransparentColor = foundNonTransparentColor || (stopColor.alpha() != 0);
+            colors.append(existingColor.blend(stopColor));
+        }
+    }
+    foundOpaqueColor = foundOpaqueColor || gradient->knownToBeOpaque(layoutObject);
+}
+
+// Gets the colors from an image style, if one exists and it is a gradient.
+void addColorsFromImageStyle(const ComputedStyle& style, WillBeHeapVector<Color>& colors, bool& foundOpaqueColor, bool& foundNonTransparentColor, const LayoutObject* layoutObject)
+{
+    const FillLayer& backgroundLayers = style.backgroundLayers();
+    if (!backgroundLayers.hasImage())
+        return;
+
+    StyleImage* styleImage = backgroundLayers.image();
+    if (!styleImage->isGeneratedImage()) {
+        // Make no assertions about the colors in non-generated images
+        colors.clear();
+        foundOpaqueColor = false;
+        return;
+    }
+
+    StyleGeneratedImage* genImage = toStyleGeneratedImage(styleImage);
+    RefPtrWillBeRawPtr<CSSValue> imageCSS = genImage->cssValue();
+    if (imageCSS->isGradientValue()) {
+        CSSGradientValue* gradient = toCSSGradientValue(imageCSS.get());
+        blendWithColorsFromGradient(gradient, colors, foundNonTransparentColor, foundOpaqueColor, layoutObject);
+    }
+    return;
+}
+
+// Get the background colors behind the given rect in the given document, by
+// walking up all the elements returned by a hit test (but not going beyond
+// |topElement|) covering the area of the rect, and blending their background
+// colors.
+bool getColorsFromRect(LayoutRect rect, Document& document, Element* topElement, WillBeHeapVector<Color>& colors)
+{
+    WillBeHeapVector<RawPtrWillBeMember<Element>> elementsUnderRect = elementsFromRect(rect, document);
+
+    bool foundOpaqueColor = false;
+    bool foundTopElement = false;
+
+    for (auto e = elementsUnderRect.rbegin(); !foundTopElement && e != elementsUnderRect.rend(); ++e) {
+        const Element* element = *e;
+        if (element->isSameNode(topElement))
+            foundTopElement = true;
+
+        const LayoutObject* layoutObject = element->layoutObject();
+        if (!layoutObject)
+            continue;
+
+        if (isHTMLCanvasElement(element) || isHTMLEmbedElement(element) || isHTMLImageElement(element) || isHTMLObjectElement(element) || isHTMLPictureElement(element) || element->isSVGElement() || isHTMLVideoElement(element)) {
+            colors.clear();
+            foundOpaqueColor = false;
+            continue;
+        }
+
+        const ComputedStyle* style = layoutObject->style();
+        if (!style)
+            continue;
+
+        Color backgroundColor = style->visitedDependentColor(CSSPropertyBackgroundColor);
+        bool foundNonTransparentColor = false;
+        if (backgroundColor.alpha() != 0) {
+            foundNonTransparentColor = true;
+            if (colors.isEmpty()) {
+                if (!backgroundColor.hasAlpha())
+                    foundOpaqueColor = true;
+                colors.append(backgroundColor);
+            } else {
+                if (!backgroundColor.hasAlpha()) {
+                    colors.clear();
+                    colors.append(backgroundColor);
+                    foundOpaqueColor = true;
+                } else {
+                    for (size_t i = 0; i < colors.size(); i++)
+                        colors[i] = colors[i].blend(backgroundColor);
+                    foundOpaqueColor = foundOpaqueColor || backgroundColor.hasAlpha();
+                }
+            }
+        }
+
+        addColorsFromImageStyle(*style, colors, foundOpaqueColor, foundNonTransparentColor, layoutObject);
+
+        bool contains = foundTopElement || element->boundingBox().contains(rect);
+        if (!contains && foundNonTransparentColor) {
+            // Only return colors if some opaque element covers up this one.
+            colors.clear();
+            foundOpaqueColor = false;
+        }
+    }
+    return foundOpaqueColor;
+}
+
 } // namespace
 
 namespace CSSAgentState {
@@ -493,7 +628,7 @@
 {
     if (!m_invalidatedDocuments.size())
         return;
-    WillBeHeapHashSet<RawPtrWillBeMember<Document> > invalidatedDocuments;
+    WillBeHeapHashSet<RawPtrWillBeMember<Document>> invalidatedDocuments;
     m_invalidatedDocuments.swap(&invalidatedDocuments);
     for (Document* document: invalidatedDocuments)
         updateActiveStyleSheets(document, ExistingFrontendRefresh);
@@ -1802,6 +1937,58 @@
     setCSSPropertyValue(errorString, element, foundStyle.get(), propertyId, value);
 }
 
+void InspectorCSSAgent::getBackgroundColors(ErrorString* errorString, int nodeId, RefPtr<TypeBuilder::Array<String>>& result)
+{
+    Element* element = elementForId(errorString, nodeId);
+    if (!element) {
+        *errorString = "Node not found";
+        return;
+    }
+
+    LayoutRect textBounds;
+    LayoutObject* elementLayout = element->layoutObject();
+    if (!elementLayout)
+        return;
+
+    for (const LayoutObject* child = elementLayout->slowFirstChild(); child; child = child->nextSibling()) {
+        if (!child->isText())
+            continue;
+        textBounds.unite(LayoutRect(child->absoluteBoundingBoxRect()));
+    }
+    if (textBounds.size().isEmpty())
+        return;
+
+    WillBeHeapVector<Color> colors;
+    FrameView* view = element->document().view();
+    if (!view) {
+        *errorString = "No view.";
+        return;
+    }
+    Document& document = element->document();
+    bool isMainFrame = !document.ownerElement();
+    bool foundOpaqueColor = false;
+    if (isMainFrame && !view->isTransparent()) {
+        // Start with the "default" page color (typically white).
+        Color baseBackgroundColor = view->baseBackgroundColor();
+        colors.append(view->baseBackgroundColor());
+        foundOpaqueColor = !baseBackgroundColor.hasAlpha();
+    }
+
+    foundOpaqueColor = getColorsFromRect(textBounds, element->document(), element, colors);
+
+    if (!foundOpaqueColor && !isMainFrame) {
+        for (HTMLFrameOwnerElement* ownerElement = document.ownerElement();
+            !foundOpaqueColor && ownerElement;
+            ownerElement = ownerElement->document().ownerElement()) {
+            foundOpaqueColor = getColorsFromRect(textBounds, ownerElement->document(), nullptr, colors);
+        }
+    }
+
+    result = TypeBuilder::Array<String>::create();
+    for (auto color : colors)
+        result->addItem(color.serializedAsCSSComponentValue());
+}
+
 DEFINE_TRACE(InspectorCSSAgent)
 {
     visitor->trace(m_domAgent);
diff --git a/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.h b/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.h
index e36ad82..996dbc1 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.h
+++ b/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.h
@@ -143,6 +143,8 @@
     void forcePseudoState(ErrorString*, int nodeId, const RefPtr<JSONArray>& forcedPseudoClasses) override;
     void getMediaQueries(ErrorString*, RefPtr<TypeBuilder::Array<TypeBuilder::CSS::CSSMedia>>& medias) override;
     void setEffectivePropertyValueForNode(ErrorString*, int nodeId, const String& propertyName, const String& value) override;
+    void getBackgroundColors(ErrorString*, int nodeId, RefPtr<TypeBuilder::Array<String>>& result) override;
+
     void collectMediaQueriesFromRule(CSSRule*, TypeBuilder::Array<TypeBuilder::CSS::CSSMedia>* mediaArray);
     void collectMediaQueriesFromStyleSheet(CSSStyleSheet*, TypeBuilder::Array<TypeBuilder::CSS::CSSMedia>* mediaArray);
     PassRefPtr<TypeBuilder::CSS::CSSMedia> buildMediaObject(const MediaList*, MediaListSource, const String&, CSSStyleSheet*);
diff --git a/third_party/WebKit/Source/core/inspector/InspectorFrontendChannel.h b/third_party/WebKit/Source/core/inspector/InspectorFrontendChannel.h
index 8b687d1..580a12d3 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorFrontendChannel.h
+++ b/third_party/WebKit/Source/core/inspector/InspectorFrontendChannel.h
@@ -34,7 +34,7 @@
 class InspectorFrontendChannel {
 public:
     virtual ~InspectorFrontendChannel() { }
-    virtual void sendProtocolResponse(int callId, PassRefPtr<JSONObject> message) = 0;
+    virtual void sendProtocolResponse(int sessionId, int callId, PassRefPtr<JSONObject> message) = 0;
     virtual void sendProtocolNotification(PassRefPtr<JSONObject> message) = 0;
     virtual void flush() = 0;
 };
diff --git a/third_party/WebKit/Source/core/inspector/InspectorResourceAgent.cpp b/third_party/WebKit/Source/core/inspector/InspectorResourceAgent.cpp
index 651b6ce..8a4228a 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorResourceAgent.cpp
+++ b/third_party/WebKit/Source/core/inspector/InspectorResourceAgent.cpp
@@ -411,6 +411,7 @@
 
 DEFINE_TRACE(InspectorResourceAgent)
 {
+    visitor->trace(m_resourcesData);
     visitor->trace(m_replayXHRs);
     visitor->trace(m_replayXHRsToBeDeleted);
     visitor->trace(m_pendingXHRReplayData);
@@ -1091,7 +1092,7 @@
 InspectorResourceAgent::InspectorResourceAgent(InspectedFrames* inspectedFrames)
     : InspectorBaseAgent<InspectorResourceAgent, InspectorFrontend::Network>("Network")
     , m_inspectedFrames(inspectedFrames)
-    , m_resourcesData(adoptPtr(new NetworkResourcesData()))
+    , m_resourcesData(NetworkResourcesData::create())
     , m_pendingRequest(nullptr)
     , m_isRecalculatingStyle(false)
     , m_removeFinishedReplayXHRTimer(this, &InspectorResourceAgent::removeFinishedReplayXHRFired)
diff --git a/third_party/WebKit/Source/core/inspector/InspectorResourceAgent.h b/third_party/WebKit/Source/core/inspector/InspectorResourceAgent.h
index 424c298..eebf270 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorResourceAgent.h
+++ b/third_party/WebKit/Source/core/inspector/InspectorResourceAgent.h
@@ -168,7 +168,7 @@
     InspectedFrames* m_inspectedFrames;
     String m_userAgentOverride;
     String m_hostId;
-    OwnPtr<NetworkResourcesData> m_resourcesData;
+    OwnPtrWillBeMember<NetworkResourcesData> m_resourcesData;
 
     typedef HashMap<ThreadableLoaderClient*, unsigned long> ThreadableLoaderClientRequestIdMap;
 
diff --git a/third_party/WebKit/Source/core/inspector/NetworkResourcesData.cpp b/third_party/WebKit/Source/core/inspector/NetworkResourcesData.cpp
index dc76af4..385807fe 100644
--- a/third_party/WebKit/Source/core/inspector/NetworkResourcesData.cpp
+++ b/third_party/WebKit/Source/core/inspector/NetworkResourcesData.cpp
@@ -82,6 +82,12 @@
 {
 }
 
+DEFINE_TRACE(NetworkResourcesData::ResourceData)
+{
+    visitor->trace(m_xhrReplayData);
+    visitor->trace(m_cachedResource);
+}
+
 void NetworkResourcesData::ResourceData::setContent(const String& content, bool base64Encoded)
 {
     ASSERT(!hasData());
@@ -152,7 +158,16 @@
 
 NetworkResourcesData::~NetworkResourcesData()
 {
+#if !ENABLE(OILPAN)
     clear();
+#endif
+}
+
+DEFINE_TRACE(NetworkResourcesData)
+{
+#if ENABLE(OILPAN)
+    visitor->trace(m_requestIdToResourceDataMap);
+#endif
 }
 
 void NetworkResourcesData::resourceCreated(const String& requestId, const String& loaderId)
@@ -295,9 +310,9 @@
     resourceData->setXHRReplayData(xhrReplayData);
 }
 
-Vector<NetworkResourcesData::ResourceData*> NetworkResourcesData::resources()
+WillBeHeapVector<RawPtrWillBeMember<NetworkResourcesData::ResourceData>> NetworkResourcesData::resources()
 {
-    Vector<ResourceData*> result;
+    WillBeHeapVector<RawPtrWillBeMember<ResourceData>> result;
     for (auto& request : m_requestIdToResourceDataMap)
         result.append(request.value);
     return result;
@@ -328,8 +343,10 @@
         ResourceData* resourceData = resource.value;
         if (!preservedLoaderId.isNull() && resourceData->loaderId() == preservedLoaderId)
             preservedMap.set(resource.key, resource.value);
+#if !ENABLE(OILPAN)
         else
             delete resourceData;
+#endif
     }
     m_requestIdToResourceDataMap.swap(preservedMap);
 
@@ -359,7 +376,9 @@
         return;
     if (resourceData->hasContent() || resourceData->hasData())
         m_contentSize -= resourceData->evictContent();
+#if !ENABLE(OILPAN)
     delete resourceData;
+#endif
     m_requestIdToResourceDataMap.remove(requestId);
 }
 
@@ -378,4 +397,3 @@
 }
 
 } // namespace blink
-
diff --git a/third_party/WebKit/Source/core/inspector/NetworkResourcesData.h b/third_party/WebKit/Source/core/inspector/NetworkResourcesData.h
index 404fc326..3f2a4fb 100644
--- a/third_party/WebKit/Source/core/inspector/NetworkResourcesData.h
+++ b/third_party/WebKit/Source/core/inspector/NetworkResourcesData.h
@@ -78,11 +78,11 @@
     bool m_includeCredentials;
 };
 
-class NetworkResourcesData {
-    USING_FAST_MALLOC(NetworkResourcesData);
+class NetworkResourcesData final : public NoBaseWillBeGarbageCollectedFinalized<NetworkResourcesData> {
+    USING_FAST_MALLOC_WILL_BE_REMOVED(NetworkResourcesData);
 public:
-    class ResourceData {
-        USING_FAST_MALLOC(ResourceData);
+    class ResourceData final : public NoBaseWillBeGarbageCollectedFinalized<ResourceData> {
+        USING_FAST_MALLOC_WILL_BE_REMOVED(ResourceData);
         friend class NetworkResourcesData;
     public:
         ResourceData(const String& requestId, const String& loaderId);
@@ -133,6 +133,7 @@
         BlobDataHandle* downloadedFileBlob() const { return m_downloadedFileBlob.get(); }
         void setDownloadedFileBlob(PassRefPtr<BlobDataHandle> blob) { m_downloadedFileBlob = blob; }
 
+        DECLARE_TRACE();
     private:
         bool hasData() const { return m_dataBuffer; }
         size_t dataLength() const;
@@ -144,7 +145,7 @@
         String m_frameId;
         KURL m_url;
         String m_content;
-        RefPtrWillBePersistent<XHRReplayData> m_xhrReplayData;
+        RefPtrWillBeMember<XHRReplayData> m_xhrReplayData;
         bool m_base64Encoded;
         RefPtr<SharedBuffer> m_dataBuffer;
         bool m_isContentEvicted;
@@ -156,12 +157,14 @@
         OwnPtr<TextResourceDecoder> m_decoder;
 
         RefPtr<SharedBuffer> m_buffer;
-        Resource* m_cachedResource;
+        RawPtrWillBeMember<Resource> m_cachedResource;
         RefPtr<BlobDataHandle> m_downloadedFileBlob;
     };
 
-    NetworkResourcesData();
-
+    static PassOwnPtrWillBeRawPtr<NetworkResourcesData> create()
+    {
+        return adoptPtrWillBeNoop(new NetworkResourcesData);
+    }
     ~NetworkResourcesData();
 
     void resourceCreated(const String& requestId, const String& loaderId);
@@ -179,9 +182,12 @@
     void setResourcesDataSizeLimits(size_t maximumResourcesContentSize, size_t maximumSingleResourceContentSize);
     void setXHRReplayData(const String& requestId, XHRReplayData*);
     XHRReplayData* xhrReplayData(const String& requestId);
-    Vector<ResourceData*> resources();
+    WillBeHeapVector<RawPtrWillBeMember<ResourceData>> resources();
 
+    DECLARE_TRACE();
 private:
+    NetworkResourcesData();
+
     ResourceData* resourceDataForRequestId(const String& requestId);
     void ensureNoDataForRequestId(const String& requestId);
     bool ensureFreeSpace(size_t);
@@ -190,7 +196,7 @@
 
     typedef HashMap<String, String> ReusedRequestIds;
     ReusedRequestIds m_reusedXHRReplayDataRequestIds;
-    typedef HashMap<String, ResourceData*> ResourceDataMap;
+    typedef WillBeHeapHashMap<String, RawPtrWillBeMember<ResourceData>> ResourceDataMap;
     ResourceDataMap m_requestIdToResourceDataMap;
     size_t m_contentSize;
     size_t m_maximumResourcesContentSize;
diff --git a/third_party/WebKit/Source/core/inspector/WorkerInspectorController.cpp b/third_party/WebKit/Source/core/inspector/WorkerInspectorController.cpp
index 6e1493d9..eef82379 100644
--- a/third_party/WebKit/Source/core/inspector/WorkerInspectorController.cpp
+++ b/third_party/WebKit/Source/core/inspector/WorkerInspectorController.cpp
@@ -65,7 +65,7 @@
     explicit PageInspectorProxy(WorkerGlobalScope* workerGlobalScope) : m_workerGlobalScope(workerGlobalScope) { }
     ~PageInspectorProxy() override { }
 private:
-    void sendProtocolResponse(int callId, PassRefPtr<JSONObject> message) override
+    void sendProtocolResponse(int sessionId, int callId, PassRefPtr<JSONObject> message) override
     {
         // Worker messages are wrapped, no need to handle callId.
         m_workerGlobalScope->thread()->workerReportingProxy().postMessageToPageInspector(message->toJSONString());
@@ -197,8 +197,10 @@
 void WorkerInspectorController::dispatchMessageFromFrontend(const String& message)
 {
     InspectorTaskRunner::IgnoreInterruptsScope scope(m_inspectorTaskRunner.get());
-    if (m_backendDispatcher)
-        m_backendDispatcher->dispatch(message);
+    if (m_backendDispatcher) {
+        // sessionId will be overwritten by WebDevToolsAgent::sendProtocolNotifications call.
+        m_backendDispatcher->dispatch(0, message);
+    }
 }
 
 void WorkerInspectorController::dispose()
diff --git a/third_party/WebKit/Source/core/paint/BackgroundImageGeometry.cpp b/third_party/WebKit/Source/core/paint/BackgroundImageGeometry.cpp
index d9fb1bd..8f336f2fe 100644
--- a/third_party/WebKit/Source/core/paint/BackgroundImageGeometry.cpp
+++ b/third_party/WebKit/Source/core/paint/BackgroundImageGeometry.cpp
@@ -302,7 +302,7 @@
     }
 
     if (backgroundRepeatX == RepeatFill) {
-        int xOffset = fillLayer.backgroundXOrigin() == RightEdge ? availableWidth - computedXPosition : computedXPosition;
+        LayoutUnit xOffset = fillLayer.backgroundXOrigin() == RightEdge ? availableWidth - computedXPosition : computedXPosition;
         setPhaseX(tileSize().width() ? tileSize().width() - roundToInt(xOffset + left) % tileSize().width() : 0);
         setSpaceSize(IntSize());
     } else if (backgroundRepeatX == SpaceFill && fillTileSize.width() > 0) {
@@ -318,13 +318,13 @@
         }
     }
     if (backgroundRepeatX == NoRepeatFill) {
-        int xOffset = fillLayer.backgroundXOrigin() == RightEdge ? availableWidth - computedXPosition : computedXPosition;
+        LayoutUnit xOffset = fillLayer.backgroundXOrigin() == RightEdge ? availableWidth - computedXPosition : computedXPosition;
         setNoRepeatX(left + xOffset);
         setSpaceSize(IntSize(0, spaceSize().height()));
     }
 
     if (backgroundRepeatY == RepeatFill) {
-        int yOffset = fillLayer.backgroundYOrigin() == BottomEdge ? availableHeight - computedYPosition : computedYPosition;
+        LayoutUnit yOffset = fillLayer.backgroundYOrigin() == BottomEdge ? availableHeight - computedYPosition : computedYPosition;
         setPhaseY(tileSize().height() ? tileSize().height() - roundToInt(yOffset + top) % tileSize().height() : 0);
         setSpaceSize(IntSize(spaceSize().width(), 0));
     } else if (backgroundRepeatY == SpaceFill && fillTileSize.height() > 0) {
@@ -340,7 +340,7 @@
         }
     }
     if (backgroundRepeatY == NoRepeatFill) {
-        int yOffset = fillLayer.backgroundYOrigin() == BottomEdge ? availableHeight - computedYPosition : computedYPosition;
+        LayoutUnit yOffset = fillLayer.backgroundYOrigin() == BottomEdge ? availableHeight - computedYPosition : computedYPosition;
         setNoRepeatY(top + yOffset);
         setSpaceSize(IntSize(spaceSize().width(), 0));
     }
diff --git a/third_party/WebKit/Source/core/style/DataRef.h b/third_party/WebKit/Source/core/style/DataRef.h
index d1511da1..a03fab56 100644
--- a/third_party/WebKit/Source/core/style/DataRef.h
+++ b/third_party/WebKit/Source/core/style/DataRef.h
@@ -24,6 +24,7 @@
 #ifndef DataRef_h
 #define DataRef_h
 
+#include "platform/heap/Handle.h"
 #include "wtf/Allocator.h"
 #include "wtf/RefPtr.h"
 
@@ -66,6 +67,9 @@
 
     void operator=(std::nullptr_t) { m_data = nullptr; }
 private:
+    // TODO(Oilpan): remove this once the GC plugin change in r359074 has
+    // rolled out & been deployed.
+    GC_PLUGIN_IGNORE("553613")
     RefPtr<T> m_data;
 };
 
diff --git a/third_party/WebKit/Source/core/style/StyleGeneratedImage.h b/third_party/WebKit/Source/core/style/StyleGeneratedImage.h
index 4703939..712528b1 100644
--- a/third_party/WebKit/Source/core/style/StyleGeneratedImage.h
+++ b/third_party/WebKit/Source/core/style/StyleGeneratedImage.h
@@ -67,5 +67,7 @@
     bool m_fixedSize;
 };
 
+DEFINE_STYLE_IMAGE_TYPE_CASTS(StyleGeneratedImage, isGeneratedImage());
+
 }
 #endif
diff --git a/third_party/WebKit/Source/core/svg/graphics/SVGImage.h b/third_party/WebKit/Source/core/svg/graphics/SVGImage.h
index c23f452..703913b 100644
--- a/third_party/WebKit/Source/core/svg/graphics/SVGImage.h
+++ b/third_party/WebKit/Source/core/svg/graphics/SVGImage.h
@@ -54,6 +54,7 @@
     LayoutBox* embeddedContentBox() const;
 
     bool isSVGImage() const override { return true; }
+    bool isTextureBacked() override { return false; }
     IntSize size() const override { return m_intrinsicSize; }
     void setURL(const KURL& url) { m_url = url; }
 
diff --git a/third_party/WebKit/Source/core/workers/WorkerThread.cpp b/third_party/WebKit/Source/core/workers/WorkerThread.cpp
index 3027f169..c4a731a6 100644
--- a/third_party/WebKit/Source/core/workers/WorkerThread.cpp
+++ b/third_party/WebKit/Source/core/workers/WorkerThread.cpp
@@ -291,6 +291,8 @@
         if (RuntimeEnabledFeatures::v8IdleTasksEnabled()) {
             V8PerIsolateData::enableIdleTasks(m_isolate, adoptPtr(new V8IdleTaskRunner(m_webScheduler)));
         }
+        // Optimize for memory usage instead of latency for the worker isolate.
+        m_isolate->IsolateInBackgroundNotification();
         m_workerGlobalScope = createWorkerGlobalScope(startupData);
         m_workerGlobalScope->scriptLoaded(sourceCode.length(), cachedMetaData.get() ? cachedMetaData->size() : 0);
 
diff --git a/third_party/WebKit/Source/devtools/front_end/common/Color.js b/third_party/WebKit/Source/devtools/front_end/common/Color.js
index 6d58c5c..d6f96ff 100644
--- a/third_party/WebKit/Source/devtools/front_end/common/Color.js
+++ b/third_party/WebKit/Source/devtools/front_end/common/Color.js
@@ -565,16 +565,16 @@
  * Combine the two given color according to alpha blending.
  * @param {!Array<number>} fgRGBA
  * @param {!Array<number>} bgRGBA
- * @param {!Array<number>} out_flattened
+ * @param {!Array<number>} out_blended
  */
-WebInspector.Color.flattenColors = function(fgRGBA, bgRGBA, out_flattened)
+WebInspector.Color.blendColors = function(fgRGBA, bgRGBA, out_blended)
 {
     var alpha = fgRGBA[3];
 
-    out_flattened[0] = ((1 - alpha) * bgRGBA[0]) + (alpha * fgRGBA[0]);
-    out_flattened[1] = ((1 - alpha) * bgRGBA[1]) + (alpha * fgRGBA[1]);
-    out_flattened[2] = ((1 - alpha) * bgRGBA[2]) + (alpha * fgRGBA[2]);
-    out_flattened[3] = alpha + (bgRGBA[3] * (1 - alpha));
+    out_blended[0] = ((1 - alpha) * bgRGBA[0]) + (alpha * fgRGBA[0]);
+    out_blended[1] = ((1 - alpha) * bgRGBA[1]) + (alpha * fgRGBA[1]);
+    out_blended[2] = ((1 - alpha) * bgRGBA[2]) + (alpha * fgRGBA[2]);
+    out_blended[3] = alpha + (bgRGBA[3] * (1 - alpha));
 }
 
 /**
@@ -587,20 +587,20 @@
  */
 WebInspector.Color.calculateContrastRatio = function(fgRGBA, bgRGBA)
 {
-    WebInspector.Color.flattenColors(fgRGBA, bgRGBA, WebInspector.Color.calculateContrastRatio._flattenedFg);
+    WebInspector.Color.blendColors(fgRGBA, bgRGBA, WebInspector.Color.calculateContrastRatio._blendedFg);
 
-    var fgLuminance = WebInspector.Color.luminance(WebInspector.Color.calculateContrastRatio._flattenedFg);
+    var fgLuminance = WebInspector.Color.luminance(WebInspector.Color.calculateContrastRatio._blendedFg);
     var bgLuminance = WebInspector.Color.luminance(bgRGBA);
     var contrastRatio = (Math.max(fgLuminance, bgLuminance) + 0.05) /
         (Math.min(fgLuminance, bgLuminance) + 0.05);
 
-    for (var i = 0; i < WebInspector.Color.calculateContrastRatio._flattenedFg.length; i++)
-        WebInspector.Color.calculateContrastRatio._flattenedFg[i] = 0;
+    for (var i = 0; i < WebInspector.Color.calculateContrastRatio._blendedFg.length; i++)
+        WebInspector.Color.calculateContrastRatio._blendedFg[i] = 0;
 
     return contrastRatio;
 }
 
-WebInspector.Color.calculateContrastRatio._flattenedFg = [0, 0, 0, 0];
+WebInspector.Color.calculateContrastRatio._blendedFg = [0, 0, 0, 0];
 
 /**
  * Compute a desired luminance given a given luminance and a desired contrast
diff --git a/third_party/WebKit/Source/devtools/front_end/elements/Spectrum.js b/third_party/WebKit/Source/devtools/front_end/elements/Spectrum.js
index 16ab34a..4199a07 100644
--- a/third_party/WebKit/Source/devtools/front_end/elements/Spectrum.js
+++ b/third_party/WebKit/Source/devtools/front_end/elements/Spectrum.js
@@ -730,8 +730,8 @@
         var pathBuilder = [];
         var candidateRGBA = [];
         WebInspector.Color.hsva2rgba(candidateHSVA, candidateRGBA);
-        var flattenedRGBA = [];
-        WebInspector.Color.flattenColors(candidateRGBA, bgRGBA, flattenedRGBA);
+        var blendedRGBA = [];
+        WebInspector.Color.blendColors(candidateRGBA, bgRGBA, blendedRGBA);
 
         /**
          * Approach the desired contrast ratio by modifying the given component
@@ -746,8 +746,8 @@
             while (0 <= x && x <= 1) {
                 candidateHSVA[index] = x;
                 WebInspector.Color.hsva2rgba(candidateHSVA, candidateRGBA);
-                WebInspector.Color.flattenColors(candidateRGBA, bgRGBA, flattenedRGBA);
-                var fgLuminance = WebInspector.Color.luminance(flattenedRGBA);
+                WebInspector.Color.blendColors(candidateRGBA, bgRGBA, blendedRGBA);
+                var fgLuminance = WebInspector.Color.luminance(blendedRGBA);
                 var dLuminance = fgLuminance - desiredLuminance;
 
                 if (Math.abs(dLuminance) < (onAxis ? epsilon / 10 : epsilon))
diff --git a/third_party/WebKit/Source/devtools/front_end/elements/StylesSidebarPane.js b/third_party/WebKit/Source/devtools/front_end/elements/StylesSidebarPane.js
index cdd3659..d4351b4 100644
--- a/third_party/WebKit/Source/devtools/front_end/elements/StylesSidebarPane.js
+++ b/third_party/WebKit/Source/devtools/front_end/elements/StylesSidebarPane.js
@@ -1906,23 +1906,35 @@
         var swatchIcon = new WebInspector.ColorSwatchPopoverIcon(this, stylesPopoverHelper, text);
 
         /**
-         * @param {?Map.<string, string>} styles
+         * @param {?Array<string>} backgroundColors
          */
-        function computedCallback(styles)
+        function computedCallback(backgroundColors)
         {
-            if (!styles)
+            // TODO(aboxhall): distinguish between !backgroundColors (no text) and
+            // !backgroundColors.length (no computed bg color)
+            if (!backgroundColors || !backgroundColors.length)
                 return;
-            var bgColorText = styles.get("background-color") || "";
+            // TODO(samli): figure out what to do in the case of multiple background colors (i.e. gradients)
+            var bgColorText = backgroundColors[0];
             var bgColor = WebInspector.Color.parse(bgColorText);
-            // TODO(aboxhall): for background color with alpha, compute the actual
-            // visible background color (blended with content underneath).
-            if (bgColor && !bgColor.hasAlpha())
-                swatchIcon.setContrastColor(bgColor);
+            if (!bgColor)
+                return;
+
+            // If we have a semi-transparent background color over an unknown
+            // background, draw the line for the "worst case" scenario: where
+            // the unknown background is the same color as the text.
+            if (bgColor.hasAlpha) {
+                var blendedRGBA = [];
+                WebInspector.Color.blendColors(bgColor.rgba(), color.rgba(), blendedRGBA);
+                bgColor = new WebInspector.Color(blendedRGBA, WebInspector.Color.Format.RGBA);
+            }
+
+            swatchIcon.setContrastColor(bgColor);
         }
 
         if (this.property.name === "color" && this._parentPane.cssModel() && this.node()) {
             var cssModel = this._parentPane.cssModel();
-            cssModel.computedStylePromise(this.node().id).then(computedCallback);
+            cssModel.backgroundColorsPromise(this.node().id).then(computedCallback);
         }
 
         return swatchIcon.element();
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/CSSStyleModel.js b/third_party/WebKit/Source/devtools/front_end/sdk/CSSStyleModel.js
index 7a5addac..bb91c40 100644
--- a/third_party/WebKit/Source/devtools/front_end/sdk/CSSStyleModel.js
+++ b/third_party/WebKit/Source/devtools/front_end/sdk/CSSStyleModel.js
@@ -160,6 +160,23 @@
 
     /**
      * @param {number} nodeId
+     * @return {!Promise<?Array<string>>}
+     */
+    backgroundColorsPromise: function(nodeId)
+    {
+        /**
+         * @param {?string} error
+         * @param {!Array<string>=} backgroundColors
+         * @return {?Array<string>}
+         */
+        function backgroundColorsCallback(error, backgroundColors) {
+            return !error && backgroundColors ? backgroundColors : null;
+        }
+        return this._agent.getBackgroundColors(nodeId, backgroundColorsCallback);
+    },
+
+    /**
+     * @param {number} nodeId
      * @return {!Promise.<?Array.<!CSSAgent.PlatformFontUsage>>}
      */
     platformFontsPromise: function(nodeId)
diff --git a/third_party/WebKit/Source/devtools/protocol.json b/third_party/WebKit/Source/devtools/protocol.json
index eb6d7bd..cee2240 100644
--- a/third_party/WebKit/Source/devtools/protocol.json
+++ b/third_party/WebKit/Source/devtools/protocol.json
@@ -3312,6 +3312,16 @@
                 ],
                 "description": "Find a rule with the given active property for the given node and set the new value for this property",
                 "hidden": true
+            },
+            {
+                "name": "getBackgroundColors",
+                "parameters": [
+                    { "name": "nodeId", "$ref": "DOM.NodeId", "description": "Id of the node to get background colors for." }
+                ],
+                "returns": [
+                    { "name": "backgroundColors", "type": "array", "items": { "type": "string" }, "description": "The range of background colors behind this element, if it contains any visible text. If no visible text is present, this will be undefined. In the case of a flat background color, this will consist of simply that color. In the case of a gradient, this will consist of each of the color stops. For anything more complicated, this will be an empty array. Images will be ignored (as if the image had failed to load).", "optional": true }
+                ],
+                "hidden": true
             }
         ],
         "events": [
diff --git a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.cpp b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.cpp
index f6d87e40..da219d6 100644
--- a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.cpp
+++ b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.cpp
@@ -1394,7 +1394,7 @@
     if (srcRect.isEmpty())
         return;
 
-    if (shouldDisableDeferral(imageSource) || image->imageForCurrentFrame()->isTextureBacked())
+    if (shouldDisableDeferral(imageSource) || image->isTextureBacked())
         canvas()->disableDeferral();
 
     validateStateStack();
diff --git a/third_party/WebKit/Source/platform/graphics/Image.cpp b/third_party/WebKit/Source/platform/graphics/Image.cpp
index 64d706b..2214f5b 100644
--- a/third_party/WebKit/Source/platform/graphics/Image.cpp
+++ b/third_party/WebKit/Source/platform/graphics/Image.cpp
@@ -274,4 +274,9 @@
     return image.release();
 }
 
+bool Image::isTextureBacked()
+{
+    return imageForCurrentFrame()->isTextureBacked();
+}
+
 } // namespace blink
diff --git a/third_party/WebKit/Source/platform/graphics/Image.h b/third_party/WebKit/Source/platform/graphics/Image.h
index fc9eb8d..88f43019 100644
--- a/third_party/WebKit/Source/platform/graphics/Image.h
+++ b/third_party/WebKit/Source/platform/graphics/Image.h
@@ -73,6 +73,7 @@
     virtual bool currentFrameKnownToBeOpaque() = 0;
     virtual bool currentFrameIsComplete() { return false; }
     virtual bool currentFrameIsLazyDecoded() { return false; }
+    virtual bool isTextureBacked();
 
     // Derived classes should override this if they can assure that the current
     // image frame contains only resources from its own security origin.
diff --git a/third_party/WebKit/Source/platform/heap/ThreadState.cpp b/third_party/WebKit/Source/platform/heap/ThreadState.cpp
index 9ad69b6..5dade814 100644
--- a/third_party/WebKit/Source/platform/heap/ThreadState.cpp
+++ b/third_party/WebKit/Source/platform/heap/ThreadState.cpp
@@ -709,6 +709,10 @@
     if (isGCForbidden())
         return;
 
+    if (isSweepingInProgress())
+        return;
+    ASSERT(!sweepForbidden());
+
     if (shouldForceMemoryPressureGC()) {
         completeSweep();
         if (shouldForceMemoryPressureGC()) {
@@ -720,10 +724,6 @@
         }
     }
 
-    if (isSweepingInProgress())
-        return;
-    ASSERT(!sweepForbidden());
-
     if (shouldForceConservativeGC()) {
         completeSweep();
         if (shouldForceConservativeGC()) {
diff --git a/third_party/WebKit/Source/web/WebDevToolsAgentImpl.cpp b/third_party/WebKit/Source/web/WebDevToolsAgentImpl.cpp
index 62258a2b..5565ad0 100644
--- a/third_party/WebKit/Source/web/WebDevToolsAgentImpl.cpp
+++ b/third_party/WebKit/Source/web/WebDevToolsAgentImpl.cpp
@@ -254,8 +254,9 @@
 
 class DebuggerTask : public InspectorTaskRunner::Task {
 public:
-    DebuggerTask(PassOwnPtr<WebDevToolsAgent::MessageDescriptor> descriptor)
-        : m_descriptor(descriptor)
+    DebuggerTask(int sessionId, PassOwnPtr<WebDevToolsAgent::MessageDescriptor> descriptor)
+        : m_sessionId(sessionId)
+        , m_descriptor(descriptor)
     {
     }
 
@@ -268,10 +269,11 @@
 
         WebDevToolsAgentImpl* agentImpl = static_cast<WebDevToolsAgentImpl*>(webagent);
         if (agentImpl->m_attached)
-            agentImpl->dispatchMessageFromFrontend(m_descriptor->message());
+            agentImpl->dispatchMessageFromFrontend(m_sessionId, m_descriptor->message());
     }
 
 private:
+    int m_sessionId;
     OwnPtr<WebDevToolsAgent::MessageDescriptor> m_descriptor;
 };
 
@@ -331,6 +333,7 @@
     , m_pageConsoleAgent(nullptr)
     , m_agents(m_instrumentingAgents.get(), m_state.get())
     , m_deferredAgentsInitialized(false)
+    , m_sessionId(0)
 {
     ASSERT(isMainThread());
     ASSERT(m_webLocalFrameImpl->frame());
@@ -497,13 +500,14 @@
     m_agents.append(agent);
 }
 
-void WebDevToolsAgentImpl::attach(const WebString& hostId)
+void WebDevToolsAgentImpl::attach(const WebString& hostId, int sessionId)
 {
     if (m_attached)
         return;
 
     // Set the attached bit first so that sync notifications were delivered.
     m_attached = true;
+    m_sessionId = sessionId;
 
     initializeDeferredAgents();
     m_resourceAgent->setHostId(hostId);
@@ -522,12 +526,12 @@
     Platform::current()->currentThread()->addTaskObserver(this);
 }
 
-void WebDevToolsAgentImpl::reattach(const WebString& hostId, const WebString& savedState)
+void WebDevToolsAgentImpl::reattach(const WebString& hostId, int sessionId, const WebString& savedState)
 {
     if (m_attached)
         return;
 
-    attach(hostId);
+    attach(hostId, sessionId);
     m_state->loadFromCookie(savedState);
     m_agents.restore();
 }
@@ -554,6 +558,7 @@
     InspectorInstrumentation::frontendDeleted();
     InspectorInstrumentation::unregisterInstrumentingAgents(m_instrumentingAgents.get());
 
+    m_sessionId = 0;
     m_attached = false;
 }
 
@@ -598,21 +603,21 @@
     m_client->disableTracing();
 }
 
-void WebDevToolsAgentImpl::dispatchOnInspectorBackend(const WebString& message)
+void WebDevToolsAgentImpl::dispatchOnInspectorBackend(int sessionId, const WebString& message)
 {
     if (!m_attached)
         return;
     if (WebDevToolsAgent::shouldInterruptForMessage(message))
         MainThreadDebugger::instance()->taskRunner()->runPendingTasks();
     else
-        dispatchMessageFromFrontend(message);
+        dispatchMessageFromFrontend(sessionId, message);
 }
 
-void WebDevToolsAgentImpl::dispatchMessageFromFrontend(const String& message)
+void WebDevToolsAgentImpl::dispatchMessageFromFrontend(int sessionId, const String& message)
 {
     InspectorTaskRunner::IgnoreInterruptsScope scope(MainThreadDebugger::instance()->taskRunner());
     if (m_inspectorBackendDispatcher)
-        m_inspectorBackendDispatcher->dispatch(message);
+        m_inspectorBackendDispatcher->dispatch(sessionId, message);
 }
 
 void WebDevToolsAgentImpl::inspectElementAt(const WebPoint& pointInRootFrame)
@@ -632,12 +637,12 @@
     m_domAgent->inspect(node);
 }
 
-void WebDevToolsAgentImpl::sendProtocolResponse(int callId, PassRefPtr<JSONObject> message)
+void WebDevToolsAgentImpl::sendProtocolResponse(int sessionId, int callId, PassRefPtr<JSONObject> message)
 {
     if (!m_attached)
         return;
     flushPendingProtocolNotifications();
-    m_client->sendProtocolMessage(callId, message->toJSONString(), m_stateCookie);
+    m_client->sendProtocolMessage(sessionId, callId, message->toJSONString(), m_stateCookie);
     m_stateCookie = String();
 }
 
@@ -645,7 +650,7 @@
 {
     if (!m_attached)
         return;
-    m_notificationQueue.append(message);
+    m_notificationQueue.append(std::make_pair(m_sessionId, message));
 }
 
 void WebDevToolsAgentImpl::flush()
@@ -678,12 +683,11 @@
 
 void WebDevToolsAgentImpl::flushPendingProtocolNotifications()
 {
-    if (!m_attached)
-        return;
-
-    m_agents.flushPendingProtocolNotifications();
-    for (size_t i = 0; i < m_notificationQueue.size(); ++i)
-        m_client->sendProtocolMessage(0, m_notificationQueue[i]->toJSONString(), WebString());
+    if (m_attached) {
+        m_agents.flushPendingProtocolNotifications();
+        for (size_t i = 0; i < m_notificationQueue.size(); ++i)
+            m_client->sendProtocolMessage(m_notificationQueue[i].first, 0, m_notificationQueue[i].second->toJSONString(), WebString());
+    }
     m_notificationQueue.clear();
 }
 
@@ -704,11 +708,11 @@
     flushPendingProtocolNotifications();
 }
 
-void WebDevToolsAgent::interruptAndDispatch(MessageDescriptor* rawDescriptor)
+void WebDevToolsAgent::interruptAndDispatch(int sessionId, MessageDescriptor* rawDescriptor)
 {
     // rawDescriptor can't be a PassOwnPtr because interruptAndDispatch is a WebKit API function.
     OwnPtr<MessageDescriptor> descriptor = adoptPtr(rawDescriptor);
-    OwnPtr<DebuggerTask> task = adoptPtr(new DebuggerTask(descriptor.release()));
+    OwnPtr<DebuggerTask> task = adoptPtr(new DebuggerTask(sessionId, descriptor.release()));
     MainThreadDebugger::interruptMainThreadAndRun(task.release());
 }
 
diff --git a/third_party/WebKit/Source/web/WebDevToolsAgentImpl.h b/third_party/WebKit/Source/web/WebDevToolsAgentImpl.h
index 9ce980bb..e1980180 100644
--- a/third_party/WebKit/Source/web/WebDevToolsAgentImpl.h
+++ b/third_party/WebKit/Source/web/WebDevToolsAgentImpl.h
@@ -85,7 +85,7 @@
     WebDevToolsAgentClient* client() { return m_client; }
     InspectorOverlay* overlay() const { return m_overlay.get(); }
     void flushPendingProtocolNotifications();
-    void dispatchMessageFromFrontend(const String& message);
+    void dispatchMessageFromFrontend(int sessionId, const String& message);
     void registerAgent(PassOwnPtrWillBeRawPtr<InspectorAgent>);
     static void webViewImplClosed(WebViewImpl*);
     static void webFrameWidgetImplClosed(WebFrameWidgetImpl*);
@@ -98,11 +98,11 @@
     void layerTreeViewChanged(WebLayerTreeView*);
 
     // WebDevToolsAgent implementation.
-    void attach(const WebString& hostId) override;
-    void reattach(const WebString& hostId, const WebString& savedState) override;
+    void attach(const WebString& hostId, int sessionId) override;
+    void reattach(const WebString& hostId, int sessionId, const WebString& savedState) override;
     void detach() override;
     void continueProgram() override;
-    void dispatchOnInspectorBackend(const WebString& message) override;
+    void dispatchOnInspectorBackend(int sessionId, const WebString& message) override;
     void inspectElementAt(const WebPoint&) override;
     void evaluateInWebInspector(long callId, const WebString& script) override;
     WebString evaluateInWebInspectorOverlay(const WebString& script) override;
@@ -121,7 +121,7 @@
     void resumeStartup() override;
 
     // InspectorFrontendChannel implementation.
-    void sendProtocolResponse(int callId, PassRefPtr<JSONObject> message) override;
+    void sendProtocolResponse(int sessionId, int callId, PassRefPtr<JSONObject> message) override;
     void sendProtocolNotification(PassRefPtr<JSONObject> message) override;
     void flush() override;
 
@@ -159,8 +159,9 @@
     InspectorAgentRegistry m_agents;
     bool m_deferredAgentsInitialized;
 
-    typedef Vector<RefPtr<JSONObject>> NotificationQueue;
+    typedef Vector<std::pair<int, RefPtr<JSONObject>>> NotificationQueue;
     NotificationQueue m_notificationQueue;
+    int m_sessionId;
     String m_stateCookie;
 
     friend class DebuggerTask;
diff --git a/third_party/WebKit/Source/web/WebEmbeddedWorkerImpl.cpp b/third_party/WebKit/Source/web/WebEmbeddedWorkerImpl.cpp
index 7873baa8..747ea14 100644
--- a/third_party/WebKit/Source/web/WebEmbeddedWorkerImpl.cpp
+++ b/third_party/WebKit/Source/web/WebEmbeddedWorkerImpl.cpp
@@ -152,18 +152,18 @@
     m_workerInspectorProxy->workerThreadTerminated();
 }
 
-void WebEmbeddedWorkerImpl::attachDevTools(const WebString& hostId)
+void WebEmbeddedWorkerImpl::attachDevTools(const WebString& hostId, int sessionId)
 {
     WebDevToolsAgent* devtoolsAgent = m_mainFrame->devToolsAgent();
     if (devtoolsAgent)
-        devtoolsAgent->attach(hostId);
+        devtoolsAgent->attach(hostId, sessionId);
 }
 
-void WebEmbeddedWorkerImpl::reattachDevTools(const WebString& hostId, const WebString& savedState)
+void WebEmbeddedWorkerImpl::reattachDevTools(const WebString& hostId, int sessionId, const WebString& savedState)
 {
     WebDevToolsAgent* devtoolsAgent = m_mainFrame->devToolsAgent();
     if (devtoolsAgent)
-        devtoolsAgent->reattach(hostId, savedState);
+        devtoolsAgent->reattach(hostId, sessionId, savedState);
     resumeStartup();
 }
 
@@ -174,13 +174,13 @@
         devtoolsAgent->detach();
 }
 
-void WebEmbeddedWorkerImpl::dispatchDevToolsMessage(const WebString& message)
+void WebEmbeddedWorkerImpl::dispatchDevToolsMessage(int sessionId, const WebString& message)
 {
     if (m_askedToTerminate)
         return;
     WebDevToolsAgent* devtoolsAgent = m_mainFrame->devToolsAgent();
     if (devtoolsAgent)
-        devtoolsAgent->dispatchOnInspectorBackend(message);
+        devtoolsAgent->dispatchOnInspectorBackend(sessionId, message);
 }
 
 void WebEmbeddedWorkerImpl::postMessageToPageInspector(const String& message)
@@ -280,9 +280,9 @@
     // invoked and |this| might have been deleted at this point.
 }
 
-void WebEmbeddedWorkerImpl::sendProtocolMessage(int callId, const WebString& message, const WebString& state)
+void WebEmbeddedWorkerImpl::sendProtocolMessage(int sessionId, int callId, const WebString& message, const WebString& state)
 {
-    m_workerContextClient->sendDevToolsMessage(callId, message, state);
+    m_workerContextClient->sendDevToolsMessage(sessionId, callId, message, state);
 }
 
 void WebEmbeddedWorkerImpl::resumeStartup()
diff --git a/third_party/WebKit/Source/web/WebEmbeddedWorkerImpl.h b/third_party/WebKit/Source/web/WebEmbeddedWorkerImpl.h
index 8c4d9d9..18c70b44d 100644
--- a/third_party/WebKit/Source/web/WebEmbeddedWorkerImpl.h
+++ b/third_party/WebKit/Source/web/WebEmbeddedWorkerImpl.h
@@ -62,10 +62,10 @@
     // WebEmbeddedWorker overrides.
     void startWorkerContext(const WebEmbeddedWorkerStartData&) override;
     void terminateWorkerContext() override;
-    void attachDevTools(const WebString& hostId) override;
-    void reattachDevTools(const WebString& hostId, const WebString& savedState) override;
+    void attachDevTools(const WebString& hostId, int sessionId) override;
+    void reattachDevTools(const WebString& hostId, int sessionId, const WebString& savedState) override;
     void detachDevTools() override;
-    void dispatchDevToolsMessage(const WebString&) override;
+    void dispatchDevToolsMessage(int sessionId, const WebString&) override;
 
     void postMessageToPageInspector(const WTF::String&);
 
@@ -80,7 +80,7 @@
     void didFinishDocumentLoad(WebLocalFrame*, bool documentIsEmpty) override;
 
     // WebDevToolsAgentClient overrides.
-    void sendProtocolMessage(int callId, const WebString&, const WebString&) override;
+    void sendProtocolMessage(int sessionId, int callId, const WebString&, const WebString&) override;
     void resumeStartup() override;
 
     void onScriptLoaderFinished();
diff --git a/third_party/WebKit/Source/web/WebSharedWorkerImpl.cpp b/third_party/WebKit/Source/web/WebSharedWorkerImpl.cpp
index e2df066..9839da9 100644
--- a/third_party/WebKit/Source/web/WebSharedWorkerImpl.cpp
+++ b/third_party/WebKit/Source/web/WebSharedWorkerImpl.cpp
@@ -197,9 +197,9 @@
     return m_networkProvider->serviceWorkerID(dataSource);
 }
 
-void WebSharedWorkerImpl::sendProtocolMessage(int callId, const WebString& message, const WebString& state)
+void WebSharedWorkerImpl::sendProtocolMessage(int sessionId, int callId, const WebString& message, const WebString& state)
 {
-    m_client->sendDevToolsMessage(callId, message, state);
+    m_client->sendDevToolsMessage(sessionId, callId, message, state);
 }
 
 void WebSharedWorkerImpl::resumeStartup()
@@ -364,18 +364,18 @@
     m_pauseWorkerContextOnStart = true;
 }
 
-void WebSharedWorkerImpl::attachDevTools(const WebString& hostId)
+void WebSharedWorkerImpl::attachDevTools(const WebString& hostId, int sessionId)
 {
     WebDevToolsAgent* devtoolsAgent = m_mainFrame->devToolsAgent();
     if (devtoolsAgent)
-        devtoolsAgent->attach(hostId);
+        devtoolsAgent->attach(hostId, sessionId);
 }
 
-void WebSharedWorkerImpl::reattachDevTools(const WebString& hostId, const WebString& savedState)
+void WebSharedWorkerImpl::reattachDevTools(const WebString& hostId, int sessionId, const WebString& savedState)
 {
     WebDevToolsAgent* devtoolsAgent = m_mainFrame->devToolsAgent();
     if (devtoolsAgent)
-        devtoolsAgent->reattach(hostId, savedState);
+        devtoolsAgent->reattach(hostId, sessionId, savedState);
     resumeStartup();
 }
 
@@ -386,13 +386,13 @@
         devtoolsAgent->detach();
 }
 
-void WebSharedWorkerImpl::dispatchDevToolsMessage(const WebString& message)
+void WebSharedWorkerImpl::dispatchDevToolsMessage(int sessionId, const WebString& message)
 {
     if (m_askedToTerminate)
         return;
     WebDevToolsAgent* devtoolsAgent = m_mainFrame->devToolsAgent();
     if (devtoolsAgent)
-        devtoolsAgent->dispatchOnInspectorBackend(message);
+        devtoolsAgent->dispatchOnInspectorBackend(sessionId, message);
 }
 
 WebSharedWorker* WebSharedWorker::create(WebSharedWorkerClient* client)
diff --git a/third_party/WebKit/Source/web/WebSharedWorkerImpl.h b/third_party/WebKit/Source/web/WebSharedWorkerImpl.h
index 7845be60..76648cb6 100644
--- a/third_party/WebKit/Source/web/WebSharedWorkerImpl.h
+++ b/third_party/WebKit/Source/web/WebSharedWorkerImpl.h
@@ -93,7 +93,7 @@
     int64_t serviceWorkerID(WebDataSource&) override;
 
     // WebDevToolsAgentClient overrides.
-    void sendProtocolMessage(int callId, const WebString&, const WebString&) override;
+    void sendProtocolMessage(int sessionId, int callId, const WebString&, const WebString&) override;
     void resumeStartup() override;
 
     // WebSharedWorker methods:
@@ -102,10 +102,10 @@
     void terminateWorkerContext() override;
 
     void pauseWorkerContextOnStart() override;
-    void attachDevTools(const WebString& hostId) override;
-    void reattachDevTools(const WebString& hostId, const WebString& savedState) override;
+    void attachDevTools(const WebString& hostId, int sessionId) override;
+    void reattachDevTools(const WebString& hostId, int sesionId, const WebString& savedState) override;
     void detachDevTools() override;
-    void dispatchDevToolsMessage(const WebString&) override;
+    void dispatchDevToolsMessage(int sessionId, const WebString&) override;
 
 private:
     ~WebSharedWorkerImpl() override;
diff --git a/third_party/WebKit/Source/wtf/Allocator.h b/third_party/WebKit/Source/wtf/Allocator.h
index bd03e4a..a6ddd0b 100644
--- a/third_party/WebKit/Source/wtf/Allocator.h
+++ b/third_party/WebKit/Source/wtf/Allocator.h
@@ -33,16 +33,16 @@
 // method. That trace method will be called automatically by the on-heap
 // collections.
 //
-#define DISALLOW_NEW()                                   \
+#define DISALLOW_NEW()                                          \
     private:                                                    \
         void* operator new(size_t) = delete;                    \
         void* operator new(size_t, NotNullTag, void*) = delete; \
         void* operator new(size_t, void*) = delete;             \
     public:
 
-#define DISALLOW_NEW_EXCEPT_PLACEMENT_NEW()                                              \
+#define DISALLOW_NEW_EXCEPT_PLACEMENT_NEW()                                         \
     public:                                                                         \
-        using IsAllowOnlyInlineAllocation = int;                                    \
+        using IsAllowOnlyPlacementNew = int;                                        \
         void* operator new(size_t, NotNullTag, void* location) { return location; } \
         void* operator new(size_t, void* location) { return location; }             \
     private:                                                                        \
diff --git a/third_party/WebKit/Source/wtf/Deque.h b/third_party/WebKit/Source/wtf/Deque.h
index 15e574d..062e610 100644
--- a/third_party/WebKit/Source/wtf/Deque.h
+++ b/third_party/WebKit/Source/wtf/Deque.h
@@ -228,7 +228,7 @@
 {
     static_assert(!IsPolymorphic<T>::value || !VectorTraits<T>::canInitializeWithMemset, "Cannot initialize with memset if there is a vtable");
 #if ENABLE(OILPAN)
-    static_assert(Allocator::isGarbageCollected || !IsAllowOnlyInlineAllocation<T>::value || !NeedsTracing<T>::value, "Cannot put DISALLOW_NEW_EXCEPT_PLACEMENT_NEW objects that have trace methods into an off-heap Deque");
+    static_assert(Allocator::isGarbageCollected || !AllowsOnlyPlacementNew<T>::value || !NeedsTracing<T>::value, "Cannot put DISALLOW_NEW_EXCEPT_PLACEMENT_NEW objects that have trace methods into an off-heap Deque");
 #endif
     static_assert(Allocator::isGarbageCollected || !IsPointerToGarbageCollectedType<T>::value, "Cannot put raw pointers to garbage-collected classes into a Deque. Use HeapDeque<Member<T>> instead.");
 }
diff --git a/third_party/WebKit/Source/wtf/HashTable.h b/third_party/WebKit/Source/wtf/HashTable.h
index 4ae3653..450f957 100644
--- a/third_party/WebKit/Source/wtf/HashTable.h
+++ b/third_party/WebKit/Source/wtf/HashTable.h
@@ -1002,8 +1002,8 @@
 
 #if ENABLE(OILPAN)
     static_assert(Allocator::isGarbageCollected
-        || ((!IsAllowOnlyInlineAllocation<KeyType>::value || !NeedsTracing<KeyType>::value)
-        && (!IsAllowOnlyInlineAllocation<ValueType>::value || !NeedsTracing<ValueType>::value))
+        || ((!AllowsOnlyPlacementNew<KeyType>::value || !NeedsTracing<KeyType>::value)
+        && (!AllowsOnlyPlacementNew<ValueType>::value || !NeedsTracing<ValueType>::value))
         , "Cannot put DISALLOW_NEW_EXCEPT_PLACEMENT_NEW objects that have trace methods into an off-heap HashTable");
 #endif
     if (Traits::emptyValueIsZero) {
diff --git a/third_party/WebKit/Source/wtf/TypeTraits.h b/third_party/WebKit/Source/wtf/TypeTraits.h
index 7bd6f57..b561606e5 100644
--- a/third_party/WebKit/Source/wtf/TypeTraits.h
+++ b/third_party/WebKit/Source/wtf/TypeTraits.h
@@ -353,14 +353,14 @@
 // This is used to check that DISALLOW_NEW_EXCEPT_PLACEMENT_NEW objects are not
 // stored in off-heap Vectors, HashTables etc.
 template <typename T>
-struct IsAllowOnlyInlineAllocation {
+struct AllowsOnlyPlacementNew {
 private:
     using YesType = char;
     struct NoType {
         char padding[8];
     };
 
-    template <typename U> static YesType checkMarker(typename U::IsAllowOnlyInlineAllocation*);
+    template <typename U> static YesType checkMarker(typename U::IsAllowOnlyPlacementNew*);
     template <typename U> static NoType checkMarker(...);
 public:
     static const bool value = sizeof(checkMarker<T>(nullptr)) == sizeof(YesType);
diff --git a/third_party/WebKit/Source/wtf/Vector.h b/third_party/WebKit/Source/wtf/Vector.h
index 355c70a..b2f295435 100644
--- a/third_party/WebKit/Source/wtf/Vector.h
+++ b/third_party/WebKit/Source/wtf/Vector.h
@@ -633,7 +633,7 @@
     {
         static_assert(!IsPolymorphic<T>::value || !VectorTraits<T>::canInitializeWithMemset, "Cannot initialize with memset if there is a vtable");
 #if ENABLE(OILPAN)
-        static_assert(Allocator::isGarbageCollected || !IsAllowOnlyInlineAllocation<T>::value || !NeedsTracing<T>::value, "Cannot put DISALLOW_NEW_EXCEPT_PLACEMENT_NEW objects that have trace methods into an off-heap Vector");
+        static_assert(Allocator::isGarbageCollected || !AllowsOnlyPlacementNew<T>::value || !NeedsTracing<T>::value, "Cannot put DISALLOW_NEW_EXCEPT_PLACEMENT_NEW objects that have trace methods into an off-heap Vector");
 #endif
         static_assert(Allocator::isGarbageCollected || !IsPointerToGarbageCollectedType<T>::value, "Cannot put raw pointers to garbage-collected classes into an off-heap Vector.  Use HeapVector<Member<T>> instead.");
 
@@ -646,7 +646,7 @@
     {
         static_assert(!IsPolymorphic<T>::value || !VectorTraits<T>::canInitializeWithMemset, "Cannot initialize with memset if there is a vtable");
 #if ENABLE(OILPAN)
-        static_assert(Allocator::isGarbageCollected || !IsAllowOnlyInlineAllocation<T>::value || !NeedsTracing<T>::value, "Cannot put DISALLOW_NEW_EXCEPT_PLACEMENT_NEW objects that have trace methods into an off-heap Vector");
+        static_assert(Allocator::isGarbageCollected || !AllowsOnlyPlacementNew<T>::value || !NeedsTracing<T>::value, "Cannot put DISALLOW_NEW_EXCEPT_PLACEMENT_NEW objects that have trace methods into an off-heap Vector");
 #endif
         static_assert(Allocator::isGarbageCollected || !IsPointerToGarbageCollectedType<T>::value, "Cannot put raw pointers to garbage-collected classes into an off-heap Vector.  Use HeapVector<Member<T>> instead.");
 
diff --git a/third_party/WebKit/public/web/WebDevToolsAgent.h b/third_party/WebKit/public/web/WebDevToolsAgent.h
index dcb76c8..05daf115 100644
--- a/third_party/WebKit/public/web/WebDevToolsAgent.h
+++ b/third_party/WebKit/public/web/WebDevToolsAgent.h
@@ -43,13 +43,13 @@
 public:
     virtual ~WebDevToolsAgent() {}
 
-    virtual void attach(const WebString& hostId) = 0;
-    virtual void reattach(const WebString& hostId, const WebString& savedState) = 0;
+    virtual void attach(const WebString& hostId, int sessionId) = 0;
+    virtual void reattach(const WebString& hostId, int sessionId, const WebString& savedState) = 0;
     virtual void detach() = 0;
 
     virtual void continueProgram() = 0;
 
-    virtual void dispatchOnInspectorBackend(const WebString& message) = 0;
+    virtual void dispatchOnInspectorBackend(int sessionId, const WebString& message) = 0;
 
     virtual void inspectElementAt(const WebPoint&) = 0;
 
@@ -64,7 +64,7 @@
         virtual WebString message() = 0;
     };
     // Asynchronously request debugger to pause immediately and run the command.
-    BLINK_EXPORT static void interruptAndDispatch(MessageDescriptor*);
+    BLINK_EXPORT static void interruptAndDispatch(int sessionId, MessageDescriptor*);
     BLINK_EXPORT static bool shouldInterruptForMessage(const WebString&);
 
 };
diff --git a/third_party/WebKit/public/web/WebDevToolsAgentClient.h b/third_party/WebKit/public/web/WebDevToolsAgentClient.h
index f674358..fa8c9b7 100644
--- a/third_party/WebKit/public/web/WebDevToolsAgentClient.h
+++ b/third_party/WebKit/public/web/WebDevToolsAgentClient.h
@@ -44,7 +44,7 @@
 public:
     // Sends response message over the protocol, update agent state on the browser side for
     // potential re-attach. |callId| for notifications is 0, |state| for notifications is empty.
-    virtual void sendProtocolMessage(int callId, const WebString& response, const WebString& state) { }
+    virtual void sendProtocolMessage(int sessionId, int callId, const WebString& response, const WebString& state) { }
 
     // Returns process id.
     virtual long processId() { return -1; }
diff --git a/third_party/WebKit/public/web/WebEmbeddedWorker.h b/third_party/WebKit/public/web/WebEmbeddedWorker.h
index 0731215..027e030d 100644
--- a/third_party/WebKit/public/web/WebEmbeddedWorker.h
+++ b/third_party/WebKit/public/web/WebEmbeddedWorker.h
@@ -59,10 +59,10 @@
     virtual void terminateWorkerContext() = 0;
 
     // Inspector related methods.
-    virtual void attachDevTools(const WebString& hostId) = 0;
-    virtual void reattachDevTools(const WebString& hostId, const WebString& savedState) = 0;
+    virtual void attachDevTools(const WebString& hostId, int sessionId) = 0;
+    virtual void reattachDevTools(const WebString& hostId, int sessionId, const WebString& savedState) = 0;
     virtual void detachDevTools() = 0;
-    virtual void dispatchDevToolsMessage(const WebString&) = 0;
+    virtual void dispatchDevToolsMessage(int sessionId, const WebString&) = 0;
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/public/web/WebSharedWorker.h b/third_party/WebKit/public/web/WebSharedWorker.h
index 407d3d1..8143de2 100644
--- a/third_party/WebKit/public/web/WebSharedWorker.h
+++ b/third_party/WebKit/public/web/WebSharedWorker.h
@@ -62,10 +62,10 @@
     virtual void terminateWorkerContext() = 0;
 
     virtual void pauseWorkerContextOnStart() = 0;
-    virtual void attachDevTools(const WebString& hostId) = 0;
-    virtual void reattachDevTools(const WebString& hostId, const WebString& savedState) = 0;
+    virtual void attachDevTools(const WebString& hostId, int sessionId) = 0;
+    virtual void reattachDevTools(const WebString& hostId, int sessionId, const WebString& savedState) = 0;
     virtual void detachDevTools() = 0;
-    virtual void dispatchDevToolsMessage(const WebString&) = 0;
+    virtual void dispatchDevToolsMessage(int sessionId, const WebString&) = 0;
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/public/web/WebSharedWorkerClient.h b/third_party/WebKit/public/web/WebSharedWorkerClient.h
index cae3117..bca580d 100644
--- a/third_party/WebKit/public/web/WebSharedWorkerClient.h
+++ b/third_party/WebKit/public/web/WebSharedWorkerClient.h
@@ -78,7 +78,7 @@
     // Ownership of the returned object is transferred to the caller.
     virtual WebServiceWorkerNetworkProvider* createServiceWorkerNetworkProvider(WebDataSource*) { return nullptr; }
 
-    virtual void sendDevToolsMessage(int callId, const WebString& message, const WebString& state) { }
+    virtual void sendDevToolsMessage(int sessionId, int callId, const WebString& message, const WebString& state) { }
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/public/web/modules/serviceworker/WebServiceWorkerContextClient.h b/third_party/WebKit/public/web/modules/serviceworker/WebServiceWorkerContextClient.h
index 473a176..18fadb6 100644
--- a/third_party/WebKit/public/web/modules/serviceworker/WebServiceWorkerContextClient.h
+++ b/third_party/WebKit/public/web/modules/serviceworker/WebServiceWorkerContextClient.h
@@ -103,7 +103,7 @@
     virtual void reportConsoleMessage(int source, int level, const WebString& message, int lineNumber, const WebString& sourceURL) { }
 
     // Inspector related messages.
-    virtual void sendDevToolsMessage(int callId, const WebString& message, const WebString& state) { }
+    virtual void sendDevToolsMessage(int sessionId, int callId, const WebString& message, const WebString& state) { }
 
     // ServiceWorker specific method.
     virtual void didHandleActivateEvent(int eventID, WebServiceWorkerEventResult result) { }
diff --git a/third_party/libjingle/README.chromium b/third_party/libjingle/README.chromium
index c03fb78..b8bbecf 100644
--- a/third_party/libjingle/README.chromium
+++ b/third_party/libjingle/README.chromium
@@ -1,7 +1,7 @@
 Name: libjingle
 URL: http://code.google.com/p/webrtc/
 Version: unknown
-Revision: 10588
+Revision: 10603
 License: BSD
 License File: source/talk/COPYING
 Security Critical: yes
diff --git a/third_party/mojo/src/mojo/public/mojo_application.gni b/third_party/mojo/src/mojo/public/mojo_application.gni
index d1327ea..cd75691 100644
--- a/third_party/mojo/src/mojo/public/mojo_application.gni
+++ b/third_party/mojo/src/mojo/public/mojo_application.gni
@@ -31,13 +31,7 @@
       assert(false, "Platform not supported.")
     }
 
-    if (is_android) {
-      # On android, use the stripped version of the library, because applications
-      # are always fetched over the network.
-      library_dir = "${root_out_dir}/lib.stripped"
-    } else {
-      library_dir = root_out_dir
-    }
+    library_dir = root_out_dir
 
     shared_library(library_target_name) {
       if (defined(invoker.cflags)) {
@@ -407,7 +401,7 @@
       script = "//build/android/gn/zip.py"
 
       inputs = [
-        "${root_out_dir}/lib.stripped/${library_basename}",
+        "${root_out_dir}/${library_basename}",
         dex_output_path,
       ]
 
diff --git a/tools/perf/measurements/image_decoding.py b/tools/perf/measurements/image_decoding.py
index 2577ce13..3e1bb35c 100644
--- a/tools/perf/measurements/image_decoding.py
+++ b/tools/perf/measurements/image_decoding.py
@@ -99,5 +99,6 @@
         tab.EvaluateJavaScript('averageLoadingTimeMs()')))
 
   def DidRunPage(self, platform):
+    self._power_metric.Close()
     if platform.tracing_controller.is_tracing_running:
       platform.tracing_controller.Stop()
diff --git a/tools/perf/measurements/media.py b/tools/perf/measurements/media.py
index 3537cda..cc9e13a 100644
--- a/tools/perf/measurements/media.py
+++ b/tools/perf/measurements/media.py
@@ -67,3 +67,6 @@
                                      trace_name=trace_name,
                                      exclude_metrics=exclude_metrics)
       self._power_metric.AddResults(tab, results)
+
+  def DidRunPage(self, platform):
+    self._power_metric.Close()
diff --git a/tools/perf/measurements/memory.py b/tools/perf/measurements/memory.py
index 4b22f6a..b9afe1cf 100644
--- a/tools/perf/measurements/memory.py
+++ b/tools/perf/measurements/memory.py
@@ -38,3 +38,6 @@
     self._memory_metric.Stop(page, tab)
     self._memory_metric.AddResults(tab, results)
     self._power_metric.AddResults(tab, results)
+
+  def DidRunPage(self, platform):
+    self._power_metric.Close()
diff --git a/tools/perf/measurements/page_cycler.py b/tools/perf/measurements/page_cycler.py
index b9e47ed..e4b2f5d1c 100644
--- a/tools/perf/measurements/page_cycler.py
+++ b/tools/perf/measurements/page_cycler.py
@@ -150,3 +150,6 @@
     # warm run, and clearing the cache before the load of the following
     # URL would eliminate the intended warmup for the previous URL.
     return self._has_loaded_page[url] >= self._cold_run_start_index
+
+  def DidRunPage(self, platform):
+    self._power_metric.Close()
diff --git a/tools/perf/measurements/power.py b/tools/perf/measurements/power.py
index 46fe04a..a4a26286 100644
--- a/tools/perf/measurements/power.py
+++ b/tools/perf/measurements/power.py
@@ -35,8 +35,7 @@
     self._power_metric.AddResults(tab, results)
 
   def DidRunPage(self, platform):
-    if platform.IsMonitoringPower():
-      platform.StopMonitoringPower()
+    self._power_metric.Close()
 
 
 class LoadPower(Power):
diff --git a/tools/perf/measurements/tab_switching.py b/tools/perf/measurements/tab_switching.py
index a4f7ac0..56b656d 100644
--- a/tools/perf/measurements/tab_switching.py
+++ b/tools/perf/measurements/tab_switching.py
@@ -104,3 +104,6 @@
                                  important=False))
 
     keychain_metric.KeychainMetric().AddResults(tab, results)
+
+  def DidRunPage(self, platform):
+    self._power_metric.Close()
diff --git a/tools/perf/measurements/webrtc.py b/tools/perf/measurements/webrtc.py
index c8ac7d6..17df5c4 100644
--- a/tools/perf/measurements/webrtc.py
+++ b/tools/perf/measurements/webrtc.py
@@ -63,3 +63,6 @@
 
     self._webrtc_stats_metric.Stop(page, tab)
     self._webrtc_stats_metric.AddResults(tab, results)
+
+  def DidRunPage(self, platform):
+    self._power_metric.Close()
diff --git a/tools/perf/metrics/power.py b/tools/perf/metrics/power.py
index df3d919b..51756bb 100644
--- a/tools/perf/metrics/power.py
+++ b/tools/perf/metrics/power.py
@@ -1,7 +1,6 @@
 # Copyright 2014 The Chromium Authors. All rights reserved.
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
-import atexit
 import logging
 import time
 
@@ -82,13 +81,6 @@
     self._starting_cpu_stats = self._browser.cpu_stats
     self._platform.StartMonitoringPower(self._browser)
 
-    # Make sure that power monitoring is cleaned up when program exits.
-    platform = self._platform
-    def CleanUp():
-      if platform.IsMonitoringPower():
-        platform.StopMonitoringPower()
-    atexit.register(CleanUp)
-
     self._running = True
 
   def Stop(self, _, tab):
@@ -98,6 +90,10 @@
 
     self._StopInternal()
 
+  def Close(self):
+    if self._platform.IsMonitoringPower():
+      self._platform.StopMonitoringPower()
+
   def AddResults(self, _, results):
     """Add the collected power data into the results object.
 
diff --git a/tools/perf/page_sets/story_set_unittest.py b/tools/perf/page_sets/story_set_unittest.py
index 9f41389..9cf753d 100644
--- a/tools/perf/page_sets/story_set_unittest.py
+++ b/tools/perf/page_sets/story_set_unittest.py
@@ -3,6 +3,7 @@
 # found in the LICENSE file.
 
 import os
+import logging
 
 import page_sets
 
@@ -10,6 +11,8 @@
 from telemetry import page
 from telemetry.testing import story_set_smoke_test
 
+from catapult_base import cloud_storage
+
 
 class StorySetUnitTest(story_set_smoke_test.StorySetSmokeTest):
 
@@ -18,10 +21,15 @@
     self.top_level_dir = os.path.dirname(self.story_sets_dir)
 
   # TODO(tbarzic): crbug.com/386416.
-  # http://crbug.com/513086
-  @decorators.Disabled('all')
+  @decorators.Disabled('chromeos')
   def testSmoke(self):
-    self.RunSmokeTest(self.story_sets_dir, self.top_level_dir)
+    try:
+      self.RunSmokeTest(self.story_sets_dir, self.top_level_dir)
+    # Swallow cloud_storage.CredentialsError due to http://crbug.com/513086.
+    # TODO(nednguyen): remove the try except block once that bug is fixed.
+    except cloud_storage.CredentialsError:
+      logging.warning(
+          'CredentialsError was ignored for StorySetUnitTest.testSmoke')
 
   # TODO(nednguyen): Remove this test once crbug.com/508538 is fixed.
   # http://crbug.com/513086
@@ -30,12 +38,18 @@
     for story_set_class in self.GetAllStorySetClasses(self.story_sets_dir,
                                                       self.top_level_dir):
       if story_set_class is page_sets.ToughSchedulingCasesPageSet:
-       continue
-      story_set = story_set_class()
-      for story in story_set:
-        if isinstance(story, page.Page):
-          self.assertFalse(
-            story.synthetic_delays,
-            'Page %s in page set %s has non empty synthetic delay. '
-            'Synthetic delay is no longer supported. See crbug.com/508538.' %
-            (story.display_name, story_set.Name()))
+        continue
+      try:
+        story_set = story_set_class()
+        for story in story_set:
+          if isinstance(story, page.Page):
+            self.assertFalse(
+              story.synthetic_delays,
+              'Page %s in page set %s has non empty synthetic delay. '
+              'Synthetic delay is no longer supported. See crbug.com/508538.' %
+              (story.display_name, story_set.Name()))
+      # Swallow cloud_storage.CredentialsError due to http://crbug.com/513086.
+      # TODO(nednguyen): remove the try except block once that bug is fixed.
+      except cloud_storage.CredentialsError:
+        logging.warning('CredentialsError was ignored for '
+                        'StorySetUnitTest.testNoPageDefinedSyntheticDelay')
diff --git a/tools/valgrind/drmemory/suppressions.txt b/tools/valgrind/drmemory/suppressions.txt
index 1ab080e..abf35496 100644
--- a/tools/valgrind/drmemory/suppressions.txt
+++ b/tools/valgrind/drmemory/suppressions.txt
@@ -437,8 +437,6 @@
 *!SkScalerContext::getImage
 *!SkGlyphCache::findImage
 *!D1G*RectClip
-*!SkDraw::drawPosText
-*!SkBitmapDevice::drawPosText
 
 HANDLE LEAK
 name=http://crbug.com/346993
@@ -741,3 +739,11 @@
 *!blink::SecurityOrigin::addSuborigin
 *!blink::SecurityOriginTest_Suborigins_Test::TestBody
 *!testing::internal::HandleExceptionsInMethodIfSupported<>
+
+UNADDRESSABLE ACCESS
+name=bug_554520
+*!gl::Program::release
+*!gl::State::reset
+*!gl::State::~State
+*!`anonymous namespace'::ValidationESTest_DrawElementsWithMaxIndexGivesError_Test::TestBody
+*!testing::internal::HandleExceptionsInMethodIfSupported<>
diff --git a/ui/webui/OWNERS b/ui/webui/OWNERS
index 0f26b6b2..08d34dd 100644
--- a/ui/webui/OWNERS
+++ b/ui/webui/OWNERS
@@ -2,7 +2,6 @@
 bauerb@chromium.org
 dbeam@chromium.org
 estade@chromium.org
-jhawkins@chromium.org
 michaelpg@chromium.org
 nkostylev@chromium.org
 pam@chromium.org