diff --git a/.gn b/.gn
index 853c59a..30f5ee55 100644
--- a/.gn
+++ b/.gn
@@ -45,6 +45,8 @@
   "//google_update/*",
 
   #"//gpu/*",  # Lots of errors.
+  "//gpu:*",
+
   #"//ios/*",
   "//ipc/*",
 
@@ -101,6 +103,7 @@
   "//chrome/browser/BUILD.gn",
   "//chrome/browser/chromeos/BUILD.gn",
   "//chrome/browser/extensions/BUILD.gn",
+  "//chrome/browser/media/router/BUILD.gn",
   "//chrome/browser/ui/BUILD.gn",
   "//chrome/chrome_tests.gni",
   "//chrome/common/BUILD.gn",
diff --git a/BUILD.gn b/BUILD.gn
index 97caab49..65f40e0 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -169,10 +169,7 @@
   }
 
   if (enable_media_router) {
-    deps += [
-      "//chrome/browser/media/router/",
-      "//chrome/browser/media/router:unit_tests",
-    ]
+    deps += [ "//chrome/browser/media/router" ]
   }
 
   if (enable_remoting) {
@@ -393,7 +390,6 @@
       "//ppapi:pepper_hash_for_uma",
       "//ppapi:ppapi_perftests",
       "//sync:run_sync_testserver",
-      "//sync:sync_endtoend_tests",
       "//third_party/codesighs:maptsvdifftool",
       "//third_party/leveldatabase:env_chromium_unittests",
       "//third_party/libaddressinput:libaddressinput_unittests",
@@ -751,8 +747,8 @@
 
     if (is_win) {
       deps += [
+        "//content/shell:crash_service",
         "//content/shell:layout_test_helper",
-        #'../content/content_shell_and_tests.gyp:content_shell_crash_service', TODO(GYP)
       ]
     }
 
diff --git a/DEPS b/DEPS
index 92a0e07f..a9ff9f9 100644
--- a/DEPS
+++ b/DEPS
@@ -34,7 +34,7 @@
   'llvm_url': 'http://src.chromium.org/llvm-project',
   'llvm_git': 'https://llvm.googlesource.com',
   'webkit_trunk': 'http://src.chromium.org/blink/trunk',
-  'webkit_revision': 'ea59f1aee78b31b87f82df18927014a053db612d', # from svn revision 195394
+  'webkit_revision': 'ae8e1952e123dd09d9fb2da286461a617f2c501a', # from svn revision 195438
   'chromium_git': 'https://chromium.googlesource.com',
   'chromiumos_git': 'https://chromium.googlesource.com/chromiumos',
   'pdfium_git': 'https://pdfium.googlesource.com',
@@ -42,7 +42,7 @@
   'boringssl_git': 'https://boringssl.googlesource.com',
   'libvpx_revision': 'd1c022c097f22987d521643c4802b623e572393a',
   'sfntly_revision': '1bdaae8fc788a5ac8936d68bf24f37d977a13dac',
-  'skia_revision': '27e517ae533775889c98c65fa2f07b98357ecbc2',
+  'skia_revision': '465706820d0d373f76ab4831c286115ee0d86b7a',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and V8 without interference from each other.
@@ -58,7 +58,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': '21ce9b02de90b81d3c3fab95f02ad45fbffd7350',
+  'angle_revision': '8befcff50d9d3c3f8b1295eb420e9cd4beeae2f4',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling build tools
   # and whatever else without interference from each other.
@@ -70,11 +70,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling openmax_dl
   # and whatever else without interference from each other.
-  'openmax_dl_revision': '0b238cb62c32b6f45680cf577eddb1b051ae0219',
+  'openmax_dl_revision': '22bb1085a6a0f6f3589a8c3d60ed0a9b82248275',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
-  'boringssl_revision': '771a138f2612c581a547cb3f045b3f6753fe5571',
+  'boringssl_revision': '966003273dc1a8b92f376aefa81232f14eecde8a',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling nss
   # and whatever else without interference from each other.
@@ -94,7 +94,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling NaCl
   # and whatever else without interference from each other.
-  'nacl_revision': 'b5365b48a73962904e04229ca3bf97948d03d034',
+  'nacl_revision': '862ca265aa1fdcabe8b3ab518251381bfbf48468',
 }
 
 # Only these hosts are allowed for dependencies in this DEPS file.
@@ -138,7 +138,7 @@
    Var('chromium_git') + '/chromium/blink.git' + '@' +  Var('webkit_revision'),
 
   'src/third_party/icu':
-   Var('chromium_git') + '/chromium/deps/icu.git' + '@' + 'ce41627e388fb46ab49671bd16a5db81dcd75a71',
+   Var('chromium_git') + '/chromium/deps/icu.git' + '@' + '5788e2736b3bc642994b6351a6096124895afa01',
 
   'src/third_party/libexif/sources':
    Var('chromium_git') + '/chromium/deps/libexif/sources.git' + '@' + 'ed98343daabd7b4497f97fda972e132e6877c48a',
@@ -210,7 +210,7 @@
     Var('chromium_git') + '/external/usrsctplib.git' + '@' + '36444a999739e9e408f8f587cb4c3ffeef2e50ac', # from svn revision 9215
 
   'src/third_party/libsrtp':
-   Var('chromium_git') + '/chromium/deps/libsrtp.git' + '@' + '6446144c7f083552f21cc4e6768e891bcb767574',
+   Var('chromium_git') + '/chromium/deps/libsrtp.git' + '@' + '9c53f858cddd4d890e405e91ff3af0b48dfd90e6', # from svn revision 295151
 
   'src/third_party/yasm/source/patched-yasm':
    Var('chromium_git') + '/chromium/deps/yasm/patched-yasm.git' + '@' + '4671120cd8558ce62ee8672ebf3eb6f5216f909b',
@@ -426,7 +426,7 @@
      Var('chromium_git') + '/external/android_protobuf.git' + '@' + '94f522f907e3f34f70d9e7816b947e62fddbb267',
 
     'src/third_party/android_tools':
-     Var('chromium_git') + '/android_tools.git' + '@' + '0c03d3bfef2606a30c3ccec9f6856e6acb75c2fb',
+     Var('chromium_git') + '/android_tools.git' + '@' + '3445d55bd6a9bedd04ecd9deabc9071fa5b93ca1',
 
     'src/third_party/apache-mime4j':
      Var('chromium_git') + '/chromium/deps/apache-mime4j.git' + '@' + '28cb1108bff4b6cf0a2e86ff58b3d025934ebe3a',
diff --git a/android_webview/browser/aw_browser_context.cc b/android_webview/browser/aw_browser_context.cc
index e6587fc..fbdb5cd 100644
--- a/android_webview/browser/aw_browser_context.cc
+++ b/android_webview/browser/aw_browser_context.cc
@@ -171,7 +171,8 @@
       new data_reduction_proxy::DataReductionProxyService(
           scoped_ptr<
               data_reduction_proxy::DataReductionProxyCompressionStats>(),
-          data_reduction_proxy_settings_.get(), GetAwURLRequestContext(),
+          data_reduction_proxy_settings_.get(), nullptr,
+          GetAwURLRequestContext(),
           BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO)));
   data_reduction_proxy_io_data_->SetDataReductionProxyService(
       data_reduction_proxy_service_->GetWeakPtr());
diff --git a/android_webview/browser/aw_dev_tools_discovery_provider.cc b/android_webview/browser/aw_dev_tools_discovery_provider.cc
index 4117358..fe1e61e 100644
--- a/android_webview/browser/aw_dev_tools_discovery_provider.cc
+++ b/android_webview/browser/aw_dev_tools_discovery_provider.cc
@@ -35,7 +35,7 @@
     description.SetInteger("height", screen_rect.height());
   }
   std::string json;
-  base::JSONWriter::Write(&description, &json);
+  base::JSONWriter::Write(description, &json);
   return json;
 }
 
diff --git a/android_webview/java/src/org/chromium/android_webview/AwContents.java b/android_webview/java/src/org/chromium/android_webview/AwContents.java
index 0a0e853..972360b 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwContents.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwContents.java
@@ -77,6 +77,7 @@
 import java.util.HashMap;
 import java.util.Locale;
 import java.util.Map;
+import java.util.WeakHashMap;
 import java.util.concurrent.Callable;
 
 /**
@@ -207,7 +208,7 @@
     private final Context mContext;
     private final int mAppTargetSdkVersion;
     private ContentViewCore mContentViewCore;
-    private WindowAndroid mWindowAndroid;
+    private WindowAndroidWrapper mWindowAndroid;
     private WebContents mWebContents;
     private NavigationController mNavigationController;
     private final AwContentsClient mContentsClient;
@@ -287,16 +288,13 @@
 
     private static final class DestroyRunnable implements Runnable {
         private final long mNativeAwContents;
-        private final WindowAndroid mWindowAndroid;
 
-        private DestroyRunnable(long nativeAwContents, WindowAndroid windowAndroid) {
+        private DestroyRunnable(long nativeAwContents) {
             mNativeAwContents = nativeAwContents;
-            mWindowAndroid = windowAndroid;
         }
         @Override
         public void run() {
             nativeDestroy(mNativeAwContents);
-            mWindowAndroid.destroy();
         }
     }
 
@@ -848,6 +846,60 @@
         mContainerView.requestLayout();
     }
 
+    // This class destroys the WindowAndroid when after it is gc-ed.
+    private static class WindowAndroidWrapper {
+        private final WindowAndroid mWindowAndroid;
+        private final CleanupReference mCleanupReference;
+
+        private static final class DestroyRunnable implements Runnable {
+            private final WindowAndroid mWindowAndroid;
+            private DestroyRunnable(WindowAndroid windowAndroid) {
+                mWindowAndroid = windowAndroid;
+            }
+            @Override
+            public void run() {
+                mWindowAndroid.destroy();
+            }
+        }
+
+        public WindowAndroidWrapper(WindowAndroid windowAndroid) {
+            mWindowAndroid = windowAndroid;
+            mCleanupReference =
+                    new CleanupReference(this, new DestroyRunnable(windowAndroid));
+        }
+
+        public WindowAndroid getWindowAndroid() {
+            return mWindowAndroid;
+        }
+    }
+    private static WindowAndroidWrapper sCachedWindowAndroid;
+    private static WeakHashMap<Activity, WindowAndroidWrapper> sActivityWindowMap;
+
+    // getWindowAndroid is only called on UI thread, so there are no threading issues with lazy
+    // initialization.
+    @SuppressFBWarnings("LI_LAZY_INIT_STATIC")
+    private static WindowAndroidWrapper getWindowAndroid(Context context) {
+        // TODO(boliu): WebView does not currently initialize ApplicationStatus, crbug.com/470582.
+        Activity activity = ContentViewCore.activityFromContext(context);
+        if (activity == null) {
+            if (sCachedWindowAndroid == null) {
+                sCachedWindowAndroid = new WindowAndroidWrapper(
+                        new WindowAndroid(context.getApplicationContext()));
+            }
+            return sCachedWindowAndroid;
+        }
+
+        if (sActivityWindowMap == null) sActivityWindowMap = new WeakHashMap<>();
+        WindowAndroidWrapper activityWindowAndroid = sActivityWindowMap.get(activity);
+        if (activityWindowAndroid == null) {
+            final boolean listenToActivityState = false;
+            activityWindowAndroid = new WindowAndroidWrapper(
+                    new ActivityWindowAndroid(activity, listenToActivityState));
+            sActivityWindowMap.put(activity, activityWindowAndroid);
+        }
+        return activityWindowAndroid;
+    }
+
     /* Common initialization routine for adopting a native AwContents instance into this
      * java instance.
      *
@@ -871,15 +923,10 @@
 
         WebContents webContents = nativeGetWebContents(mNativeAwContents);
 
-        // WebView does not currently initialize ApplicationStatus, crbug.com/470582.
-        final boolean listenToActivityState = false;
-        Activity activity = ContentViewCore.activityFromContext(mContext);
-        mWindowAndroid = activity != null
-                ? new ActivityWindowAndroid(activity, listenToActivityState)
-                : new WindowAndroid(mContext.getApplicationContext());
-        mContentViewCore = createAndInitializeContentViewCore(
-                mContainerView, mContext, mInternalAccessAdapter, webContents,
-                new AwGestureStateListener(), mContentViewClient, mZoomControls, mWindowAndroid);
+        mWindowAndroid = getWindowAndroid(mContext);
+        mContentViewCore = createAndInitializeContentViewCore(mContainerView, mContext,
+                mInternalAccessAdapter, webContents, new AwGestureStateListener(),
+                mContentViewClient, mZoomControls, mWindowAndroid.getWindowAndroid());
         nativeSetJavaPeers(mNativeAwContents, this, mWebContentsDelegate, mContentsClientBridge,
                 mIoThreadClient, mInterceptNavigationDelegate);
         mWebContents = mContentViewCore.getWebContents();
@@ -892,7 +939,7 @@
         // The native side object has been bound to this java instance, so now is the time to
         // bind all the native->java relationships.
         mCleanupReference =
-                new CleanupReference(this, new DestroyRunnable(mNativeAwContents, mWindowAndroid));
+                new CleanupReference(this, new DestroyRunnable(mNativeAwContents));
     }
 
     private void installWebContentsObserver() {
@@ -2452,7 +2499,7 @@
 
     @CalledByNative
     private void postInvalidateOnAnimation() {
-        if (!mWindowAndroid.isInsideVSync()) {
+        if (!mWindowAndroid.getWindowAndroid().isInsideVSync()) {
             mContainerView.postInvalidateOnAnimation();
         } else {
             mContainerView.invalidate();
diff --git a/android_webview/renderer/aw_render_view_ext.cc b/android_webview/renderer/aw_render_view_ext.cc
index c2877c5..7aa901d5 100644
--- a/android_webview/renderer/aw_render_view_ext.cc
+++ b/android_webview/renderer/aw_render_view_ext.cc
@@ -247,12 +247,12 @@
   if (node.isNull() || !node.isElementNode() || !render_view())
     return;
 
-  // Note: element is not const due to innerText() is not const.
+  // Note: element is not const due to textContent() is not const.
   blink::WebElement element = node.toConst<blink::WebElement>();
   AwHitTestData data;
 
   data.href = GetHref(element);
-  data.anchor_text = element.innerText();
+  data.anchor_text = element.textContent();
 
   GURL absolute_link_url;
   if (node.isLink())
@@ -280,7 +280,7 @@
 
   GURL absolute_image_url = result.absoluteImageURL();
   if (!result.urlElement().isNull()) {
-    data.anchor_text = result.urlElement().innerText();
+    data.anchor_text = result.urlElement().textContent();
     data.href = GetHref(result.urlElement());
     // If we hit an image that failed to load, Blink won't give us its URL.
     // Fall back to walking the DOM in this case.
diff --git a/ash/accelerators/key_hold_detector.cc b/ash/accelerators/key_hold_detector.cc
index 8326d9a..46c17ea 100644
--- a/ash/accelerators/key_hold_detector.cc
+++ b/ash/accelerators/key_hold_detector.cc
@@ -4,11 +4,6 @@
 
 #include "ash/accelerators/key_hold_detector.h"
 
-#include <X11/Xlib.h>
-
-#undef RootWindow
-#undef Status
-
 #include "ash/shell.h"
 #include "base/message_loop/message_loop.h"
 #include "ui/aura/window_tracker.h"
diff --git a/ash/ash.gyp b/ash/ash.gyp
index e8e819b..082a6f8 100644
--- a/ash/ash.gyp
+++ b/ash/ash.gyp
@@ -43,6 +43,8 @@
       'autoclick/autoclick_controller.h',
       'cancel_mode.cc',
       'cancel_mode.h',
+      'cast_config_delegate.cc',
+      'cast_config_delegate.h',
       'content/display/display_color_manager_chromeos.cc',
       'content/display/display_color_manager_chromeos.h',
       'content/display/screen_orientation_controller_chromeos.cc',
diff --git a/ash/cast_config_delegate.cc b/ash/cast_config_delegate.cc
new file mode 100644
index 0000000..5cbbc07
--- /dev/null
+++ b/ash/cast_config_delegate.cc
@@ -0,0 +1,27 @@
+// 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 "ash/cast_config_delegate.h"
+
+namespace ash {
+
+CastConfigDelegate::Receiver::Receiver() {
+}
+
+CastConfigDelegate::Receiver::~Receiver() {
+}
+
+CastConfigDelegate::Activity::Activity() {
+}
+
+CastConfigDelegate::Activity::~Activity() {
+}
+
+CastConfigDelegate::ReceiverAndActivity::ReceiverAndActivity() {
+}
+
+CastConfigDelegate::ReceiverAndActivity::~ReceiverAndActivity() {
+}
+
+}  // namespace ash
diff --git a/ash/cast_config_delegate.h b/ash/cast_config_delegate.h
new file mode 100644
index 0000000..2f5e334
--- /dev/null
+++ b/ash/cast_config_delegate.h
@@ -0,0 +1,103 @@
+// 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 ASH_CAST_CONFIG_DELEGATE_H_
+#define ASH_CAST_CONFIG_DELEGATE_H_
+
+#include <map>
+#include <string>
+
+#include "ash/ash_export.h"
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string16.h"
+#include "url/gurl.h"
+
+namespace ash {
+
+// This delegate allows the UI code in ash, e.g. |TrayCastDetailedView|,
+// to access the cast extension.
+class CastConfigDelegate {
+ public:
+  struct ASH_EXPORT Receiver {
+    Receiver();
+    ~Receiver();
+
+    std::string id;
+    base::string16 name;
+  };
+
+  struct ASH_EXPORT Activity {
+    // The tab identifier that we are casting. These are the special tab values
+    // taken from the chromecast extension itself. If an actual tab is being
+    // casted, then the TabId will be >= 0.
+    enum TabId {
+      EXTENSION = -1,
+      DESKTOP = -2,
+      DISCOVERED_ACTIVITY = -3,
+      EXTERNAL_EXTENSION_CLIENT = -4
+    };
+
+    Activity();
+    ~Activity();
+
+    std::string id;
+    base::string16 title;
+    std::string activity_type;
+    bool allow_stop = false;
+
+    // The id for the tab we are casting. Could be one of the TabId values,
+    // or a value >= 0 that represents that tab index of the tab we are
+    // casting. We default to casting the desktop, as a tab may not
+    // necessarily exist.
+    int tab_id = TabId::DESKTOP;
+  };
+
+  struct ASH_EXPORT ReceiverAndActivity {
+    ReceiverAndActivity();
+    ~ReceiverAndActivity();
+
+    Receiver receiver;
+    Activity activity;
+  };
+
+  // The key is the receiver id.
+  using ReceiversAndActivites = std::map<std::string, ReceiverAndActivity>;
+  using ReceiversAndActivitesCallback =
+      base::Callback<void(const ReceiversAndActivites&)>;
+
+  virtual ~CastConfigDelegate() {}
+
+  // Returns true if cast extension is installed.
+  virtual bool HasCastExtension() const = 0;
+
+  // Fetches the current set of receivers and their possible activities. This
+  // method will lookup the current chromecast extension and query its current
+  // state. The |callback| will be invoked when the receiver/activity data is
+  // available.
+  virtual void GetReceiversAndActivities(
+      const ReceiversAndActivitesCallback& callback) = 0;
+
+  // Cast to a receiver specified by |receiver_id|.
+  virtual void CastToReceiver(const std::string& receiver_id) = 0;
+
+  // Stop ongoing cast. The |activity_id| is the unique identifier associated
+  // with the ongoing cast. Each receiver has only one possible activity
+  // associated with it. The |activity_id| is available by invoking
+  // GetReceiversAndActivities(); if the receiver is currently casting, then the
+  // associated activity data will have an id. This id can be used to stop the
+  // cast in this method.
+  virtual void StopCasting(const std::string& activity_id) = 0;
+
+  // Opens Options page for cast.
+  virtual void LaunchCastOptions() = 0;
+
+ private:
+  DISALLOW_ASSIGN(CastConfigDelegate);
+};
+
+}  // namespace ash
+
+#endif  // ASH_CAST_CONFIG_DELEGATE_H_
diff --git a/ash/content/display/display_color_manager_chromeos.cc b/ash/content/display/display_color_manager_chromeos.cc
index 9692e624..1f177fd 100644
--- a/ash/content/display/display_color_manager_chromeos.cc
+++ b/ash/content/display/display_color_manager_chromeos.cc
@@ -11,6 +11,7 @@
 #include "base/format_macros.h"
 #include "base/logging.h"
 #include "base/path_service.h"
+#include "base/stl_util.h"
 #include "base/strings/stringprintf.h"
 #include "chromeos/chromeos_paths.h"
 #include "chromeos/chromeos_switches.h"
@@ -91,11 +92,7 @@
 
 DisplayColorManager::~DisplayColorManager() {
   configurator_->RemoveObserver(this);
-
-  for (auto it : calibration_map_) {
-    delete it.second;
-    calibration_map_.erase(it.first);
-  }
+  STLDeleteValues(&calibration_map_);
 }
 
 void DisplayColorManager::OnDisplayModeChanged(
diff --git a/ash/metrics/task_switch_metrics_recorder.cc b/ash/metrics/task_switch_metrics_recorder.cc
index 667c7e4..b8b57fe 100644
--- a/ash/metrics/task_switch_metrics_recorder.cc
+++ b/ash/metrics/task_switch_metrics_recorder.cc
@@ -13,12 +13,31 @@
 const char kShelfHistogramName[] =
     "Ash.Shelf.TimeBetweenNavigateToTaskSwitches";
 
+const char kTabStripHistogramName[] =
+    "Ash.Tab.TimeBetweenSwitchToExistingTabUserActions";
+
+const char kAcceleratorWindowCycleHistogramName[] =
+    "Ash.WindowCycleController.TimeBetweenTaskSwitches";
+
+const char kAppListHistogramName[] = "Ash.AppList.TimeBetweenTaskSwitches";
+
+const char kOverviewModeHistogramName[] =
+    "Ash.WindowSelector.TimeBetweenActiveWindowChanges";
+
 // Returns the histogram name for the given |task_switch_source|.
 const char* GetHistogramName(
     TaskSwitchMetricsRecorder::TaskSwitchSource task_switch_source) {
   switch (task_switch_source) {
+    case TaskSwitchMetricsRecorder::kAppList:
+      return kAppListHistogramName;
+    case TaskSwitchMetricsRecorder::kOverviewMode:
+      return kOverviewModeHistogramName;
     case TaskSwitchMetricsRecorder::kShelf:
       return kShelfHistogramName;
+    case TaskSwitchMetricsRecorder::kTabStrip:
+      return kTabStripHistogramName;
+    case TaskSwitchMetricsRecorder::kWindowCycleController:
+      return kAcceleratorWindowCycleHistogramName;
   }
   NOTREACHED();
   return nullptr;
diff --git a/ash/metrics/task_switch_metrics_recorder.h b/ash/metrics/task_switch_metrics_recorder.h
index 87a77600..b2103be 100644
--- a/ash/metrics/task_switch_metrics_recorder.h
+++ b/ash/metrics/task_switch_metrics_recorder.h
@@ -22,8 +22,17 @@
   // Enumeration of the different user interfaces that could be the source of
   // a task switch. Note this is not necessarily comprehensive of all sources.
   enum TaskSwitchSource {
+    // Task switches from selecting items in the app list.
+    kAppList,
+    // Task switches caused by selecting a window from overview mode which is
+    // different from the previously-active window.
+    kOverviewMode,
     // All task switches caused by shelf buttons, not including sub-menus.
-    kShelf
+    kShelf,
+    // All task switches caused by the tab strip.
+    kTabStrip,
+    // Task switches caused by the WindowCycleController (ie Alt+Tab).
+    kWindowCycleController
   };
 
   TaskSwitchMetricsRecorder();
diff --git a/ash/metrics/task_switch_metrics_recorder_unittest.cc b/ash/metrics/task_switch_metrics_recorder_unittest.cc
index 155be5b..90a0db1 100644
--- a/ash/metrics/task_switch_metrics_recorder_unittest.cc
+++ b/ash/metrics/task_switch_metrics_recorder_unittest.cc
@@ -62,6 +62,21 @@
 
 }  // namespace
 
+// Verifies that the TaskSwitchMetricsRecorder::kWindowCycleController source
+// adds data to the Ash.WindowCycleController.TimeBetweenTaskSwitches histogram.
+TEST_F(TaskSwitchMetricsRecorderTest,
+       VerifyTaskSwitchesForWindowCycleControllerAreRecorded) {
+  const std::string kHistogramName =
+      "Ash.WindowCycleController.TimeBetweenTaskSwitches";
+
+  OnTaskSwitch(TaskSwitchMetricsRecorder::kWindowCycleController);
+  OnTaskSwitch(TaskSwitchMetricsRecorder::kWindowCycleController);
+  histogram_tester_->ExpectTotalCount(kHistogramName, 1);
+
+  OnTaskSwitch(TaskSwitchMetricsRecorder::kWindowCycleController);
+  histogram_tester_->ExpectTotalCount(kHistogramName, 2);
+}
+
 // Verifies that the TaskSwitchMetricsRecorder::kShelf source adds data to the
 // Ash.Shelf.TimeBetweenNavigateToTaskSwitches histogram.
 TEST_F(TaskSwitchMetricsRecorderTest,
@@ -77,4 +92,48 @@
   histogram_tester_->ExpectTotalCount(kHistogramName, 2);
 }
 
+// Verifies that the TaskSwitchMetricsRecorder::kTabStrip source adds data to
+// the Ash.Tab.TimeBetweenSwitchToExistingTabUserActions histogram.
+TEST_F(TaskSwitchMetricsRecorderTest,
+       VerifyTaskSwitchesFromTheTabStripAreRecorded) {
+  const std::string kHistogramName =
+      "Ash.Tab.TimeBetweenSwitchToExistingTabUserActions";
+
+  OnTaskSwitch(TaskSwitchMetricsRecorder::kTabStrip);
+  OnTaskSwitch(TaskSwitchMetricsRecorder::kTabStrip);
+  histogram_tester_->ExpectTotalCount(kHistogramName, 1);
+
+  OnTaskSwitch(TaskSwitchMetricsRecorder::kTabStrip);
+  histogram_tester_->ExpectTotalCount(kHistogramName, 2);
+}
+
+// Verifies that the TaskSwitchMetricsRecorder::kOverviewMode source adds data
+// to the Ash.WindowSelector.TimeBetweenActiveWindowChanges histogram.
+TEST_F(TaskSwitchMetricsRecorderTest,
+       VerifyTaskSwitchesFromOverviewModeAreRecorded) {
+  const std::string kHistogramName =
+      "Ash.WindowSelector.TimeBetweenActiveWindowChanges";
+
+  OnTaskSwitch(TaskSwitchMetricsRecorder::kOverviewMode);
+  OnTaskSwitch(TaskSwitchMetricsRecorder::kOverviewMode);
+  histogram_tester_->ExpectTotalCount(kHistogramName, 1);
+
+  OnTaskSwitch(TaskSwitchMetricsRecorder::kOverviewMode);
+  histogram_tester_->ExpectTotalCount(kHistogramName, 2);
+}
+
+// Verifies that the TaskSwitchMetricsRecorder::kAppList source adds data to the
+// Ash.AppList.TimeBetweenTaskSwitches histogram.
+TEST_F(TaskSwitchMetricsRecorderTest,
+       VerifyTaskSwitchesFromApplistAreRecorded) {
+  const std::string kHistogramName = "Ash.AppList.TimeBetweenTaskSwitches";
+
+  OnTaskSwitch(TaskSwitchMetricsRecorder::kAppList);
+  OnTaskSwitch(TaskSwitchMetricsRecorder::kAppList);
+  histogram_tester_->ExpectTotalCount(kHistogramName, 1);
+
+  OnTaskSwitch(TaskSwitchMetricsRecorder::kAppList);
+  histogram_tester_->ExpectTotalCount(kHistogramName, 2);
+}
+
 }  // namespace ash
diff --git a/ash/metrics/user_metrics_recorder.cc b/ash/metrics/user_metrics_recorder.cc
index e992940..cfc4d8e 100644
--- a/ash/metrics/user_metrics_recorder.cc
+++ b/ash/metrics/user_metrics_recorder.cc
@@ -584,6 +584,8 @@
     case ash::UMA_WINDOW_OVERVIEW_ACTIVE_WINDOW_CHANGED:
       base::RecordAction(
           base::UserMetricsAction("WindowSelector_ActiveWindowChanged"));
+      task_switch_metrics_recorder_.OnTaskSwitch(
+          TaskSwitchMetricsRecorder::kOverviewMode);
       break;
     case ash::UMA_WINDOW_OVERVIEW_ENTER_KEY:
       base::RecordAction(
diff --git a/ash/metrics/user_metrics_recorder.h b/ash/metrics/user_metrics_recorder.h
index 956bb40..7bb6f9d 100644
--- a/ash/metrics/user_metrics_recorder.h
+++ b/ash/metrics/user_metrics_recorder.h
@@ -149,6 +149,10 @@
   // Records an Ash owned user action.
   void RecordUserMetricsAction(ash::UserMetricsAction action);
 
+  TaskSwitchMetricsRecorder& task_switch_metrics_recorder() {
+    return task_switch_metrics_recorder_;
+  }
+
  private:
   friend class test::UserMetricsRecorderTestAPI;
 
diff --git a/ash/rotator/screen_rotation_animator.cc b/ash/rotator/screen_rotation_animator.cc
index 9b746b68..742ade9 100644
--- a/ash/rotator/screen_rotation_animator.cc
+++ b/ash/rotator/screen_rotation_animator.cc
@@ -12,6 +12,7 @@
 #include "ash/display/display_info.h"
 #include "ash/display/display_manager.h"
 #include "ash/rotator/screen_rotation_animation.h"
+#include "ash/session/session_state_delegate.h"
 #include "ash/shell.h"
 #include "base/command_line.h"
 #include "base/time/time.h"
@@ -280,10 +281,19 @@
 }
 
 bool ScreenRotationAnimator::CanAnimate() const {
+  // Animations are currently broken on the login screen.
+  // (chrome-os-partners:40118). Disabling the animations on this screen for
+  // M-43
   return Shell::GetInstance()
-      ->display_manager()
-      ->GetDisplayForId(display_id_)
-      .is_valid();
+             ->display_manager()
+             ->GetDisplayForId(display_id_)
+             .is_valid() &&
+         Shell::GetInstance()
+             ->session_state_delegate()
+             ->IsActiveUserSessionStarted() &&
+         !Shell::GetInstance()->session_state_delegate()->IsScreenLocked() &&
+         Shell::GetInstance()->session_state_delegate()->GetSessionState() ==
+             SessionStateDelegate::SESSION_STATE_ACTIVE;
 }
 
 void ScreenRotationAnimator::Rotate(gfx::Display::Rotation new_rotation,
diff --git a/ash/system/tray/system_tray_delegate.cc b/ash/system/tray/system_tray_delegate.cc
index eaab406..ed999b6a 100644
--- a/ash/system/tray/system_tray_delegate.cc
+++ b/ash/system/tray/system_tray_delegate.cc
@@ -223,6 +223,10 @@
 void SystemTrayDelegate::ChangeProxySettings() {
 }
 
+CastConfigDelegate* SystemTrayDelegate::GetCastConfigDelegate() const {
+  return nullptr;
+}
+
 NetworkingConfigDelegate* SystemTrayDelegate::GetNetworkingConfigDelegate()
     const {
   return nullptr;
diff --git a/ash/system/tray/system_tray_delegate.h b/ash/system/tray/system_tray_delegate.h
index fb2601a..857ee093 100644
--- a/ash/system/tray/system_tray_delegate.h
+++ b/ash/system/tray/system_tray_delegate.h
@@ -98,6 +98,7 @@
 
 using IMEInfoList = std::vector<IMEInfo>;
 
+class CastConfigDelegate;
 class NetworkingConfigDelegate;
 class VPNDelegate;
 
@@ -284,6 +285,9 @@
   // Shows UI for changing proxy settings.
   virtual void ChangeProxySettings();
 
+  // Returns CastConfigDelegate. May return nullptr.
+  virtual CastConfigDelegate* GetCastConfigDelegate() const;
+
   // Returns NetworkingConfigDelegate. May return nullptr.
   virtual NetworkingConfigDelegate* GetNetworkingConfigDelegate() const;
 
diff --git a/ash/wm/window_cycle_controller.cc b/ash/wm/window_cycle_controller.cc
index 42f866e..d2366c3 100644
--- a/ash/wm/window_cycle_controller.cc
+++ b/ash/wm/window_cycle_controller.cc
@@ -4,11 +4,13 @@
 
 #include "ash/wm/window_cycle_controller.h"
 
+#include "ash/metrics/user_metrics_recorder.h"
 #include "ash/session/session_state_delegate.h"
 #include "ash/shell.h"
 #include "ash/wm/mru_window_tracker.h"
 #include "ash/wm/window_cycle_list.h"
 #include "base/metrics/histogram.h"
+#include "ui/aura/window.h"
 #include "ui/events/event.h"
 #include "ui/events/event_handler.h"
 
@@ -16,6 +18,12 @@
 
 namespace {
 
+// Returns the most recently active window from the |window_list| or nullptr
+// if the list is empty.
+aura::Window* GetActiveWindow(const MruWindowTracker::WindowList& window_list) {
+  return window_list.empty() ? nullptr : window_list[0];
+}
+
 // Filter to watch for the termination of a keyboard gesture to cycle through
 // multiple windows.
 class WindowCycleEventFilter : public ui::EventHandler {
@@ -77,8 +85,12 @@
 }
 
 void WindowCycleController::StartCycling() {
-  window_cycle_list_.reset(new WindowCycleList(ash::Shell::GetInstance()->
-      mru_window_tracker()->BuildMruWindowList()));
+  MruWindowTracker::WindowList window_list =
+      Shell::GetInstance()->mru_window_tracker()->BuildMruWindowList();
+
+  active_window_before_window_cycle_ = GetActiveWindow(window_list);
+
+  window_cycle_list_.reset(new WindowCycleList(window_list));
   event_handler_.reset(new WindowCycleEventFilter());
   cycle_start_time_ = base::Time::Now();
   Shell::GetInstance()->metrics()->RecordUserMetricsAction(UMA_WINDOW_CYCLE);
@@ -94,10 +106,23 @@
 
 void WindowCycleController::StopCycling() {
   window_cycle_list_.reset();
+
+  aura::Window* active_window_after_window_cycle = GetActiveWindow(
+      Shell::GetInstance()->mru_window_tracker()->BuildMruWindowList());
+
   // Remove our key event filter.
   event_handler_.reset();
   UMA_HISTOGRAM_MEDIUM_TIMES("Ash.WindowCycleController.CycleTime",
                              base::Time::Now() - cycle_start_time_);
+
+  if (active_window_after_window_cycle != nullptr &&
+      active_window_before_window_cycle_ != active_window_after_window_cycle) {
+    Shell::GetInstance()
+        ->metrics()
+        ->task_switch_metrics_recorder()
+        .OnTaskSwitch(TaskSwitchMetricsRecorder::kWindowCycleController);
+  }
+  active_window_before_window_cycle_ = nullptr;
 }
 
 }  // namespace ash
diff --git a/ash/wm/window_cycle_controller.h b/ash/wm/window_cycle_controller.h
index 4120bc05..8cfd2a58 100644
--- a/ash/wm/window_cycle_controller.h
+++ b/ash/wm/window_cycle_controller.h
@@ -14,6 +14,10 @@
 class EventHandler;
 }
 
+namespace aura {
+class Window;
+}  // namespace aura
+
 namespace ash {
 
 class WindowCycleList;
@@ -63,6 +67,10 @@
 
   scoped_ptr<WindowCycleList> window_cycle_list_;
 
+  // Tracks what Window was active when starting to cycle and used to determine
+  // if the active Window changed in when ending cycling.
+  aura::Window* active_window_before_window_cycle_ = nullptr;
+
   // Event handler to watch for release of alt key.
   scoped_ptr<ui::EventHandler> event_handler_;
 
diff --git a/base/json/json_string_value_serializer.cc b/base/json/json_string_value_serializer.cc
index debf9f08..3787fdb6d 100644
--- a/base/json/json_string_value_serializer.cc
+++ b/base/json/json_string_value_serializer.cc
@@ -37,7 +37,7 @@
   if (pretty_print_)
     options |= base::JSONWriter::OPTIONS_PRETTY_PRINT;
 
-  return base::JSONWriter::WriteWithOptions(&root, options, json_string_);
+  return base::JSONWriter::WriteWithOptions(root, options, json_string_);
 }
 
 JSONStringValueDeserializer::JSONStringValueDeserializer(
diff --git a/base/json/json_value_serializer_unittest.cc b/base/json/json_value_serializer_unittest.cc
index b8aebe06..61860fd 100644
--- a/base/json/json_value_serializer_unittest.cc
+++ b/base/json/json_value_serializer_unittest.cc
@@ -302,7 +302,7 @@
   std::string output_js;
   DictionaryValue valueRoot;
   valueRoot.SetString("all_chars", all_chars);
-  JSONWriter::Write(&valueRoot, &output_js);
+  JSONWriter::Write(valueRoot, &output_js);
   ASSERT_EQ(expected_output, output_js);
 
   // Test JSONValueSerializer interface (uses JSONWriter).
diff --git a/base/json/json_writer.cc b/base/json/json_writer.cc
index d14c92c0..abfead800 100644
--- a/base/json/json_writer.cc
+++ b/base/json/json_writer.cc
@@ -21,12 +21,13 @@
 #endif
 
 // static
-bool JSONWriter::Write(const Value* const node, std::string* json) {
+bool JSONWriter::Write(const Value& node, std::string* json) {
   return WriteWithOptions(node, 0, json);
 }
 
 // static
-bool JSONWriter::WriteWithOptions(const Value* const node, int options,
+bool JSONWriter::WriteWithOptions(const Value& node,
+                                  int options,
                                   std::string* json) {
   json->clear();
   // Is there a better way to estimate the size of the output?
@@ -50,8 +51,8 @@
   DCHECK(json);
 }
 
-bool JSONWriter::BuildJSONString(const Value* const node, size_t depth) {
-  switch (node->GetType()) {
+bool JSONWriter::BuildJSONString(const Value& node, size_t depth) {
+  switch (node.GetType()) {
     case Value::TYPE_NULL: {
       json_string_->append("null");
       return true;
@@ -59,7 +60,7 @@
 
     case Value::TYPE_BOOLEAN: {
       bool value;
-      bool result = node->GetAsBoolean(&value);
+      bool result = node.GetAsBoolean(&value);
       DCHECK(result);
       json_string_->append(value ? "true" : "false");
       return result;
@@ -67,7 +68,7 @@
 
     case Value::TYPE_INTEGER: {
       int value;
-      bool result = node->GetAsInteger(&value);
+      bool result = node.GetAsInteger(&value);
       DCHECK(result);
       json_string_->append(IntToString(value));
       return result;
@@ -75,7 +76,7 @@
 
     case Value::TYPE_DOUBLE: {
       double value;
-      bool result = node->GetAsDouble(&value);
+      bool result = node.GetAsDouble(&value);
       DCHECK(result);
       if (omit_double_type_preservation_ &&
           value <= kint64max &&
@@ -107,7 +108,7 @@
 
     case Value::TYPE_STRING: {
       std::string value;
-      bool result = node->GetAsString(&value);
+      bool result = node.GetAsString(&value);
       DCHECK(result);
       EscapeJSONString(value, true, json_string_);
       return result;
@@ -120,7 +121,7 @@
 
       const ListValue* list = NULL;
       bool first_value_has_been_output = false;
-      bool result = node->GetAsList(&list);
+      bool result = node.GetAsList(&list);
       DCHECK(result);
       for (ListValue::const_iterator it = list->begin(); it != list->end();
            ++it) {
@@ -134,7 +135,7 @@
             json_string_->push_back(' ');
         }
 
-        if (!BuildJSONString(value, depth))
+        if (!BuildJSONString(*value, depth))
           result = false;
 
         first_value_has_been_output = true;
@@ -153,7 +154,7 @@
 
       const DictionaryValue* dict = NULL;
       bool first_value_has_been_output = false;
-      bool result = node->GetAsDictionary(&dict);
+      bool result = node.GetAsDictionary(&dict);
       DCHECK(result);
       for (DictionaryValue::Iterator itr(*dict); !itr.IsAtEnd();
            itr.Advance()) {
@@ -176,7 +177,7 @@
         if (pretty_print_)
           json_string_->push_back(' ');
 
-        if (!BuildJSONString(&itr.value(), depth + 1U))
+        if (!BuildJSONString(itr.value(), depth + 1U))
           result = false;
 
         first_value_has_been_output = true;
diff --git a/base/json/json_writer.h b/base/json/json_writer.h
index 9709c7e7..5711665 100644
--- a/base/json/json_writer.h
+++ b/base/json/json_writer.h
@@ -38,11 +38,12 @@
   // TODO(tc): Should we generate json if it would be invalid json (e.g.,
   // |node| is not a DictionaryValue/ListValue or if there are inf/-inf float
   // values)? Return true on success and false on failure.
-  static bool Write(const Value* const node, std::string* json);
+  static bool Write(const Value& node, std::string* json);
 
   // Same as above but with |options| which is a bunch of JSONWriter::Options
   // bitwise ORed together. Return true on success and false on failure.
-  static bool WriteWithOptions(const Value* const node, int options,
+  static bool WriteWithOptions(const Value& node,
+                               int options,
                                std::string* json);
 
  private:
@@ -50,7 +51,7 @@
 
   // Called recursively to build the JSON string. When completed,
   // |json_string_| will contain the JSON.
-  bool BuildJSONString(const Value* const node, size_t depth);
+  bool BuildJSONString(const Value& node, size_t depth);
 
   // Adds space to json_string_ for the indent level.
   void IndentLine(size_t depth);
diff --git a/base/json/json_writer_unittest.cc b/base/json/json_writer_unittest.cc
index 5ac2590..0daeafc 100644
--- a/base/json/json_writer_unittest.cc
+++ b/base/json/json_writer_unittest.cc
@@ -12,47 +12,39 @@
   std::string output_js;
 
   // Test null.
-  EXPECT_TRUE(JSONWriter::Write(Value::CreateNullValue().get(), &output_js));
+  EXPECT_TRUE(JSONWriter::Write(*Value::CreateNullValue(), &output_js));
   EXPECT_EQ("null", output_js);
 
   // Test empty dict.
-  DictionaryValue dict;
-  EXPECT_TRUE(JSONWriter::Write(&dict, &output_js));
+  EXPECT_TRUE(JSONWriter::Write(DictionaryValue(), &output_js));
   EXPECT_EQ("{}", output_js);
 
   // Test empty list.
-  ListValue list;
-  EXPECT_TRUE(JSONWriter::Write(&list, &output_js));
+  EXPECT_TRUE(JSONWriter::Write(ListValue(), &output_js));
   EXPECT_EQ("[]", output_js);
 
   // Test integer values.
-  FundamentalValue int_value(42);
-  EXPECT_TRUE(JSONWriter::Write(&int_value, &output_js));
+  EXPECT_TRUE(JSONWriter::Write(FundamentalValue(42), &output_js));
   EXPECT_EQ("42", output_js);
 
   // Test boolean values.
-  FundamentalValue bool_value(true);
-  EXPECT_TRUE(JSONWriter::Write(&bool_value, &output_js));
+  EXPECT_TRUE(JSONWriter::Write(FundamentalValue(true), &output_js));
   EXPECT_EQ("true", output_js);
 
   // Test Real values should always have a decimal or an 'e'.
-  FundamentalValue double_value(1.0);
-  EXPECT_TRUE(JSONWriter::Write(&double_value, &output_js));
+  EXPECT_TRUE(JSONWriter::Write(FundamentalValue(1.0), &output_js));
   EXPECT_EQ("1.0", output_js);
 
   // Test Real values in the the range (-1, 1) must have leading zeros
-  FundamentalValue double_value2(0.2);
-  EXPECT_TRUE(JSONWriter::Write(&double_value2, &output_js));
+  EXPECT_TRUE(JSONWriter::Write(FundamentalValue(0.2), &output_js));
   EXPECT_EQ("0.2", output_js);
 
   // Test Real values in the the range (-1, 1) must have leading zeros
-  FundamentalValue double_value3(-0.8);
-  EXPECT_TRUE(JSONWriter::Write(&double_value3, &output_js));
+  EXPECT_TRUE(JSONWriter::Write(FundamentalValue(-0.8), &output_js));
   EXPECT_EQ("-0.8", output_js);
 
   // Test String values.
-  StringValue string_value("foo");
-  EXPECT_TRUE(JSONWriter::Write(&string_value, &output_js));
+  EXPECT_TRUE(JSONWriter::Write(StringValue("foo"), &output_js));
   EXPECT_EQ("\"foo\"", output_js);
 }
 
@@ -71,11 +63,10 @@
   root_dict.Set("list", list.Pass());
 
   // Test the pretty-printer.
-  EXPECT_TRUE(JSONWriter::Write(&root_dict, &output_js));
+  EXPECT_TRUE(JSONWriter::Write(root_dict, &output_js));
   EXPECT_EQ("{\"list\":[{\"inner int\":10},[],true]}", output_js);
-  EXPECT_TRUE(JSONWriter::WriteWithOptions(&root_dict,
-                                           JSONWriter::OPTIONS_PRETTY_PRINT,
-                                           &output_js));
+  EXPECT_TRUE(JSONWriter::WriteWithOptions(
+      root_dict, JSONWriter::OPTIONS_PRETTY_PRINT, &output_js));
 
   // The pretty-printer uses a different newline style on Windows than on
   // other platforms.
@@ -102,13 +93,13 @@
   scoped_ptr<DictionaryValue> period_dict2(new DictionaryValue());
   period_dict2->SetIntegerWithoutPathExpansion("g.h.i.j", 1);
   period_dict.SetWithoutPathExpansion("d.e.f", period_dict2.Pass());
-  EXPECT_TRUE(JSONWriter::Write(&period_dict, &output_js));
+  EXPECT_TRUE(JSONWriter::Write(period_dict, &output_js));
   EXPECT_EQ("{\"a.b\":3,\"c\":2,\"d.e.f\":{\"g.h.i.j\":1}}", output_js);
 
   DictionaryValue period_dict3;
   period_dict3.SetInteger("a.b", 2);
   period_dict3.SetIntegerWithoutPathExpansion("a.b", 1);
-  EXPECT_TRUE(JSONWriter::Write(&period_dict3, &output_js));
+  EXPECT_TRUE(JSONWriter::Write(period_dict3, &output_js));
   EXPECT_EQ("{\"a\":{\"b\":2},\"a.b\":1}", output_js);
 }
 
@@ -118,9 +109,9 @@
   // Binary values should return errors unless suppressed via the
   // OPTIONS_OMIT_BINARY_VALUES flag.
   scoped_ptr<Value> root(BinaryValue::CreateWithCopiedBuffer("asdf", 4));
-  EXPECT_FALSE(JSONWriter::Write(root.get(), &output_js));
+  EXPECT_FALSE(JSONWriter::Write(*root, &output_js));
   EXPECT_TRUE(JSONWriter::WriteWithOptions(
-      root.get(), JSONWriter::OPTIONS_OMIT_BINARY_VALUES, &output_js));
+      *root, JSONWriter::OPTIONS_OMIT_BINARY_VALUES, &output_js));
   EXPECT_TRUE(output_js.empty());
 
   ListValue binary_list;
@@ -129,9 +120,9 @@
   binary_list.Append(BinaryValue::CreateWithCopiedBuffer("asdf", 4));
   binary_list.Append(make_scoped_ptr(new FundamentalValue(2)));
   binary_list.Append(BinaryValue::CreateWithCopiedBuffer("asdf", 4));
-  EXPECT_FALSE(JSONWriter::Write(&binary_list, &output_js));
+  EXPECT_FALSE(JSONWriter::Write(binary_list, &output_js));
   EXPECT_TRUE(JSONWriter::WriteWithOptions(
-      &binary_list, JSONWriter::OPTIONS_OMIT_BINARY_VALUES, &output_js));
+      binary_list, JSONWriter::OPTIONS_OMIT_BINARY_VALUES, &output_js));
   EXPECT_EQ("[5,2]", output_js);
 
   DictionaryValue binary_dict;
@@ -143,9 +134,9 @@
   binary_dict.SetInteger("d", 2);
   binary_dict.Set(
       "e", make_scoped_ptr(BinaryValue::CreateWithCopiedBuffer("asdf", 4)));
-  EXPECT_FALSE(JSONWriter::Write(&binary_dict, &output_js));
+  EXPECT_FALSE(JSONWriter::Write(binary_dict, &output_js));
   EXPECT_TRUE(JSONWriter::WriteWithOptions(
-      &binary_dict, JSONWriter::OPTIONS_OMIT_BINARY_VALUES, &output_js));
+      binary_dict, JSONWriter::OPTIONS_OMIT_BINARY_VALUES, &output_js));
   EXPECT_EQ("{\"b\":5,\"d\":2}", output_js);
 }
 
@@ -155,8 +146,7 @@
   // Test allowing a double with no fractional part to be written as an integer.
   FundamentalValue double_value(1e10);
   EXPECT_TRUE(JSONWriter::WriteWithOptions(
-      &double_value,
-      JSONWriter::OPTIONS_OMIT_DOUBLE_TYPE_PRESERVATION,
+      double_value, JSONWriter::OPTIONS_OMIT_DOUBLE_TYPE_PRESERVATION,
       &output_js));
   EXPECT_EQ("10000000000", output_js);
 }
diff --git a/base/trace_event/trace_event_argument.cc b/base/trace_event/trace_event_argument.cc
index 88b1879..e83aa737 100644
--- a/base/trace_event/trace_event_argument.cc
+++ b/base/trace_event/trace_event_argument.cc
@@ -108,7 +108,7 @@
 
 void TracedValue::AppendAsTraceFormat(std::string* out) const {
   std::string tmp;
-  JSONWriter::Write(stack_.front(), &tmp);
+  JSONWriter::Write(*stack_.front(), &tmp);
   *out += tmp;
   DCHECK_EQ(1u, stack_.size()) << tmp;
 }
diff --git a/base/trace_event/trace_event_system_stats_monitor.cc b/base/trace_event/trace_event_system_stats_monitor.cc
index 98f361a..c08d9b9 100644
--- a/base/trace_event/trace_event_system_stats_monitor.cc
+++ b/base/trace_event/trace_event_system_stats_monitor.cc
@@ -125,7 +125,7 @@
 void AppendSystemProfileAsTraceFormat(const SystemMetrics& system_metrics,
                                       std::string* output) {
   std::string tmp;
-  base::JSONWriter::Write(system_metrics.ToValue().get(), &tmp);
+  base::JSONWriter::Write(*system_metrics.ToValue(), &tmp);
   *output += tmp;
 }
 
diff --git a/base/values.cc b/base/values.cc
index 4093eba..ebd7157 100644
--- a/base/values.cc
+++ b/base/values.cc
@@ -1168,9 +1168,7 @@
 
 std::ostream& operator<<(std::ostream& out, const Value& value) {
   std::string json;
-  JSONWriter::WriteWithOptions(&value,
-                               JSONWriter::OPTIONS_PRETTY_PRINT,
-                               &json);
+  JSONWriter::WriteWithOptions(value, JSONWriter::OPTIONS_PRETTY_PRINT, &json);
   return out << json;
 }
 
diff --git a/build/all.gyp b/build/all.gyp
index 4837097..04ba3f8 100644
--- a/build/all.gyp
+++ b/build/all.gyp
@@ -884,11 +884,6 @@
                 '../chrome/chrome.gyp:unit_tests_apk',
               ],
             }],
-            ['enable_webrtc==1 and "<(libpeer_target_type)"=="static_library"', {
-              'dependencies': [
-                '../components/devtools_bridge.gyp:devtools_bridge_tests_apk',
-              ],
-            }],
           ],
         },
         {
@@ -900,8 +895,6 @@
             '../content/content_shell_and_tests.gyp:content_browsertests',
             '../tools/android/android_tools.gyp:android_tools',
             '../tools/android/android_tools.gyp:memconsumer',
-            # Unit test bundles packaged as an apk.
-            '../components/devtools_bridge.gyp:devtools_bridge_tests_apk',
             '../content/content_shell_and_tests.gyp:content_browsertests_apk',
           ],
         },  # target_name: android_builder_chromium_webrtc
diff --git a/build/android/ant/apk-package.xml b/build/android/ant/apk-package.xml
index 99279a4..e8b76f7e 100644
--- a/build/android/ant/apk-package.xml
+++ b/build/android/ant/apk-package.xml
@@ -67,7 +67,7 @@
           debugpackaging="${build.is.packaging.debug}"
           debugsigning="${build.is.signing.debug}"
           verbose="${verbose}"
-          hascode="true"
+          hascode="${HAS_CODE}"
           previousBuildType="/"
           buildType="${build.is.packaging.debug}/${build.is.signing.debug}">
         <dex path="${intermediate.dex.file}"/>
diff --git a/build/android/apkbuilder_action.gypi b/build/android/apkbuilder_action.gypi
new file mode 100644
index 0000000..27807d8
--- /dev/null
+++ b/build/android/apkbuilder_action.gypi
@@ -0,0 +1,79 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This file is a helper to java_apk.gypi. It should be used to create an
+# action that runs ApkBuilder via ANT.
+#
+# Required variables:
+#  apk_name - File name (minus path & extension) of the output apk.
+#  apk_path - Path to output apk.
+#  package_input_paths - Late-evaluated list of resource zips.
+#  native_libs_dir - Path to lib/ directory to use. Set to an empty directory
+#    if no native libs are needed.
+# Optional variables:
+#  has_code - Whether to include classes.dex in the apk.
+#  dex_path - Path to classes.dex. Used only when has_code=1.
+#  extra_inputs - List of extra action inputs.
+{
+  'variables': {
+    'variables': {
+      'has_code%': 1,
+    },
+    'conditions': [
+      ['has_code == 0', {
+        'has_code_str': 'false',
+      }, {
+        'has_code_str': 'true',
+      }],
+    ],
+    'has_code%': '<(has_code)',
+    'extra_inputs%': [],
+    # Write the inputs list to a file, so that its mtime is updated when
+    # the list of inputs changes.
+    'inputs_list_file': '>|(apk_package.<(_target_name).<(apk_name).gypcmd >@(package_input_paths))',
+    'resource_packaged_apk_name': '<(apk_name)-resources.ap_',
+    'resource_packaged_apk_path': '<(intermediate_dir)/<(resource_packaged_apk_name)',
+  },
+  'action_name': 'apkbuilder_<(apk_name)',
+  'message': 'Packaging <(apk_name)',
+  'inputs': [
+    '<(DEPTH)/build/android/ant/apk-package.xml',
+    '<(DEPTH)/build/android/gyp/util/build_utils.py',
+    '<(DEPTH)/build/android/gyp/ant.py',
+    '<(resource_packaged_apk_path)',
+    '<@(extra_inputs)',
+    '>@(package_input_paths)',
+    '>(inputs_list_file)',
+  ],
+  'outputs': [
+    '<(apk_path)',
+  ],
+  'conditions': [
+    ['has_code == 1', {
+      'inputs': ['<(dex_path)'],
+      'action': [
+        '-DDEX_FILE_PATH=<(dex_path)',
+      ]
+    }],
+  ],
+  'action': [
+    'python', '<(DEPTH)/build/android/gyp/ant.py',
+    '--',
+    '-quiet',
+    '-DHAS_CODE=<(has_code_str)',
+    '-DANDROID_SDK_ROOT=<(android_sdk_root)',
+    '-DANDROID_SDK_TOOLS=<(android_sdk_tools)',
+    '-DRESOURCE_PACKAGED_APK_NAME=<(resource_packaged_apk_name)',
+    '-DNATIVE_LIBS_DIR=<(native_libs_dir)',
+    '-DAPK_NAME=<(apk_name)',
+    '-DCONFIGURATION_NAME=<(CONFIGURATION_NAME)',
+    '-DOUT_DIR=<(intermediate_dir)',
+    '-DUNSIGNED_APK_PATH=<(apk_path)',
+    '-DEMMA_INSTRUMENT=<(emma_instrument)',
+    '-DEMMA_DEVICE_JAR=<(emma_device_jar)',
+    '-Dbasedir=.',
+    '-buildfile',
+    '<(DEPTH)/build/android/ant/apk-package.xml',
+  ]
+}
diff --git a/build/android/gyp/package_resources.py b/build/android/gyp/package_resources.py
index 2251de00..53937664 100755
--- a/build/android/gyp/package_resources.py
+++ b/build/android/gyp/package_resources.py
@@ -60,7 +60,7 @@
   # Check that required options have been provided.
   required_options = ('android_sdk', 'android_sdk_tools', 'configuration_name',
                       'android_manifest', 'version_code', 'version_name',
-                      'resource_zips', 'asset_dir', 'apk_path')
+                      'apk_path')
 
   build_utils.CheckOptions(options, parser, required=required_options)
 
@@ -140,16 +140,17 @@
     if options.shared_resources:
       package_command.append('--shared-lib')
 
-    if os.path.exists(options.asset_dir):
+    if options.asset_dir and os.path.exists(options.asset_dir):
       package_command += ['-A', options.asset_dir]
 
-    dep_zips = build_utils.ParseGypList(options.resource_zips)
-    for z in dep_zips:
-      subdir = os.path.join(temp_dir, os.path.basename(z))
-      if os.path.exists(subdir):
-        raise Exception('Resource zip name conflict: ' + os.path.basename(z))
-      build_utils.ExtractAll(z, path=subdir)
-      package_command += PackageArgsForExtractedZip(subdir)
+    if options.resource_zips:
+      dep_zips = build_utils.ParseGypList(options.resource_zips)
+      for z in dep_zips:
+        subdir = os.path.join(temp_dir, os.path.basename(z))
+        if os.path.exists(subdir):
+          raise Exception('Resource zip name conflict: ' + os.path.basename(z))
+        build_utils.ExtractAll(z, path=subdir)
+        package_command += PackageArgsForExtractedZip(subdir)
 
     if 'Debug' in options.configuration_name:
       package_command += ['--debug-mode']
diff --git a/build/android/package_resources_action.gypi b/build/android/package_resources_action.gypi
new file mode 100644
index 0000000..fe1645f8
--- /dev/null
+++ b/build/android/package_resources_action.gypi
@@ -0,0 +1,73 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This file is a helper to java_apk.gypi. It should be used to create an
+# action that runs ApkBuilder via ANT.
+#
+# Required variables:
+#  apk_name - File name (minus path & extension) of the output apk.
+#  android_manifest_path - Path to AndroidManifest.xml.
+#  app_manifest_version_name - set the apps 'human readable' version number.
+#  app_manifest_version_code - set the apps version number.
+# Optional variables:
+#  asset_location - The directory where assets are located (if any).
+#  resource_zips - List of paths to resource zip files.
+#  shared_resources - Make a resource package that can be loaded by a different
+#    application at runtime to access the package's resources.
+#  extensions_to_not_compress - E.g.: 'pak,dat,bin'
+#  extra_inputs - List of extra action inputs.
+{
+  'variables': {
+    'asset_location%': '',
+    'resource_zips%': [],
+    'shared_resources%': 0,
+    'extensions_to_not_compress%': '',
+    'extra_inputs%': [],
+    'resource_packaged_apk_name': '<(apk_name)-resources.ap_',
+    'resource_packaged_apk_path': '<(intermediate_dir)/<(resource_packaged_apk_name)',
+  },
+  'action_name': 'package_resources_<(apk_name)',
+  'message': 'packaging resources for <(apk_name)',
+  'inputs': [
+    # TODO: This isn't always rerun correctly, http://crbug.com/351928
+    '<(DEPTH)/build/android/gyp/util/build_utils.py',
+    '<(DEPTH)/build/android/gyp/package_resources.py',
+    '<(android_manifest_path)',
+    '<@(extra_inputs)',
+  ],
+  'outputs': [
+    '<(resource_packaged_apk_path)',
+  ],
+  'action': [
+    'python', '<(DEPTH)/build/android/gyp/package_resources.py',
+    '--android-sdk', '<(android_sdk)',
+    '--android-sdk-tools', '<(android_sdk_tools)',
+    '--configuration-name', '<(CONFIGURATION_NAME)',
+    '--android-manifest', '<(android_manifest_path)',
+    '--version-code', '<(app_manifest_version_code)',
+    '--version-name', '<(app_manifest_version_name)',
+    '--no-compress', '<(extensions_to_not_compress)',
+    '--apk-path', '<(resource_packaged_apk_path)',
+  ],
+  'conditions': [
+    ['shared_resources == 1', {
+      'action': [
+        '--shared-resources',
+      ],
+    }],
+    ['asset_location != ""', {
+      'action': [
+        '--asset-dir', '<(asset_location)',
+      ],
+    }],
+    ['resource_zips != []', {
+      'action': [
+        '--resource-zips', '>(resource_zips)',
+      ],
+      'inputs': [
+        '>@(resource_zips)',
+      ],
+    }],
+  ],
+}
diff --git a/build/config/BUILD.gn b/build/config/BUILD.gn
index 5eb5e0a..26bcd7d 100644
--- a/build/config/BUILD.gn
+++ b/build/config/BUILD.gn
@@ -248,6 +248,9 @@
   } else {
     defines += [ "CHROMIUM_BUILD" ]
   }
+  if (enable_media_router) {
+    defines += [ "ENABLE_MEDIA_ROUTER=1" ]
+  }
 }
 
 # Debug/release ----------------------------------------------------------------
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni
index 07a05e1..a5a12352 100644
--- a/build/config/android/internal_rules.gni
+++ b/build/config/android/internal_rules.gni
@@ -449,8 +449,13 @@
   _android_manifest = invoker.android_manifest
   _base_path = invoker.base_path
   _final_apk_path = invoker.apk_path
-  _resources_zip = invoker.resources_zip
-  _dex_path = invoker.dex_path
+
+  if (defined(invoker.resources_zip)) {
+    _resources_zip = invoker.resources_zip
+  }
+  if (defined(invoker.dex_path)) {
+    _dex_path = invoker.dex_path
+  }
   _keystore_path = invoker.keystore_path
   _keystore_name = invoker.keystore_name
   _keystore_password = invoker.keystore_password
@@ -466,7 +471,6 @@
     _native_libs_dir = invoker.native_libs_dir
   }
 
-  _asset_location = "//build/android/empty/res"
   if (defined(invoker.asset_location)) {
     _asset_location = invoker.asset_location
   }
@@ -493,14 +497,15 @@
     depfile = "${target_gen_dir}/${target_name}.d"
     inputs = [
       _android_manifest,
-      _resources_zip,
     ]
+    if (defined(_resources_zip)) {
+      inputs += [ _resources_zip ]
+    }
     outputs = [
       depfile,
       _resource_packaged_apk_path,
     ]
 
-    _rebased_resources_zips = [ rebase_path(_resources_zip, root_build_dir) ]
     args = [
       "--depfile",
       rebase_path(depfile, root_build_dir),
@@ -515,13 +520,22 @@
       _version_code,
       "--version-name",
       _version_name,
-      "--asset-dir",
-      rebase_path(_asset_location, root_build_dir),
-      "--resource-zips=$_rebased_resources_zips",
       "--apk-path",
       rebase_path(_resource_packaged_apk_path, root_build_dir),
     ]
 
+    if (defined(_asset_location)) {
+      args += [
+        "--asset-dir",
+        rebase_path(_asset_location, root_build_dir),
+      ]
+    }
+    if (defined(_resources_zip)) {
+      args += [
+        "--resource-zips",
+        rebase_path(_resources_zip, root_build_dir),
+      ]
+    }
     if (_shared_resources) {
       args += [ "--shared-resources" ]
     }
@@ -534,10 +548,12 @@
     depfile = "$target_gen_dir/$target_name.d"
 
     inputs = [
-      _dex_path,
       _resource_packaged_apk_path,
       _ant_script,
     ]
+    if (defined(_dex_path)) {
+      inputs += [ _dex_path ]
+    }
 
     outputs = [
       depfile,
@@ -549,7 +565,6 @@
         rebase_path(_resource_packaged_apk_path, root_build_dir)
     _rebased_packaged_apk_path = rebase_path(_packaged_apk_path, root_build_dir)
     _rebased_native_libs_dir = rebase_path(_native_libs_dir, root_build_dir)
-    _rebased_dex_path = rebase_path(_dex_path, root_build_dir)
     args = [
       "--depfile",
       rebase_path(depfile, root_build_dir),
@@ -564,11 +579,19 @@
       "-DUNSIGNED_APK_PATH=$_rebased_packaged_apk_path",
       "-DEMMA_INSTRUMENT=0",
       "-DEMMA_DEVICE_JAR=$_rebased_emma_jar",
-      "-DDEX_FILE_PATH=$_rebased_dex_path",
       "-Dbasedir=.",
       "-buildfile",
       rebase_path(_ant_script, root_build_dir),
     ]
+    if (defined(_dex_path)) {
+      _rebased_dex_path = rebase_path(_dex_path, root_build_dir)
+      args += [
+        "-DDEX_FILE_PATH=$_rebased_dex_path",
+        "-DHAS_CODE=true",
+      ]
+    } else {
+      args += [ "-DHAS_CODE=false" ]
+    }
   }
 
   action("${target_name}__finalize") {
@@ -616,6 +639,7 @@
   group(target_name) {
     deps = [
       ":${target_name}__finalize",
+      ":${target_name}__package_resources",
     ]
   }
 }
@@ -1080,6 +1104,10 @@
       args += [ "--v14-verify-only" ]
     }
 
+    if (defined(invoker.v14_skip) && invoker.v14_skip) {
+      args += [ "--v14-skip" ]
+    }
+
     if (defined(invoker.shared_resources) && invoker.shared_resources) {
       args += [ "--shared-resources" ]
     }
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni
index 0b7593d2..6140b5e 100644
--- a/build/config/android/rules.gni
+++ b/build/config/android/rules.gni
@@ -583,6 +583,10 @@
       v14_verify_only = invoker.v14_verify_only
     }
 
+    if (defined(invoker.v14_skip)) {
+      v14_skip = invoker.v14_skip
+    }
+
     if (defined(invoker.shared_resources)) {
       shared_resources = invoker.shared_resources
     }
diff --git a/build/gn_migration.gypi b/build/gn_migration.gypi
index ab16c05..f9a4db8 100644
--- a/build/gn_migration.gypi
+++ b/build/gn_migration.gypi
@@ -168,7 +168,6 @@
         '../skia/skia.gyp:image_operations_bench',
         '../sql/sql.gyp:sql_unittests',
         '../sync/sync.gyp:run_sync_testserver',
-        '../sync/sync.gyp:sync_endtoend_tests',
         '../sync/sync.gyp:sync_unit_tests',
         '../sync/tools/sync_tools.gyp:sync_client',
         '../sync/tools/sync_tools.gyp:sync_listen_notifications',
diff --git a/build/java_apk.gypi b/build/java_apk.gypi
index 154c16e83..ab415a9 100644
--- a/build/java_apk.gypi
+++ b/build/java_apk.gypi
@@ -128,10 +128,7 @@
     'android_manifest_path%': '<(java_in_dir)/AndroidManifest.xml',
     'push_stamp': '<(intermediate_dir)/push.stamp',
     'link_stamp': '<(intermediate_dir)/link.stamp',
-    'package_resources_stamp': '<(intermediate_dir)/package_resources.stamp',
     'resource_zip_path': '<(intermediate_dir)/<(_target_name).resources.zip',
-    'resource_packaged_apk_name': '<(apk_name)-resources.ap_',
-    'resource_packaged_apk_path': '<(intermediate_dir)/<(resource_packaged_apk_name)',
     'shared_resources%': 0,
     'unsigned_apk_path': '<(intermediate_dir)/<(apk_name)-unsigned.apk',
     'final_apk_path%': '<(PRODUCT_DIR)/apks/<(apk_name).apk',
@@ -867,109 +864,32 @@
       'includes': [ 'android/dex_action.gypi' ],
     },
     {
-      'action_name': 'package_resources',
-      'message': 'packaging resources for <(_target_name)',
       'variables': {
-        'package_resources_options': [],
-        'package_resource_zip_input_paths': [
+        'extra_inputs': ['<(codegen_stamp)'],
+        'resource_zips': [
           '<(resource_zip_path)',
-          '>@(dependencies_res_zip_paths)',
         ],
         'conditions': [
-          ['shared_resources == 1', {
-            'package_resources_options+': ['--shared-resources']
+          ['is_test_apk == 0', {
+            'resource_zips': [
+              '>@(dependencies_res_zip_paths)',
+            ],
           }],
         ],
       },
-      'conditions': [
-        ['is_test_apk == 1', {
-          'variables': {
-            'dependencies_res_zip_paths=': [],
-            'additional_res_packages=': [],
-          }
-        }],
-      ],
-      'inputs': [
-        # TODO: This isn't always rerun correctly, http://crbug.com/351928
-        '<(DEPTH)/build/android/gyp/util/build_utils.py',
-        '<(DEPTH)/build/android/gyp/package_resources.py',
-        '<(android_manifest_path)',
-
-        '>@(package_resource_zip_input_paths)',
-
-        '<(codegen_stamp)',
-      ],
-      'outputs': [
-        '<(resource_packaged_apk_path)',
-      ],
-      'action': [
-        'python', '<(DEPTH)/build/android/gyp/package_resources.py',
-        '--android-sdk', '<(android_sdk)',
-        '--android-sdk-tools', '<(android_sdk_tools)',
-
-        '--configuration-name', '<(CONFIGURATION_NAME)',
-
-        '--android-manifest', '<(android_manifest_path)',
-        '--version-code', '<(app_manifest_version_code)',
-        '--version-name', '<(app_manifest_version_name)',
-
-        '--asset-dir', '<(asset_location)',
-        '--resource-zips', '>(package_resource_zip_input_paths)',
-
-        '--no-compress', '<(extensions_to_not_compress)',
-
-        '--apk-path', '<(resource_packaged_apk_path)',
-
-        '<@(package_resources_options)',
-      ],
+      'includes': [ 'android/package_resources_action.gypi' ],
     },
     {
-      'action_name': 'ant_package_<(_target_name)',
-      'message': 'Packaging <(_target_name)',
       'variables': {
-        # Write the inputs list to a file, so that its mtime is updated when
-        # the list of inputs changes.
-        'inputs_list_file': '>|(apk_package.<(_target_name).gypcmd >@(package_input_paths))'
+        'apk_path': '<(unsigned_apk_path)',
+        'native_libs_dir': '<(apk_package_native_libs_dir)',
+        'conditions': [
+          ['native_lib_target != ""', {
+            'extra_inputs': ['<(native_lib_placeholder_stamp)'],
+          }],
+        ],
       },
-      'inputs': [
-        '<(DEPTH)/build/android/ant/apk-package.xml',
-        '<(DEPTH)/build/android/gyp/util/build_utils.py',
-        '<(DEPTH)/build/android/gyp/ant.py',
-        '<(dex_path)',
-        '<(codegen_stamp)',
-        '<(obfuscate_stamp)',
-        '<(resource_packaged_apk_path)',
-        '>@(package_input_paths)',
-        '>(inputs_list_file)',
-      ],
-      'outputs': [
-        '<(unsigned_apk_path)',
-      ],
-      'conditions': [
-        ['native_lib_target != ""', {
-          'inputs': ['<(native_lib_placeholder_stamp)'],
-        }],
-      ],
-      'action': [
-        'python', '<(DEPTH)/build/android/gyp/ant.py',
-        '--',
-        '-quiet',
-        '-DDEX_FILE_PATH=<(intermediate_dir)/classes.dex',
-        '-DANDROID_SDK_ROOT=<(android_sdk_root)',
-        '-DANDROID_SDK_TOOLS=<(android_sdk_tools)',
-        '-DRESOURCE_PACKAGED_APK_NAME=<(resource_packaged_apk_name)',
-        '-DAPK_NAME=<(apk_name)',
-        '-DCONFIGURATION_NAME=<(CONFIGURATION_NAME)',
-        '-DNATIVE_LIBS_DIR=<(apk_package_native_libs_dir)',
-        '-DOUT_DIR=<(intermediate_dir)',
-        '-DUNSIGNED_APK_PATH=<(unsigned_apk_path)',
-        '-DEMMA_INSTRUMENT=<(emma_instrument)',
-        '-DEMMA_DEVICE_JAR=<(emma_device_jar)',
-
-        '-Dbasedir=.',
-        '-buildfile',
-        '<(DEPTH)/build/android/ant/apk-package.xml',
-      ]
+      'includes': ['android/apkbuilder_action.gypi'],
     },
   ],
 }
diff --git a/build/secondary/third_party/android_tools/BUILD.gn b/build/secondary/third_party/android_tools/BUILD.gn
index 099b892..f054125f 100644
--- a/build/secondary/third_party/android_tools/BUILD.gn
+++ b/build/secondary/third_party/android_tools/BUILD.gn
@@ -34,7 +34,7 @@
 }
 
 android_resources("android_support_v7_appcompat_resources") {
-  v14_verify_only = true
+  v14_skip = true
   resource_dirs =
       [ "$android_sdk_root/extras/android/support/v7/appcompat/res" ]
   custom_package = "android.support.v7.appcompat"
@@ -48,7 +48,7 @@
 }
 
 android_resources("android_support_v7_mediarouter_resources") {
-  v14_verify_only = true
+  v14_skip = true
   resource_dirs =
       [ "$android_sdk_root/extras/android/support/v7/mediarouter/res" ]
   deps = [
@@ -73,7 +73,7 @@
 }
 
 android_resources("google_play_services_default_resources") {
-  v14_verify_only = true
+  v14_skip = true
   resource_dirs = [ "$android_sdk_root/extras/google/google_play_services/libproject/google-play-services_lib/res" ]
   custom_package = "com.google.android.gms"
 }
diff --git a/build/secondary/third_party/libsrtp/BUILD.gn b/build/secondary/third_party/libsrtp/BUILD.gn
index 8b9647c..7601bea0 100644
--- a/build/secondary/third_party/libsrtp/BUILD.gn
+++ b/build/secondary/third_party/libsrtp/BUILD.gn
@@ -4,12 +4,15 @@
 
 declare_args() {
   use_system_libsrtp = false
+  use_srtp_boringssl = true
 }
 
 config("libsrtp_config") {
   defines = [
+    "HAVE_CONFIG_H",
     "HAVE_STDLIB_H",
     "HAVE_STRING_H",
+    "TESTAPP_SOURCE",
   ]
 
   include_dirs = [
@@ -18,6 +21,10 @@
     "srtp/crypto/include",
   ]
 
+  if (use_srtp_boringssl) {
+    defines += [ "OPENSSL" ]
+  }
+
   if (is_posix) {
     defines += [
       "HAVE_INT16_T",
@@ -30,13 +37,14 @@
       "HAVE_STDINT_H",
       "HAVE_INTTYPES_H",
       "HAVE_NETINET_IN_H",
-      "INLINE=inline",
+      "HAVE_ARPA_INET_H",
+      "HAVE_UNISTD_H",
     ]
+    cflags = [ "-Wno-unused-variable" ]
   }
 
   if (is_win) {
     defines += [
-      "INLINE=__inline",
       "HAVE_BYTESWAP_METHODS_H",
 
       # All Windows architectures are this way.
@@ -149,6 +157,30 @@
     if (is_clang) {
       cflags = [ "-Wno-implicit-function-declaration" ]
     }
+
+    if (use_srtp_boringssl) {
+      deps = [
+        "//third_party/boringssl:boringssl",
+      ]
+      public_deps = [
+        "//third_party/boringssl:boringssl",
+      ]
+      sources -= [
+        "srtp/crypto/cipher/aes_cbc.c",
+        "srtp/crypto/cipher/aes_icm.c",
+        "srtp/crypto/hash/hmac.c",
+        "srtp/crypto/hash/sha1.c",
+        "srtp/crypto/rng/ctr_prng.c",
+        "srtp/crypto/rng/prng.c",
+      ]
+      sources += [
+        "srtp/crypto/cipher/aes_gcm_ossl.c",
+        "srtp/crypto/cipher/aes_icm_ossl.c",
+        "srtp/crypto/hash/hmac_ossl.c",
+        "srtp/crypto/include/aes_gcm_ossl.h",
+        "srtp/crypto/include/aes_icm_ossl.h",
+      ]
+    }
   }
 
   # TODO(GYP): A bunch of these tests don't compile (in gyp either). They're
@@ -238,6 +270,8 @@
       ]
       sources = [
         "srtp/crypto/test/cipher_driver.c",
+        "srtp/include/getopt_s.h",
+        "srtp/test/getopt_s.c",
       ]
     }
 
@@ -282,6 +316,8 @@
       ]
       sources = [
         "srtp/crypto/test/kernel_driver.c",
+        "srtp/include/getopt_s.h",
+        "srtp/test/getopt_s.c",
       ]
     }
 
@@ -304,6 +340,21 @@
       ]
       sources = [
         "srtp/crypto/test/rand_gen.c",
+        "srtp/include/getopt_s.h",
+        "srtp/test/getopt_s.c",
+      ]
+    }
+
+    executable("srtp_test_rand_gen_soak") {
+      configs -= [ "//build/config/compiler:chromium_code" ]
+      configs += [ "//build/config/compiler:no_chromium_code" ]
+      deps = [
+        ":libsrtp",
+      ]
+      sources = [
+        "srtp/crypto/test/rand_gen_soak.c",
+        "srtp/include/getopt_s.h",
+        "srtp/test/getopt_s.c",
       ]
     }
 
@@ -332,6 +383,7 @@
         ":srtp_test_kernel_driver",
         ":srtp_test_aes_calc",
         ":srtp_test_rand_gen",
+        ":srtp_test_rand_gen_soak",
         ":srtp_test_env",
       ]
     }
diff --git a/cc/blink/BUILD.gn b/cc/blink/BUILD.gn
index 1769efb..4854ead 100644
--- a/cc/blink/BUILD.gn
+++ b/cc/blink/BUILD.gn
@@ -78,11 +78,15 @@
       "web_animation_unittest.cc",
       "web_float_animation_curve_unittest.cc",
       "web_layer_impl_fixed_bounds_unittest.cc",
+
+      # Setup.
+      "test/cc_blink_test_suite.cc",
+      "test/run_all_unittests.cc",
     ]
 
     deps = [
       ":blink",
-      "//base/test:run_all_unittests",
+      "//base/test:test_support",
       "//base/third_party/dynamic_annotations",
       "//skia",
       "//testing/gtest",
diff --git a/cc/blink/cc_blink_tests.gyp b/cc/blink/cc_blink_tests.gyp
index 2e3fef5..f20c463 100644
--- a/cc/blink/cc_blink_tests.gyp
+++ b/cc/blink/cc_blink_tests.gyp
@@ -20,7 +20,8 @@
         'cc_blink.gyp:cc_blink',
       ],
       'sources': [
-        '../../base/test/run_all_unittests.cc',
+        'test/cc_blink_test_suite.cc',
+        'test/run_all_unittests.cc',
         'web_animation_unittest.cc',
         'web_float_animation_curve_unittest.cc',
         'web_layer_impl_fixed_bounds_unittest.cc',
diff --git a/cc/blink/test/cc_blink_test_suite.cc b/cc/blink/test/cc_blink_test_suite.cc
new file mode 100644
index 0000000..6202cfd3
--- /dev/null
+++ b/cc/blink/test/cc_blink_test_suite.cc
@@ -0,0 +1,33 @@
+// Copyright (c) 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 "cc/blink/test/cc_blink_test_suite.h"
+
+#include "base/message_loop/message_loop.h"
+#include "base/threading/thread_id_name_manager.h"
+
+namespace cc_blink {
+
+CCBlinkTestSuite::CCBlinkTestSuite(int argc, char** argv)
+    : base::TestSuite(argc, argv) {}
+
+CCBlinkTestSuite::~CCBlinkTestSuite() {}
+
+void CCBlinkTestSuite::Initialize() {
+  base::TestSuite::Initialize();
+
+  message_loop_.reset(new base::MessageLoop);
+
+  base::ThreadIdNameManager::GetInstance()->SetName(
+      base::PlatformThread::CurrentId(),
+      "Main");
+}
+
+void CCBlinkTestSuite::Shutdown() {
+  message_loop_ = nullptr;
+
+  base::TestSuite::Shutdown();
+}
+
+}  // namespace cc_blink
diff --git a/cc/blink/test/cc_blink_test_suite.h b/cc/blink/test/cc_blink_test_suite.h
new file mode 100644
index 0000000..faa76840
--- /dev/null
+++ b/cc/blink/test/cc_blink_test_suite.h
@@ -0,0 +1,36 @@
+// Copyright (c) 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 CC_BLINK_TEST_CC_BLINK_TEST_SUITE_H_
+#define CC_BLINK_TEST_CC_BLINK_TEST_SUITE_H_
+
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/test/test_suite.h"
+
+namespace base {
+class MessageLoop;
+}
+
+namespace cc_blink {
+
+class CCBlinkTestSuite : public base::TestSuite {
+ public:
+  CCBlinkTestSuite(int argc, char** argv);
+  ~CCBlinkTestSuite() override;
+
+ protected:
+  // Overridden from base::TestSuite:
+  void Initialize() override;
+  void Shutdown() override;
+
+ private:
+  scoped_ptr<base::MessageLoop> message_loop_;
+
+  DISALLOW_COPY_AND_ASSIGN(CCBlinkTestSuite);
+};
+
+}  // namespace cc_blink
+
+#endif  // CC_BLINK_TEST_CC_BLINK_TEST_SUITE_H_
diff --git a/cc/blink/test/run_all_unittests.cc b/cc/blink/test/run_all_unittests.cc
new file mode 100644
index 0000000..294039a
--- /dev/null
+++ b/cc/blink/test/run_all_unittests.cc
@@ -0,0 +1,17 @@
+// Copyright (c) 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 "base/bind.h"
+#include "base/test/launcher/unit_test_launcher.h"
+#include "cc/blink/test/cc_blink_test_suite.h"
+
+int main(int argc, char** argv) {
+  cc_blink::CCBlinkTestSuite test_suite(argc, argv);
+
+  return base::LaunchUnitTests(
+      argc,
+      argv,
+      base::Bind(&cc_blink::CCBlinkTestSuite::Run,
+                 base::Unretained(&test_suite)));
+}
diff --git a/cc/debug/traced_picture.cc b/cc/debug/traced_picture.cc
index 2c7622b6..3241871d 100644
--- a/cc/debug/traced_picture.cc
+++ b/cc/debug/traced_picture.cc
@@ -40,18 +40,16 @@
   scoped_ptr<base::DictionaryValue> alias(new base::DictionaryValue());
   alias->SetString("id_ref", base::StringPrintf("%p", picture_.get()));
 
-  scoped_ptr<base::DictionaryValue> res(new base::DictionaryValue());
-  res->Set("alias", alias.release());
-
+  base::DictionaryValue res;
+  res.Set("alias", alias.release());
   std::string tmp;
-  base::JSONWriter::Write(res.get(), &tmp);
+  base::JSONWriter::Write(res, &tmp);
   out->append(tmp);
 }
 
 void TracedPicture::AppendPicture(std::string* out) const {
-  scoped_ptr<base::Value> value = picture_->AsValue();
   std::string tmp;
-  base::JSONWriter::Write(value.get(), &tmp);
+  base::JSONWriter::Write(*picture_->AsValue(), &tmp);
   out->append(tmp);
 }
 
diff --git a/cc/layers/delegated_renderer_layer_impl.cc b/cc/layers/delegated_renderer_layer_impl.cc
index 63039fb..a99cd17 100644
--- a/cc/layers/delegated_renderer_layer_impl.cc
+++ b/cc/layers/delegated_renderer_layer_impl.cc
@@ -78,6 +78,7 @@
   own_child_id_ = false;
 
   if (have_render_passes_to_push_) {
+    DCHECK(child_id_);
     // This passes ownership of the render passes to the active tree.
     delegated_layer->SetRenderPasses(&render_passes_in_draw_order_);
     // Once resources are on the active tree, give them to the ResourceProvider
@@ -216,6 +217,7 @@
 void DelegatedRendererLayerImpl::ReleaseResources() {
   ClearRenderPasses();
   ClearChildId();
+  have_render_passes_to_push_ = false;
 }
 
 static inline int IndexToId(int index) { return index + 1; }
diff --git a/cc/layers/picture_layer_impl_unittest.cc b/cc/layers/picture_layer_impl_unittest.cc
index 13d39ac..fb056aa 100644
--- a/cc/layers/picture_layer_impl_unittest.cc
+++ b/cc/layers/picture_layer_impl_unittest.cc
@@ -2443,9 +2443,9 @@
   // Gpu rasterization is disabled by default.
   EXPECT_FALSE(host_impl_.use_gpu_rasterization());
   // Toggling the gpu rasterization clears all tilings on both trees.
-  host_impl_.set_has_gpu_rasterization_trigger(true);
-  host_impl_.set_content_is_suitable_for_gpu_rasterization(true);
-  host_impl_.UpdateGpuRasterizationStatus();
+  host_impl_.SetHasGpuRasterizationTrigger(true);
+  host_impl_.SetContentIsSuitableForGpuRasterization(true);
+  host_impl_.UpdateTreeResourcesForGpuRasterizationIfNeeded();
   EXPECT_EQ(0u, pending_layer_->tilings()->num_tilings());
   EXPECT_EQ(0u, active_layer_->tilings()->num_tilings());
 
@@ -2466,16 +2466,15 @@
 
   // Toggling the gpu rasterization clears all tilings on both trees.
   EXPECT_TRUE(host_impl_.use_gpu_rasterization());
-  host_impl_.set_has_gpu_rasterization_trigger(false);
-  host_impl_.UpdateGpuRasterizationStatus();
+  host_impl_.SetHasGpuRasterizationTrigger(false);
+  host_impl_.UpdateTreeResourcesForGpuRasterizationIfNeeded();
   EXPECT_EQ(GpuRasterizationStatus::OFF_VIEWPORT,
             host_impl_.gpu_rasterization_status());
   EXPECT_EQ(0u, pending_layer_->tilings()->num_tilings());
   EXPECT_EQ(0u, active_layer_->tilings()->num_tilings());
 
-  host_impl_.set_has_gpu_rasterization_trigger(true);
-  host_impl_.set_content_is_suitable_for_gpu_rasterization(false);
-  host_impl_.UpdateGpuRasterizationStatus();
+  host_impl_.SetHasGpuRasterizationTrigger(true);
+  host_impl_.SetContentIsSuitableForGpuRasterization(false);
   EXPECT_EQ(GpuRasterizationStatus::OFF_CONTENT,
             host_impl_.gpu_rasterization_status());
 }
@@ -2521,8 +2520,7 @@
   gfx::Size layer_bounds(default_tile_size.width() * 4,
                          default_tile_size.height() * 4);
 
-  host_impl_.set_has_gpu_rasterization_trigger(false);
-  host_impl_.UpdateGpuRasterizationStatus();
+  host_impl_.SetHasGpuRasterizationTrigger(false);
 
   SetupDefaultTrees(layer_bounds);
   EXPECT_FALSE(host_impl_.use_gpu_rasterization());
@@ -2535,9 +2533,8 @@
   gfx::Size layer_bounds(default_tile_size.width() * 4,
                          default_tile_size.height() * 4);
 
-  host_impl_.set_has_gpu_rasterization_trigger(true);
-  host_impl_.set_content_is_suitable_for_gpu_rasterization(true);
-  host_impl_.UpdateGpuRasterizationStatus();
+  host_impl_.SetHasGpuRasterizationTrigger(true);
+  host_impl_.SetContentIsSuitableForGpuRasterization(true);
 
   SetupDefaultTrees(layer_bounds);
   EXPECT_TRUE(host_impl_.use_gpu_rasterization());
@@ -2546,9 +2543,8 @@
 }
 
 TEST_F(PictureLayerImplTest, RequiredTilesWithGpuRasterization) {
-  host_impl_.set_has_gpu_rasterization_trigger(true);
-  host_impl_.set_content_is_suitable_for_gpu_rasterization(true);
-  host_impl_.UpdateGpuRasterizationStatus();
+  host_impl_.SetHasGpuRasterizationTrigger(true);
+  host_impl_.SetContentIsSuitableForGpuRasterization(true);
 
   gfx::Size viewport_size(1000, 1000);
   host_impl_.SetViewportSize(viewport_size);
@@ -2848,9 +2844,9 @@
   gfx::Size viewport_size(1000, 1000);
   SetupDefaultTrees(layer_bounds);
   host_impl_.SetViewportSize(viewport_size);
-  host_impl_.set_has_gpu_rasterization_trigger(true);
-  host_impl_.set_content_is_suitable_for_gpu_rasterization(true);
-  host_impl_.UpdateGpuRasterizationStatus();
+  host_impl_.SetHasGpuRasterizationTrigger(true);
+  host_impl_.SetContentIsSuitableForGpuRasterization(true);
+  host_impl_.UpdateTreeResourcesForGpuRasterizationIfNeeded();
 
   float contents_scale = 1.f;
   float device_scale = 1.3f;
@@ -5042,9 +5038,8 @@
   host_impl_.SetViewportSize(gfx::Size(1000, 1000));
   gfx::Size result;
 
-  host_impl_.set_content_is_suitable_for_gpu_rasterization(true);
-  host_impl_.set_has_gpu_rasterization_trigger(false);
-  host_impl_.UpdateGpuRasterizationStatus();
+  host_impl_.SetContentIsSuitableForGpuRasterization(true);
+  host_impl_.SetHasGpuRasterizationTrigger(false);
   EXPECT_EQ(host_impl_.gpu_rasterization_status(),
             GpuRasterizationStatus::OFF_VIEWPORT);
 
@@ -5065,8 +5060,7 @@
 
   // Gpu-rasterization uses 25% viewport-height tiles.
   // The +2's below are for border texels.
-  host_impl_.set_has_gpu_rasterization_trigger(true);
-  host_impl_.UpdateGpuRasterizationStatus();
+  host_impl_.SetHasGpuRasterizationTrigger(true);
   EXPECT_EQ(host_impl_.gpu_rasterization_status(), GpuRasterizationStatus::ON);
   host_impl_.SetViewportSize(gfx::Size(2000, 2000));
 
diff --git a/cc/layers/surface_layer.cc b/cc/layers/surface_layer.cc
index 1a690b6e..67a26322 100644
--- a/cc/layers/surface_layer.cc
+++ b/cc/layers/surface_layer.cc
@@ -19,6 +19,7 @@
   ~SatisfySwapPromise() override {}
 
  private:
+  void DidActivate() override {}
   void DidSwap(CompositorFrameMetadata* metadata) override {
     metadata->satisfies_sequences.push_back(sequence_.sequence);
   }
diff --git a/cc/output/gl_renderer.cc b/cc/output/gl_renderer.cc
index bdb537a..93a4114 100644
--- a/cc/output/gl_renderer.cc
+++ b/cc/output/gl_renderer.cc
@@ -163,7 +163,13 @@
  public:
   static scoped_ptr<ScopedUseGrContext> Create(GLRenderer* renderer,
                                                DrawingFrame* frame) {
-    return make_scoped_ptr(new ScopedUseGrContext(renderer, frame));
+    // GrContext for filters is created lazily, and may fail if the context
+    // is lost.
+    // TODO(vmiura,bsalomon): crbug.com/487850 Ensure that
+    // ContextProvider::GrContext() does not return NULL.
+    if (renderer->output_surface_->context_provider()->GrContext())
+      return make_scoped_ptr(new ScopedUseGrContext(renderer, frame));
+    return nullptr;
   }
 
   ~ScopedUseGrContext() {
diff --git a/cc/output/latency_info_swap_promise.cc b/cc/output/latency_info_swap_promise.cc
index 3c07162..afc0f2d 100644
--- a/cc/output/latency_info_swap_promise.cc
+++ b/cc/output/latency_info_swap_promise.cc
@@ -10,7 +10,7 @@
 ui::LatencyComponentType DidNotSwapReasonToLatencyComponentType(
     cc::SwapPromise::DidNotSwapReason reason) {
   switch (reason) {
-    case cc::SwapPromise::DID_NOT_SWAP_UNKNOWN:
+    case cc::SwapPromise::ACTIVATION_FAILS:
     case cc::SwapPromise::SWAP_FAILS:
       return ui::INPUT_EVENT_LATENCY_TERMINATED_SWAP_FAILED_COMPONENT;
     case cc::SwapPromise::COMMIT_FAILS:
diff --git a/cc/output/latency_info_swap_promise.h b/cc/output/latency_info_swap_promise.h
index afd1633..74810b8 100644
--- a/cc/output/latency_info_swap_promise.h
+++ b/cc/output/latency_info_swap_promise.h
@@ -16,6 +16,7 @@
   explicit LatencyInfoSwapPromise(const ui::LatencyInfo& latency_info);
   ~LatencyInfoSwapPromise() override;
 
+  void DidActivate() override {}
   void DidSwap(CompositorFrameMetadata* metadata) override;
   void DidNotSwap(DidNotSwapReason reason) override;
 
diff --git a/cc/output/swap_promise.h b/cc/output/swap_promise.h
index 1d6dabcb..45deee8 100644
--- a/cc/output/swap_promise.h
+++ b/cc/output/swap_promise.h
@@ -15,30 +15,43 @@
 // completed in the compositor, i.e. the compositor knows it has been sent
 // to its output or not.
 //
-// If the new compositor state is sent to the output, SwapPromise::DidSwap()
-// will be called, and if the compositor fails to send its new state to the
-// output, SwapPromise::DidNotSwap() will be called.
+// If the commit results in a successful activation of the pending layer tree,
+// SwapPromise::DidActivate() will be called.
 //
-// Client wishes to use SwapPromise should have a subclass that defines
-// the behavior of DidSwap() and DidNotSwap(). Notice that the promise can
-// be broken at either main or impl thread, e.g. commit fails on main thread,
-// new frame data has no actual damage so LayerTreeHostImpl::SwapBuffers()
-// bails out early on impl thread, so don't assume that DidSwap() and
-// DidNotSwap() are called at a particular thread. It is better to let the
-// subclass carry thread-safe member data and operate on that member data in
-// DidSwap() and DidNotSwap().
+// If the new compositor state is sent to the output, SwapPromise::DidSwap()
+// will be called.
+//
+// If the scheduler fails to activate the pending tree, or the compositor
+// fails to send its new state to the output, SwapPromise::DidNotSwap() will
+// be called. Note that it is possible to activate, and subsequently not swap.
+//
+// Promises complete afer either DidSwap() or DidNotSwap() is called, thus
+// there are three possible call sequences:
+//   DidNotSwap()
+//   DidActivate() ; DidSwap()
+//   DidActivate() ; DidNotSwap()
+//
+// Clients that wish to use SwapPromise should have a subclass that defines
+// the behavior of DidActivate(), DidSwap() and DidNotSwap(). Notice that the
+// promise can be broken at either main or impl thread, e.g. commit fails on
+// main thread, new frame data has no actual damage so
+// LayerTreeHostImpl::SwapBuffers() bails out early on impl thread, so don't
+// assume that Did*() methods are called at a particular thread. It is better
+// to let the subclass carry thread-safe member data and operate on that
+// member data in Did*().
 class CC_EXPORT SwapPromise {
  public:
   enum DidNotSwapReason {
-    DID_NOT_SWAP_UNKNOWN,
     SWAP_FAILS,
     COMMIT_FAILS,
     COMMIT_NO_UPDATE,
+    ACTIVATION_FAILS,
   };
 
   SwapPromise() {}
   virtual ~SwapPromise() {}
 
+  virtual void DidActivate() = 0;
   virtual void DidSwap(CompositorFrameMetadata* metadata) = 0;
   virtual void DidNotSwap(DidNotSwapReason reason) = 0;
 
diff --git a/cc/resources/picture_layer_tiling.cc b/cc/resources/picture_layer_tiling.cc
index 70c4b11..b90d28d1 100644
--- a/cc/resources/picture_layer_tiling.cc
+++ b/cc/resources/picture_layer_tiling.cc
@@ -806,7 +806,9 @@
   tile->set_required_for_draw(IsTileRequiredForDraw(tile));
 }
 
-PrioritizedTile PictureLayerTiling::MakePrioritizedTile(Tile* tile) const {
+PrioritizedTile PictureLayerTiling::MakePrioritizedTile(
+    Tile* tile,
+    PriorityRectType priority_rect_type) const {
   DCHECK(tile);
   DCHECK(
       raster_source()->CoversRect(tile->content_rect(), tile->contents_scale()))
@@ -814,7 +816,8 @@
       << gfx::ScaleToEnclosingRect(tile->content_rect(),
                                    1.f / tile->contents_scale()).ToString();
 
-  return PrioritizedTile(tile, raster_source(), ComputePriorityForTile(tile),
+  return PrioritizedTile(tile, raster_source(),
+                         ComputePriorityForTile(tile, priority_rect_type),
                          IsTileOccluded(tile));
 }
 
@@ -822,53 +825,83 @@
 PictureLayerTiling::UpdateAndGetAllPrioritizedTilesForTesting() const {
   std::map<const Tile*, PrioritizedTile> result;
   for (const auto& key_tile_pair : tiles_) {
-    UpdateRequiredStatesOnTile(key_tile_pair.second);
+    Tile* tile = key_tile_pair.second;
+    UpdateRequiredStatesOnTile(tile);
     PrioritizedTile prioritized_tile =
-        MakePrioritizedTile(key_tile_pair.second);
+        MakePrioritizedTile(tile, ComputePriorityRectTypeForTile(tile));
     result.insert(std::make_pair(prioritized_tile.tile(), prioritized_tile));
   }
   return result;
 }
 
 TilePriority PictureLayerTiling::ComputePriorityForTile(
-    const Tile* tile) const {
+    const Tile* tile,
+    PriorityRectType priority_rect_type) const {
   // TODO(vmpstr): See if this can be moved to iterators.
   TilePriority::PriorityBin max_tile_priority_bin =
       client_->GetMaxTilePriorityBin();
 
+  DCHECK_EQ(ComputePriorityRectTypeForTile(tile), priority_rect_type);
   DCHECK_EQ(TileAt(tile->tiling_i_index(), tile->tiling_j_index()), tile);
+
+  TilePriority::PriorityBin priority_bin = max_tile_priority_bin;
+
+  switch (priority_rect_type) {
+    case VISIBLE_RECT:
+      return TilePriority(resolution_, priority_bin, 0);
+    case PENDING_VISIBLE_RECT:
+      if (max_tile_priority_bin <= TilePriority::SOON)
+        return TilePriority(resolution_, TilePriority::SOON, 0);
+      priority_bin = TilePriority::EVENTUALLY;
+      break;
+    case SKEWPORT_RECT:
+    case SOON_BORDER_RECT:
+      if (max_tile_priority_bin <= TilePriority::SOON)
+        priority_bin = TilePriority::SOON;
+      break;
+    case EVENTUALLY_RECT:
+      priority_bin = TilePriority::EVENTUALLY;
+      break;
+  }
+
   gfx::Rect tile_bounds =
       tiling_data_.TileBounds(tile->tiling_i_index(), tile->tiling_j_index());
-
-  if (max_tile_priority_bin <= TilePriority::NOW &&
-      current_visible_rect_.Intersects(tile_bounds)) {
-    return TilePriority(resolution_, TilePriority::NOW, 0);
-  }
-
-  if (max_tile_priority_bin <= TilePriority::SOON &&
-      pending_visible_rect().Intersects(tile_bounds)) {
-    return TilePriority(resolution_, TilePriority::SOON, 0);
-  }
-
   DCHECK_GT(current_content_to_screen_scale_, 0.f);
   float distance_to_visible =
       current_visible_rect_.ManhattanInternalDistance(tile_bounds) *
       current_content_to_screen_scale_;
 
-  if (max_tile_priority_bin <= TilePriority::SOON &&
-      (current_soon_border_rect_.Intersects(tile_bounds) ||
-       current_skewport_rect_.Intersects(tile_bounds))) {
-    return TilePriority(resolution_, TilePriority::SOON, distance_to_visible);
-  }
+  return TilePriority(resolution_, priority_bin, distance_to_visible);
+}
 
-  return TilePriority(resolution_, TilePriority::EVENTUALLY,
-                      distance_to_visible);
+PictureLayerTiling::PriorityRectType
+PictureLayerTiling::ComputePriorityRectTypeForTile(const Tile* tile) const {
+  DCHECK_EQ(TileAt(tile->tiling_i_index(), tile->tiling_j_index()), tile);
+  gfx::Rect tile_bounds =
+      tiling_data_.TileBounds(tile->tiling_i_index(), tile->tiling_j_index());
+
+  if (current_visible_rect_.Intersects(tile_bounds))
+    return VISIBLE_RECT;
+
+  if (pending_visible_rect().Intersects(tile_bounds))
+    return PENDING_VISIBLE_RECT;
+
+  if (current_skewport_rect_.Intersects(tile_bounds))
+    return SKEWPORT_RECT;
+
+  if (current_soon_border_rect_.Intersects(tile_bounds))
+    return SOON_BORDER_RECT;
+
+  DCHECK(current_eventually_rect_.Intersects(tile_bounds));
+  return EVENTUALLY_RECT;
 }
 
 void PictureLayerTiling::GetAllPrioritizedTilesForTracing(
     std::vector<PrioritizedTile>* prioritized_tiles) const {
   for (const auto& tile_pair : tiles_) {
-    prioritized_tiles->push_back(MakePrioritizedTile(tile_pair.second));
+    Tile* tile = tile_pair.second;
+    prioritized_tiles->push_back(
+        MakePrioritizedTile(tile, ComputePriorityRectTypeForTile(tile)));
   }
 }
 
diff --git a/cc/resources/picture_layer_tiling.h b/cc/resources/picture_layer_tiling.h
index 4a555a28..8ae68e1 100644
--- a/cc/resources/picture_layer_tiling.h
+++ b/cc/resources/picture_layer_tiling.h
@@ -212,6 +212,19 @@
   friend class TilingSetRasterQueueRequired;
   friend class TilingSetEvictionQueue;
 
+  // PENDING VISIBLE RECT refers to the visible rect that will become current
+  // upon activation (ie, the pending tree's visible rect). Tiles in this
+  // region that are not part of the current visible rect are all handled
+  // here. Note that when processing a pending tree, this rect is the same as
+  // the visible rect so no tiles are processed in this case.
+  enum PriorityRectType {
+    VISIBLE_RECT,
+    PENDING_VISIBLE_RECT,
+    SKEWPORT_RECT,
+    SOON_BORDER_RECT,
+    EVENTUALLY_RECT
+  };
+
   using TileMapKey = std::pair<int, int>;
   using TileMap = base::ScopedPtrHashMap<TileMapKey, ScopedTilePtr>;
 
@@ -272,8 +285,13 @@
   bool ShouldCreateTileAt(int i, int j) const;
   bool IsTileOccluded(const Tile* tile) const;
   void UpdateRequiredStatesOnTile(Tile* tile) const;
-  PrioritizedTile MakePrioritizedTile(Tile* tile) const;
-  TilePriority ComputePriorityForTile(const Tile* tile) const;
+  PrioritizedTile MakePrioritizedTile(
+      Tile* tile,
+      PriorityRectType priority_rect_type) const;
+  TilePriority ComputePriorityForTile(
+      const Tile* tile,
+      PriorityRectType priority_rect_type) const;
+  PriorityRectType ComputePriorityRectTypeForTile(const Tile* tile) const;
   bool has_visible_rect_tiles() const { return has_visible_rect_tiles_; }
   bool has_skewport_rect_tiles() const { return has_skewport_rect_tiles_; }
   bool has_soon_border_rect_tiles() const {
diff --git a/cc/resources/tiling_set_eviction_queue.cc b/cc/resources/tiling_set_eviction_queue.cc
index fde0a85a..f494da3 100644
--- a/cc/resources/tiling_set_eviction_queue.cc
+++ b/cc/resources/tiling_set_eviction_queue.cc
@@ -188,10 +188,10 @@
 TilingSetEvictionQueue::EvictionRectIterator::EvictionRectIterator(
     std::vector<PictureLayerTiling*>* tilings,
     WhichTree tree,
-    bool skip_pending_visible_rect)
+    PictureLayerTiling::PriorityRectType priority_rect_type)
     : tilings_(tilings),
       tree_(tree),
-      skip_pending_visible_rect_(skip_pending_visible_rect),
+      priority_rect_type_(priority_rect_type),
       tiling_index_(0) {
 }
 
@@ -219,12 +219,16 @@
   // If there's nothing to evict, return false.
   if (!tile || !tile->draw_info().has_resource())
     return false;
-  if (skip_pending_visible_rect_ &&
+  // After the pending visible rect has been processed, we must return false
+  // for pending visible rect tiles as tiling iterators do not ignore those
+  // tiles.
+  if (priority_rect_type_ > PictureLayerTiling::PENDING_VISIBLE_RECT &&
       tiling->pending_visible_rect().Intersects(tile->content_rect())) {
     return false;
   }
   (*tilings_)[tiling_index_]->UpdateRequiredStatesOnTile(tile);
-  prioritized_tile_ = (*tilings_)[tiling_index_]->MakePrioritizedTile(tile);
+  prioritized_tile_ = (*tilings_)[tiling_index_]->MakePrioritizedTile(
+      tile, priority_rect_type_);
   // In other cases, the tile we got is a viable candidate, return true.
   return true;
 }
@@ -233,9 +237,7 @@
 TilingSetEvictionQueue::EventuallyTilingIterator::EventuallyTilingIterator(
     std::vector<PictureLayerTiling*>* tilings,
     WhichTree tree)
-    : EvictionRectIterator(tilings,
-                           tree,
-                           true /* skip_pending_visible_rect */) {
+    : EvictionRectIterator(tilings, tree, PictureLayerTiling::EVENTUALLY_RECT) {
   // Find the first tiling with a tile.
   while (tiling_index_ < tilings_->size()) {
     if (!(*tilings_)[tiling_index_]->has_eventually_rect_tiles()) {
@@ -287,7 +289,7 @@
     WhichTree tree)
     : EvictionRectIterator(tilings,
                            tree,
-                           true /* skip_pending_visible_rect */) {
+                           PictureLayerTiling::SOON_BORDER_RECT) {
   // Find the first tiling with a tile.
   while (tiling_index_ < tilings_->size()) {
     if (!(*tilings_)[tiling_index_]->has_soon_border_rect_tiles()) {
@@ -337,9 +339,7 @@
 TilingSetEvictionQueue::SkewportTilingIterator::SkewportTilingIterator(
     std::vector<PictureLayerTiling*>* tilings,
     WhichTree tree)
-    : EvictionRectIterator(tilings,
-                           tree,
-                           true /* skip_pending_visible_rect */) {
+    : EvictionRectIterator(tilings, tree, PictureLayerTiling::SKEWPORT_RECT) {
   // Find the first tiling with a tile.
   while (tiling_index_ < tilings_->size()) {
     if (!(*tilings_)[tiling_index_]->has_skewport_rect_tiles()) {
@@ -392,7 +392,7 @@
                                  bool return_required_for_activation_tiles)
     : EvictionRectIterator(tilings,
                            tree,
-                           false /* skip_pending_visible_rect */),
+                           PictureLayerTiling::PENDING_VISIBLE_RECT),
       return_required_for_activation_tiles_(
           return_required_for_activation_tiles) {
   // Find the first tiling with a tile.
@@ -456,9 +456,7 @@
     WhichTree tree,
     bool return_occluded_tiles,
     bool return_required_for_activation_tiles)
-    : EvictionRectIterator(tilings,
-                           tree,
-                           false /* skip_pending_visible_rect */),
+    : EvictionRectIterator(tilings, tree, PictureLayerTiling::VISIBLE_RECT),
       return_occluded_tiles_(return_occluded_tiles),
       return_required_for_activation_tiles_(
           return_required_for_activation_tiles) {
diff --git a/cc/resources/tiling_set_eviction_queue.h b/cc/resources/tiling_set_eviction_queue.h
index f5e2c10..58e5a7d7 100644
--- a/cc/resources/tiling_set_eviction_queue.h
+++ b/cc/resources/tiling_set_eviction_queue.h
@@ -91,9 +91,10 @@
   class EvictionRectIterator {
    public:
     EvictionRectIterator();
-    EvictionRectIterator(std::vector<PictureLayerTiling*>* tilings,
-                         WhichTree tree,
-                         bool skip_pending_visible_rect);
+    EvictionRectIterator(
+        std::vector<PictureLayerTiling*>* tilings,
+        WhichTree tree,
+        PictureLayerTiling::PriorityRectType priority_rect_type);
 
     bool done() const { return !prioritized_tile_.tile(); }
     const PrioritizedTile& operator*() const { return prioritized_tile_; }
@@ -109,7 +110,7 @@
     PrioritizedTile prioritized_tile_;
     std::vector<PictureLayerTiling*>* tilings_;
     WhichTree tree_;
-    bool skip_pending_visible_rect_;
+    PictureLayerTiling::PriorityRectType priority_rect_type_;
     size_t tiling_index_;
   };
 
diff --git a/cc/resources/tiling_set_raster_queue_all.cc b/cc/resources/tiling_set_raster_queue_all.cc
index ba2f115..330f0883 100644
--- a/cc/resources/tiling_set_raster_queue_all.cc
+++ b/cc/resources/tiling_set_raster_queue_all.cc
@@ -148,24 +148,25 @@
 
 TilingSetRasterQueueAll::OnePriorityRectIterator::OnePriorityRectIterator(
     PictureLayerTiling* tiling,
-    TilingData* tiling_data)
-    : tiling_(tiling), tiling_data_(tiling_data) {
+    TilingData* tiling_data,
+    PictureLayerTiling::PriorityRectType priority_rect_type)
+    : tiling_(tiling),
+      tiling_data_(tiling_data),
+      priority_rect_type_(priority_rect_type) {
 }
 
 template <typename TilingIteratorType>
 void TilingSetRasterQueueAll::OnePriorityRectIterator::AdvanceToNextTile(
     TilingIteratorType* iterator) {
-  current_tile_ = PrioritizedTile();
-  Tile* tile = nullptr;
-  while (!tile || !TileNeedsRaster(tile)) {
+  bool found_tile = false;
+  while (!found_tile) {
     ++(*iterator);
     if (!(*iterator)) {
-      return;
+      current_tile_ = PrioritizedTile();
+      break;
     }
-    tile = tiling_->TileAt(iterator->index_x(), iterator->index_y());
+    found_tile = GetFirstTileAndCheckIfValid(iterator);
   }
-  tiling_->UpdateRequiredStatesOnTile(tile);
-  current_tile_ = tiling_->MakePrioritizedTile(tile);
 }
 
 template <typename TilingIteratorType>
@@ -176,8 +177,16 @@
     current_tile_ = PrioritizedTile();
     return false;
   }
+  // After the pending visible rect has been processed, we must return false
+  // for pending visible rect tiles as tiling iterators do not ignore those
+  // tiles.
+  if (priority_rect_type_ > PictureLayerTiling::PENDING_VISIBLE_RECT &&
+      tiling_->pending_visible_rect().Intersects(tile->content_rect())) {
+    current_tile_ = PrioritizedTile();
+    return false;
+  }
   tiling_->UpdateRequiredStatesOnTile(tile);
-  current_tile_ = tiling_->MakePrioritizedTile(tile);
+  current_tile_ = tiling_->MakePrioritizedTile(tile, priority_rect_type_);
   return true;
 }
 
@@ -185,7 +194,9 @@
 TilingSetRasterQueueAll::VisibleTilingIterator::VisibleTilingIterator(
     PictureLayerTiling* tiling,
     TilingData* tiling_data)
-    : OnePriorityRectIterator(tiling, tiling_data) {
+    : OnePriorityRectIterator(tiling,
+                              tiling_data,
+                              PictureLayerTiling::VISIBLE_RECT) {
   if (!tiling_->has_visible_rect_tiles())
     return;
   iterator_ =
@@ -208,7 +219,9 @@
 TilingSetRasterQueueAll::PendingVisibleTilingIterator::
     PendingVisibleTilingIterator(PictureLayerTiling* tiling,
                                  TilingData* tiling_data)
-    : OnePriorityRectIterator(tiling, tiling_data) {
+    : OnePriorityRectIterator(tiling,
+                              tiling_data,
+                              PictureLayerTiling::PENDING_VISIBLE_RECT) {
   iterator_ = TilingData::DifferenceIterator(tiling_data_,
                                              tiling_->pending_visible_rect(),
                                              tiling_->current_visible_rect());
@@ -229,7 +242,9 @@
 TilingSetRasterQueueAll::SkewportTilingIterator::SkewportTilingIterator(
     PictureLayerTiling* tiling,
     TilingData* tiling_data)
-    : OnePriorityRectIterator(tiling, tiling_data),
+    : OnePriorityRectIterator(tiling,
+                              tiling_data,
+                              PictureLayerTiling::SKEWPORT_RECT),
       pending_visible_rect_(tiling->pending_visible_rect()) {
   if (!tiling_->has_skewport_rect_tiles())
     return;
@@ -242,6 +257,8 @@
     ++(*this);
     return;
   }
+  // TODO(e_hakkinen): This is not needed as GetFirstTileAndCheckIfValid
+  // does the same checking.
   if (current_tile_.tile()->content_rect().Intersects(pending_visible_rect_))
     ++(*this);
 }
@@ -250,6 +267,8 @@
     TilingSetRasterQueueAll::SkewportTilingIterator::
     operator++() {
   AdvanceToNextTile(&iterator_);
+  // TODO(e_hakkinen): This is not needed as GetFirstTileAndCheckIfValid called
+  // by AdvanceToNextTile does the same checking.
   while (!done()) {
     if (!current_tile_.tile()->content_rect().Intersects(pending_visible_rect_))
       break;
@@ -262,7 +281,9 @@
 TilingSetRasterQueueAll::SoonBorderTilingIterator::SoonBorderTilingIterator(
     PictureLayerTiling* tiling,
     TilingData* tiling_data)
-    : OnePriorityRectIterator(tiling, tiling_data),
+    : OnePriorityRectIterator(tiling,
+                              tiling_data,
+                              PictureLayerTiling::SOON_BORDER_RECT),
       pending_visible_rect_(tiling->pending_visible_rect()) {
   if (!tiling_->has_soon_border_rect_tiles())
     return;
@@ -275,6 +296,8 @@
     ++(*this);
     return;
   }
+  // TODO(e_hakkinen): This is not needed as GetFirstTileAndCheckIfValid
+  // does the same checking.
   if (current_tile_.tile()->content_rect().Intersects(pending_visible_rect_))
     ++(*this);
 }
@@ -283,6 +306,8 @@
     TilingSetRasterQueueAll::SoonBorderTilingIterator::
     operator++() {
   AdvanceToNextTile(&iterator_);
+  // TODO(e_hakkinen): This is not needed as GetFirstTileAndCheckIfValid called
+  // by AdvanceToNextTile does the same checking.
   while (!done()) {
     if (!current_tile_.tile()->content_rect().Intersects(pending_visible_rect_))
       break;
@@ -295,7 +320,9 @@
 TilingSetRasterQueueAll::EventuallyTilingIterator::EventuallyTilingIterator(
     PictureLayerTiling* tiling,
     TilingData* tiling_data)
-    : OnePriorityRectIterator(tiling, tiling_data),
+    : OnePriorityRectIterator(tiling,
+                              tiling_data,
+                              PictureLayerTiling::EVENTUALLY_RECT),
       pending_visible_rect_(tiling->pending_visible_rect()) {
   if (!tiling_->has_eventually_rect_tiles())
     return;
@@ -308,6 +335,8 @@
     ++(*this);
     return;
   }
+  // TODO(e_hakkinen): This is not needed as GetFirstTileAndCheckIfValid
+  // does the same checking.
   if (current_tile_.tile()->content_rect().Intersects(pending_visible_rect_))
     ++(*this);
 }
@@ -316,6 +345,8 @@
     TilingSetRasterQueueAll::EventuallyTilingIterator::
     operator++() {
   AdvanceToNextTile(&iterator_);
+  // TODO(e_hakkinen): This is not needed as GetFirstTileAndCheckIfValid called
+  // by AdvanceToNextTile does the same checking.
   while (!done()) {
     if (!current_tile_.tile()->content_rect().Intersects(pending_visible_rect_))
       break;
@@ -331,7 +362,7 @@
 TilingSetRasterQueueAll::TilingIterator::TilingIterator(
     PictureLayerTiling* tiling,
     TilingData* tiling_data)
-    : tiling_(tiling), tiling_data_(tiling_data), phase_(VISIBLE_RECT) {
+    : tiling_(tiling), tiling_data_(tiling_data), phase_(Phase::VISIBLE_RECT) {
   visible_iterator_ = VisibleTilingIterator(tiling_, tiling_data_);
   if (visible_iterator_.done()) {
     AdvancePhase();
@@ -344,32 +375,32 @@
 }
 
 void TilingSetRasterQueueAll::TilingIterator::AdvancePhase() {
-  DCHECK_LT(phase_, EVENTUALLY_RECT);
+  DCHECK_LT(phase_, Phase::EVENTUALLY_RECT);
 
   current_tile_ = PrioritizedTile();
-  while (!current_tile_.tile() && phase_ < EVENTUALLY_RECT) {
+  while (!current_tile_.tile() && phase_ < Phase::EVENTUALLY_RECT) {
     phase_ = static_cast<Phase>(phase_ + 1);
     switch (phase_) {
-      case VISIBLE_RECT:
+      case Phase::VISIBLE_RECT:
         NOTREACHED();
         return;
-      case PENDING_VISIBLE_RECT:
+      case Phase::PENDING_VISIBLE_RECT:
         pending_visible_iterator_ =
             PendingVisibleTilingIterator(tiling_, tiling_data_);
         if (!pending_visible_iterator_.done())
           current_tile_ = *pending_visible_iterator_;
         break;
-      case SKEWPORT_RECT:
+      case Phase::SKEWPORT_RECT:
         skewport_iterator_ = SkewportTilingIterator(tiling_, tiling_data_);
         if (!skewport_iterator_.done())
           current_tile_ = *skewport_iterator_;
         break;
-      case SOON_BORDER_RECT:
+      case Phase::SOON_BORDER_RECT:
         soon_border_iterator_ = SoonBorderTilingIterator(tiling_, tiling_data_);
         if (!soon_border_iterator_.done())
           current_tile_ = *soon_border_iterator_;
         break;
-      case EVENTUALLY_RECT:
+      case Phase::EVENTUALLY_RECT:
         eventually_iterator_ = EventuallyTilingIterator(tiling_, tiling_data_);
         if (!eventually_iterator_.done())
           current_tile_ = *eventually_iterator_;
@@ -382,7 +413,7 @@
     TilingSetRasterQueueAll::TilingIterator::
     operator++() {
   switch (phase_) {
-    case VISIBLE_RECT:
+    case Phase::VISIBLE_RECT:
       ++visible_iterator_;
       if (visible_iterator_.done()) {
         AdvancePhase();
@@ -390,7 +421,7 @@
       }
       current_tile_ = *visible_iterator_;
       break;
-    case PENDING_VISIBLE_RECT:
+    case Phase::PENDING_VISIBLE_RECT:
       ++pending_visible_iterator_;
       if (pending_visible_iterator_.done()) {
         AdvancePhase();
@@ -398,7 +429,7 @@
       }
       current_tile_ = *pending_visible_iterator_;
       break;
-    case SKEWPORT_RECT:
+    case Phase::SKEWPORT_RECT:
       ++skewport_iterator_;
       if (skewport_iterator_.done()) {
         AdvancePhase();
@@ -406,7 +437,7 @@
       }
       current_tile_ = *skewport_iterator_;
       break;
-    case SOON_BORDER_RECT:
+    case Phase::SOON_BORDER_RECT:
       ++soon_border_iterator_;
       if (soon_border_iterator_.done()) {
         AdvancePhase();
@@ -414,7 +445,7 @@
       }
       current_tile_ = *soon_border_iterator_;
       break;
-    case EVENTUALLY_RECT:
+    case Phase::EVENTUALLY_RECT:
       ++eventually_iterator_;
       if (eventually_iterator_.done()) {
         current_tile_ = PrioritizedTile();
diff --git a/cc/resources/tiling_set_raster_queue_all.h b/cc/resources/tiling_set_raster_queue_all.h
index dd3a7a8..8c8b012 100644
--- a/cc/resources/tiling_set_raster_queue_all.h
+++ b/cc/resources/tiling_set_raster_queue_all.h
@@ -31,8 +31,10 @@
   class OnePriorityRectIterator {
    public:
     OnePriorityRectIterator();
-    OnePriorityRectIterator(PictureLayerTiling* tiling,
-                            TilingData* tiling_data);
+    OnePriorityRectIterator(
+        PictureLayerTiling* tiling,
+        TilingData* tiling_data,
+        PictureLayerTiling::PriorityRectType priority_rect_type);
 
     bool done() const { return !current_tile_.tile(); }
     const PrioritizedTile& operator*() const { return current_tile_; }
@@ -51,6 +53,7 @@
     PrioritizedTile current_tile_;
     PictureLayerTiling* tiling_;
     TilingData* tiling_data_;
+    PictureLayerTiling::PriorityRectType priority_rect_type_;
   };
 
   // Iterates over visible rect only, left to right top to bottom order.
@@ -131,13 +134,13 @@
     const PrioritizedTile& operator*() const { return current_tile_; }
     TilePriority::PriorityBin type() const {
       switch (phase_) {
-        case VISIBLE_RECT:
+        case Phase::VISIBLE_RECT:
           return TilePriority::NOW;
-        case PENDING_VISIBLE_RECT:
-        case SKEWPORT_RECT:
-        case SOON_BORDER_RECT:
+        case Phase::PENDING_VISIBLE_RECT:
+        case Phase::SKEWPORT_RECT:
+        case Phase::SOON_BORDER_RECT:
           return TilePriority::SOON;
-        case EVENTUALLY_RECT:
+        case Phase::EVENTUALLY_RECT:
           return TilePriority::EVENTUALLY;
       }
       NOTREACHED();
@@ -147,18 +150,7 @@
     TilingIterator& operator++();
 
    private:
-    // PENDING VISIBLE RECT refers to the visible rect that will become current
-    // upon activation (ie, the pending tree's visible rect). Tiles in this
-    // region that are not part of the current visible rect are all handled
-    // here. Note that when processing a pending tree, this rect is the same as
-    // the visible rect so no tiles are processed in this case.
-    enum Phase {
-      VISIBLE_RECT,
-      PENDING_VISIBLE_RECT,
-      SKEWPORT_RECT,
-      SOON_BORDER_RECT,
-      EVENTUALLY_RECT
-    };
+    using Phase = PictureLayerTiling::PriorityRectType;
 
     void AdvancePhase();
 
diff --git a/cc/resources/tiling_set_raster_queue_required.cc b/cc/resources/tiling_set_raster_queue_required.cc
index 19c2c814..f95cd42 100644
--- a/cc/resources/tiling_set_raster_queue_required.cc
+++ b/cc/resources/tiling_set_raster_queue_required.cc
@@ -104,7 +104,8 @@
   if (tile && tile->draw_info().NeedsRaster() &&
       !tiling_->IsTileOccluded(tile)) {
     tiling_->UpdateRequiredStatesOnTile(tile);
-    current_tile_ = tiling_->MakePrioritizedTile(tile);
+    current_tile_ = tiling_->MakePrioritizedTile(
+        tile, tiling_->ComputePriorityRectTypeForTile(tile));
     return;
   }
   ++(*this);
@@ -143,7 +144,8 @@
   }
 
   tiling_->UpdateRequiredStatesOnTile(tile);
-  current_tile_ = tiling_->MakePrioritizedTile(tile);
+  current_tile_ = tiling_->MakePrioritizedTile(
+      tile, tiling_->ComputePriorityRectTypeForTile(tile));
   return *this;
 }
 
diff --git a/cc/test/fake_output_surface.h b/cc/test/fake_output_surface.h
index 6028cad..7041a44 100644
--- a/cc/test/fake_output_surface.h
+++ b/cc/test/fake_output_surface.h
@@ -29,7 +29,8 @@
 
   static scoped_ptr<FakeOutputSurface> Create3d(
       scoped_refptr<ContextProvider> context_provider) {
-    return make_scoped_ptr(new FakeOutputSurface(context_provider, false));
+    return make_scoped_ptr(new FakeOutputSurface(
+        context_provider, TestContextProvider::Create(), false));
   }
 
   static scoped_ptr<FakeOutputSurface> Create3d(
@@ -41,8 +42,9 @@
 
   static scoped_ptr<FakeOutputSurface> Create3d(
       scoped_ptr<TestWebGraphicsContext3D> context) {
-    return make_scoped_ptr(new FakeOutputSurface(
-        TestContextProvider::Create(context.Pass()), false));
+    return make_scoped_ptr(
+        new FakeOutputSurface(TestContextProvider::Create(context.Pass()),
+                              TestContextProvider::Create(), false));
   }
 
   static scoped_ptr<FakeOutputSurface> CreateSoftware(
diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc
index 45ecee4..6c4696e 100644
--- a/cc/trees/layer_tree_host.cc
+++ b/cc/trees/layer_tree_host.cc
@@ -330,8 +330,8 @@
   sync_tree->set_top_controls_height(top_controls_height_);
   sync_tree->PushTopControlsFromMainThread(top_controls_shown_ratio_);
 
-  host_impl->set_has_gpu_rasterization_trigger(has_gpu_rasterization_trigger_);
-  host_impl->set_content_is_suitable_for_gpu_rasterization(
+  host_impl->SetHasGpuRasterizationTrigger(has_gpu_rasterization_trigger_);
+  host_impl->SetContentIsSuitableForGpuRasterization(
       content_is_suitable_for_gpu_rasterization_);
   RecordGpuRasterizationHistogram();
 
@@ -434,8 +434,8 @@
       settings_, client, proxy_.get(), rendering_stats_instrumentation_.get(),
       shared_bitmap_manager_, gpu_memory_buffer_manager_, task_graph_runner_,
       id_);
-  host_impl->set_has_gpu_rasterization_trigger(has_gpu_rasterization_trigger_);
-  host_impl->set_content_is_suitable_for_gpu_rasterization(
+  host_impl->SetHasGpuRasterizationTrigger(has_gpu_rasterization_trigger_);
+  host_impl->SetContentIsSuitableForGpuRasterization(
       content_is_suitable_for_gpu_rasterization_);
   shared_bitmap_manager_ = NULL;
   gpu_memory_buffer_manager_ = NULL;
@@ -1279,8 +1279,8 @@
 }
 
 void LayerTreeHost::BreakSwapPromises(SwapPromise::DidNotSwapReason reason) {
-  for (size_t i = 0; i < swap_promise_list_.size(); i++)
-    swap_promise_list_[i]->DidNotSwap(reason);
+  for (auto* swap_promise : swap_promise_list_)
+    swap_promise->DidNotSwap(reason);
   swap_promise_list_.clear();
 }
 
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index 6125337..d421f84b 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -195,6 +195,7 @@
       use_gpu_rasterization_(false),
       use_msaa_(false),
       gpu_rasterization_status_(GpuRasterizationStatus::OFF_DEVICE),
+      tree_resources_for_gpu_rasterization_dirty_(false),
       input_handler_client_(NULL),
       did_lock_scrolling_layer_(false),
       should_bubble_scrolls_(false),
@@ -308,7 +309,9 @@
 void LayerTreeHostImpl::CommitComplete() {
   TRACE_EVENT0("cc", "LayerTreeHostImpl::CommitComplete");
 
-  UpdateGpuRasterizationStatus();
+  // LayerTreeHost may have changed the GPU rasterization flags state, which
+  // may require an update of the tree resources.
+  UpdateTreeResourcesForGpuRasterizationIfNeeded();
   sync_tree()->set_needs_update_draw_properties();
 
   if (settings_.impl_side_painting) {
@@ -1584,6 +1587,20 @@
     renderer_->Finish();
 }
 
+bool LayerTreeHostImpl::CanUseGpuRasterization() {
+  if (!(output_surface_ && output_surface_->context_provider() &&
+        output_surface_->worker_context_provider()))
+    return false;
+
+  ContextProvider* context_provider =
+      output_surface_->worker_context_provider();
+  base::AutoLock context_lock(*context_provider->GetLock());
+  if (!context_provider->GrContext())
+    return false;
+
+  return true;
+}
+
 void LayerTreeHostImpl::UpdateGpuRasterizationStatus() {
   bool use_gpu = false;
   bool use_msaa = false;
@@ -1613,6 +1630,17 @@
     gpu_rasterization_status_ = GpuRasterizationStatus::OFF_CONTENT;
   }
 
+  if (use_gpu && !use_gpu_rasterization_) {
+    if (!CanUseGpuRasterization()) {
+      // If GPU rasterization is unusable, e.g. if GlContext could not
+      // be created due to losing the GL context, force use of software
+      // raster.
+      use_gpu = false;
+      use_msaa = false;
+      gpu_rasterization_status_ = GpuRasterizationStatus::OFF_DEVICE;
+    }
+  }
+
   if (use_gpu == use_gpu_rasterization_ && use_msaa == use_msaa_)
     return;
 
@@ -1621,6 +1649,13 @@
   use_gpu_rasterization_ = use_gpu;
   use_msaa_ = use_msaa;
 
+  tree_resources_for_gpu_rasterization_dirty_ = true;
+}
+
+void LayerTreeHostImpl::UpdateTreeResourcesForGpuRasterizationIfNeeded() {
+  if (!tree_resources_for_gpu_rasterization_dirty_)
+    return;
+
   // Clean up and replace existing tile manager with another one that uses
   // appropriate rasterizer.
   ReleaseTreeResources();
@@ -1634,6 +1669,8 @@
   // We would not have any content to draw until the pending tree is activated.
   // Prevent the active tree from drawing until activation.
   SetRequiresHighResToDraw();
+
+  tree_resources_for_gpu_rasterization_dirty_ = false;
 }
 
 const RendererCapabilitiesImpl&
@@ -1990,8 +2027,6 @@
   }
   DCHECK(renderer_);
 
-  // Since the new renderer may be capable of MSAA, update status here.
-  UpdateGpuRasterizationStatus();
   renderer_->SetVisible(visible_);
   SetFullRootLayerDamage();
 
@@ -2176,6 +2211,9 @@
 
   CreateAndSetRenderer();
 
+  // Since the new renderer may be capable of MSAA, update status here.
+  UpdateGpuRasterizationStatus();
+
   if (settings_.impl_side_painting && settings_.raster_enabled)
     CreateAndSetTileManager();
   RecreateTreeResources();
@@ -3086,7 +3124,7 @@
   if (active_tree_->root_layer()) {
     scoped_ptr<base::Value> json(active_tree_->root_layer()->LayerTreeAsJson());
     base::JSONWriter::WriteWithOptions(
-        json.get(), base::JSONWriter::OPTIONS_PRETTY_PRINT, &str);
+        *json, base::JSONWriter::OPTIONS_PRETTY_PRINT, &str);
   }
   return str;
 }
diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h
index 54776e7..82955d4e 100644
--- a/cc/trees/layer_tree_host_impl.h
+++ b/cc/trees/layer_tree_host_impl.h
@@ -321,13 +321,16 @@
   virtual bool InitializeRenderer(scoped_ptr<OutputSurface> output_surface);
   TileManager* tile_manager() { return tile_manager_.get(); }
 
-  void set_has_gpu_rasterization_trigger(bool flag) {
+  void SetHasGpuRasterizationTrigger(bool flag) {
     has_gpu_rasterization_trigger_ = flag;
+    UpdateGpuRasterizationStatus();
   }
-  void set_content_is_suitable_for_gpu_rasterization(bool flag) {
+  void SetContentIsSuitableForGpuRasterization(bool flag) {
     content_is_suitable_for_gpu_rasterization_ = flag;
+    UpdateGpuRasterizationStatus();
   }
-  void UpdateGpuRasterizationStatus();
+  bool CanUseGpuRasterization();
+  void UpdateTreeResourcesForGpuRasterizationIfNeeded();
   bool use_gpu_rasterization() const { return use_gpu_rasterization_; }
   bool use_msaa() const { return use_msaa_; }
 
@@ -571,6 +574,8 @@
   void ReleaseTreeResources();
   void RecreateTreeResources();
 
+  void UpdateGpuRasterizationStatus();
+
   bool IsSynchronousSingleThreaded() const;
 
   Viewport* viewport() { return viewport_.get(); }
@@ -646,6 +651,7 @@
   bool use_gpu_rasterization_;
   bool use_msaa_;
   GpuRasterizationStatus gpu_rasterization_status_;
+  bool tree_resources_for_gpu_rasterization_dirty_;
   scoped_ptr<TileTaskWorkerPool> tile_task_worker_pool_;
   scoped_ptr<ResourcePool> resource_pool_;
   scoped_ptr<ResourcePool> staging_resource_pool_;
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
index cc239da..15994ef9 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -5931,11 +5931,9 @@
   // when visible.
   LayerTreeSettings settings;
   settings.gpu_rasterization_enabled = true;
-  host_impl_ = LayerTreeHostImpl::Create(
-      settings, this, &proxy_, &stats_instrumentation_, NULL, NULL, NULL, 0);
-  host_impl_->set_content_is_suitable_for_gpu_rasterization(true);
-  host_impl_->set_has_gpu_rasterization_trigger(true);
-  host_impl_->UpdateGpuRasterizationStatus();
+  CreateHostImpl(settings, CreateOutputSurface());
+  host_impl_->SetContentIsSuitableForGpuRasterization(true);
+  host_impl_->SetHasGpuRasterizationTrigger(true);
   host_impl_->SetVisible(true);
   host_impl_->SetMemoryPolicy(policy1);
   EXPECT_EQ(policy1.bytes_limit_when_visible, current_limit_bytes_);
@@ -5977,22 +5975,22 @@
 
   host_impl_->ResetRequiresHighResToDraw();
 
-  host_impl_->set_content_is_suitable_for_gpu_rasterization(true);
-  host_impl_->set_has_gpu_rasterization_trigger(false);
-  host_impl_->UpdateGpuRasterizationStatus();
+  host_impl_->SetContentIsSuitableForGpuRasterization(true);
+  host_impl_->SetHasGpuRasterizationTrigger(false);
+  host_impl_->UpdateTreeResourcesForGpuRasterizationIfNeeded();
   EXPECT_FALSE(host_impl_->RequiresHighResToDraw());
-  host_impl_->set_has_gpu_rasterization_trigger(true);
-  host_impl_->UpdateGpuRasterizationStatus();
+  host_impl_->SetHasGpuRasterizationTrigger(true);
+  host_impl_->UpdateTreeResourcesForGpuRasterizationIfNeeded();
   EXPECT_TRUE(host_impl_->RequiresHighResToDraw());
-  host_impl_->set_has_gpu_rasterization_trigger(false);
-  host_impl_->UpdateGpuRasterizationStatus();
+  host_impl_->SetHasGpuRasterizationTrigger(false);
+  host_impl_->UpdateTreeResourcesForGpuRasterizationIfNeeded();
   EXPECT_TRUE(host_impl_->RequiresHighResToDraw());
 
   host_impl_->ResetRequiresHighResToDraw();
 
   EXPECT_FALSE(host_impl_->RequiresHighResToDraw());
-  host_impl_->set_has_gpu_rasterization_trigger(true);
-  host_impl_->UpdateGpuRasterizationStatus();
+  host_impl_->SetHasGpuRasterizationTrigger(true);
+  host_impl_->UpdateTreeResourcesForGpuRasterizationIfNeeded();
   EXPECT_TRUE(host_impl_->RequiresHighResToDraw());
 }
 
@@ -7727,22 +7725,19 @@
 TEST_F(LayerTreeHostImplTest, GpuRasterizationStatusModes) {
   EXPECT_FALSE(host_impl_->use_gpu_rasterization());
 
-  host_impl_->set_has_gpu_rasterization_trigger(true);
-  host_impl_->set_content_is_suitable_for_gpu_rasterization(true);
-  host_impl_->UpdateGpuRasterizationStatus();
+  host_impl_->SetHasGpuRasterizationTrigger(true);
+  host_impl_->SetContentIsSuitableForGpuRasterization(true);
   EXPECT_EQ(GpuRasterizationStatus::ON, host_impl_->gpu_rasterization_status());
   EXPECT_TRUE(host_impl_->use_gpu_rasterization());
 
-  host_impl_->set_has_gpu_rasterization_trigger(false);
-  host_impl_->set_content_is_suitable_for_gpu_rasterization(true);
-  host_impl_->UpdateGpuRasterizationStatus();
+  host_impl_->SetHasGpuRasterizationTrigger(false);
+  host_impl_->SetContentIsSuitableForGpuRasterization(true);
   EXPECT_EQ(GpuRasterizationStatus::OFF_VIEWPORT,
             host_impl_->gpu_rasterization_status());
   EXPECT_FALSE(host_impl_->use_gpu_rasterization());
 
-  host_impl_->set_has_gpu_rasterization_trigger(true);
-  host_impl_->set_content_is_suitable_for_gpu_rasterization(false);
-  host_impl_->UpdateGpuRasterizationStatus();
+  host_impl_->SetHasGpuRasterizationTrigger(true);
+  host_impl_->SetContentIsSuitableForGpuRasterization(false);
   EXPECT_EQ(GpuRasterizationStatus::OFF_CONTENT,
             host_impl_->gpu_rasterization_status());
   EXPECT_FALSE(host_impl_->use_gpu_rasterization());
@@ -7756,9 +7751,8 @@
   msaaSettings.gpu_rasterization_msaa_sample_count = 4;
   EXPECT_TRUE(CreateHostImpl(
       msaaSettings, FakeOutputSurface::Create3d(context_with_msaa.Pass())));
-  host_impl_->set_has_gpu_rasterization_trigger(true);
-  host_impl_->set_content_is_suitable_for_gpu_rasterization(false);
-  host_impl_->UpdateGpuRasterizationStatus();
+  host_impl_->SetHasGpuRasterizationTrigger(true);
+  host_impl_->SetContentIsSuitableForGpuRasterization(false);
   EXPECT_EQ(GpuRasterizationStatus::MSAA_CONTENT,
             host_impl_->gpu_rasterization_status());
   EXPECT_TRUE(host_impl_->use_gpu_rasterization());
@@ -7767,9 +7761,8 @@
   LayerTreeSettings settings = DefaultSettings();
   settings.gpu_rasterization_enabled = false;
   EXPECT_TRUE(CreateHostImpl(settings, FakeOutputSurface::Create3d()));
-  host_impl_->set_has_gpu_rasterization_trigger(true);
-  host_impl_->set_content_is_suitable_for_gpu_rasterization(true);
-  host_impl_->UpdateGpuRasterizationStatus();
+  host_impl_->SetHasGpuRasterizationTrigger(true);
+  host_impl_->SetContentIsSuitableForGpuRasterization(true);
   EXPECT_EQ(GpuRasterizationStatus::OFF_DEVICE,
             host_impl_->gpu_rasterization_status());
   EXPECT_FALSE(host_impl_->use_gpu_rasterization());
@@ -7777,9 +7770,8 @@
   settings.gpu_rasterization_forced = true;
   EXPECT_TRUE(CreateHostImpl(settings, FakeOutputSurface::Create3d()));
 
-  host_impl_->set_has_gpu_rasterization_trigger(false);
-  host_impl_->set_content_is_suitable_for_gpu_rasterization(false);
-  host_impl_->UpdateGpuRasterizationStatus();
+  host_impl_->SetHasGpuRasterizationTrigger(false);
+  host_impl_->SetContentIsSuitableForGpuRasterization(false);
   EXPECT_EQ(GpuRasterizationStatus::ON_FORCED,
             host_impl_->gpu_rasterization_status());
   EXPECT_TRUE(host_impl_->use_gpu_rasterization());
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc
index 51ea3d9..98ac5a1 100644
--- a/cc/trees/layer_tree_host_unittest.cc
+++ b/cc/trees/layer_tree_host_unittest.cc
@@ -4927,11 +4927,13 @@
 
 struct TestSwapPromiseResult {
   TestSwapPromiseResult()
-      : did_swap_called(false),
+      : did_activate_called(false),
+        did_swap_called(false),
         did_not_swap_called(false),
         dtor_called(false),
-        reason(SwapPromise::DID_NOT_SWAP_UNKNOWN) {}
+        reason(SwapPromise::COMMIT_FAILS) {}
 
+  bool did_activate_called;
   bool did_swap_called;
   bool did_not_swap_called;
   bool dtor_called;
@@ -4948,8 +4950,17 @@
     result_->dtor_called = true;
   }
 
+  void DidActivate() override {
+    base::AutoLock lock(result_->lock);
+    EXPECT_FALSE(result_->did_activate_called);
+    EXPECT_FALSE(result_->did_swap_called);
+    EXPECT_FALSE(result_->did_not_swap_called);
+    result_->did_activate_called = true;
+  }
+
   void DidSwap(CompositorFrameMetadata* metadata) override {
     base::AutoLock lock(result_->lock);
+    EXPECT_TRUE(result_->did_activate_called);
     EXPECT_FALSE(result_->did_swap_called);
     EXPECT_FALSE(result_->did_not_swap_called);
     result_->did_swap_called = true;
@@ -4959,6 +4970,8 @@
     base::AutoLock lock(result_->lock);
     EXPECT_FALSE(result_->did_swap_called);
     EXPECT_FALSE(result_->did_not_swap_called);
+    EXPECT_FALSE(result_->did_activate_called &&
+                 reason != DidNotSwapReason::SWAP_FAILS);
     result_->did_not_swap_called = true;
     result_->reason = reason;
   }
@@ -4992,6 +5005,22 @@
     }
   }
 
+  void WillActivateTreeOnThread(LayerTreeHostImpl* host_impl) override {
+    if (host_impl->pending_tree()) {
+      int frame = host_impl->pending_tree()->source_frame_number();
+      base::AutoLock lock(swap_promise_result_[frame].lock);
+      EXPECT_FALSE(swap_promise_result_[frame].did_activate_called);
+      EXPECT_FALSE(swap_promise_result_[frame].did_swap_called);
+    }
+  }
+
+  void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override {
+    int frame = host_impl->active_tree()->source_frame_number();
+    base::AutoLock lock(swap_promise_result_[frame].lock);
+    EXPECT_TRUE(swap_promise_result_[frame].did_activate_called);
+    EXPECT_FALSE(swap_promise_result_[frame].did_swap_called);
+  }
+
   void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override {
     commit_complete_count_++;
     if (commit_complete_count_ == 1) {
@@ -5019,6 +5048,7 @@
     {
       // The second commit is aborted since it contains no updates.
       base::AutoLock lock(swap_promise_result_[1].lock);
+      EXPECT_FALSE(swap_promise_result_[1].did_activate_called);
       EXPECT_FALSE(swap_promise_result_[1].did_swap_called);
       EXPECT_TRUE(swap_promise_result_[1].did_not_swap_called);
       EXPECT_EQ(SwapPromise::COMMIT_NO_UPDATE, swap_promise_result_[1].reason);
@@ -5029,6 +5059,7 @@
       // The last commit completes but it does not cause swap buffer because
       // there is no damage in the frame data.
       base::AutoLock lock(swap_promise_result_[2].lock);
+      EXPECT_TRUE(swap_promise_result_[2].did_activate_called);
       EXPECT_FALSE(swap_promise_result_[2].did_swap_called);
       EXPECT_TRUE(swap_promise_result_[2].did_not_swap_called);
       EXPECT_EQ(SwapPromise::SWAP_FAILS, swap_promise_result_[2].reason);
@@ -5078,6 +5109,41 @@
     }
   }
 
+  void WillActivateTreeOnThread(LayerTreeHostImpl* host_impl) override {
+    if (host_impl->pending_tree()) {
+      if (host_impl->pending_tree()->source_frame_number() == 1) {
+        base::AutoLock lock(swap_promise_result_.lock);
+        EXPECT_FALSE(swap_promise_result_.did_activate_called);
+        EXPECT_FALSE(swap_promise_result_.did_swap_called);
+        SetCallback(true);
+      } else {
+        SetCallback(false);
+      }
+    }
+  }
+
+  void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override {
+    if (host_impl->active_tree()->source_frame_number() == 1) {
+      base::AutoLock lock(swap_promise_result_.lock);
+      EXPECT_TRUE(swap_promise_result_.did_activate_called);
+      EXPECT_FALSE(swap_promise_result_.did_swap_called);
+    }
+  }
+
+  void ActivationCallback() {
+    // DidActivate needs to happen before the tree activation callback.
+    base::AutoLock lock(swap_promise_result_.lock);
+    EXPECT_TRUE(swap_promise_result_.did_activate_called);
+  }
+
+  void SetCallback(bool enable) {
+    output_surface()->SetTreeActivationCallback(
+        enable
+            ? base::Bind(&LayerTreeHostTestKeepSwapPromise::ActivationCallback,
+                         base::Unretained(this))
+            : base::Closure());
+  }
+
   void SwapBuffersOnThread(LayerTreeHostImpl* host_impl, bool result) override {
     EXPECT_TRUE(result);
     if (host_impl->active_tree()->source_frame_number() >= 1) {
@@ -5127,6 +5193,7 @@
   void AfterTest() override {
     {
       base::AutoLock lock(swap_promise_result_.lock);
+      EXPECT_FALSE(swap_promise_result_.did_activate_called);
       EXPECT_FALSE(swap_promise_result_.did_swap_called);
       EXPECT_TRUE(swap_promise_result_.did_not_swap_called);
       EXPECT_EQ(SwapPromise::COMMIT_FAILS, swap_promise_result_.reason);
@@ -5176,6 +5243,7 @@
   void AfterTest() override {
     {
       base::AutoLock lock(swap_promise_result_.lock);
+      EXPECT_FALSE(swap_promise_result_.did_activate_called);
       EXPECT_FALSE(swap_promise_result_.did_swap_called);
       EXPECT_TRUE(swap_promise_result_.did_not_swap_called);
       EXPECT_EQ(SwapPromise::COMMIT_FAILS, swap_promise_result_.reason);
@@ -5829,6 +5897,7 @@
     // Second swap promise fails to swap.
     {
       base::AutoLock lock(swap_promise_result_[1].lock);
+      EXPECT_TRUE(swap_promise_result_[1].did_activate_called);
       EXPECT_FALSE(swap_promise_result_[1].did_swap_called);
       EXPECT_TRUE(swap_promise_result_[1].did_not_swap_called);
       EXPECT_EQ(SwapPromise::SWAP_FAILS, swap_promise_result_[1].reason);
@@ -5838,6 +5907,7 @@
     // Third swap promises also fails to swap (and draw).
     {
       base::AutoLock lock(swap_promise_result_[2].lock);
+      EXPECT_TRUE(swap_promise_result_[2].did_activate_called);
       EXPECT_FALSE(swap_promise_result_[2].did_swap_called);
       EXPECT_TRUE(swap_promise_result_[2].did_not_swap_called);
       EXPECT_EQ(SwapPromise::SWAP_FAILS, swap_promise_result_[2].reason);
diff --git a/cc/trees/layer_tree_host_unittest_delegated.cc b/cc/trees/layer_tree_host_unittest_delegated.cc
index 6d0fb0a..2864eb8 100644
--- a/cc/trees/layer_tree_host_unittest_delegated.cc
+++ b/cc/trees/layer_tree_host_unittest_delegated.cc
@@ -404,6 +404,37 @@
 
 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostDelegatedTestCreateChildId);
 
+class LayerTreeHostDelegatedTestDontUseLostChildIdAfterCommit
+    : public LayerTreeHostDelegatedTestCaseSingleDelegatedLayer {
+ protected:
+  void BeginTest() override {
+    SetFrameData(CreateFrameData(gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1)));
+    LayerTreeHostDelegatedTestCaseSingleDelegatedLayer::BeginTest();
+  }
+
+  void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override {
+    // Act like the context was lost while the layer is in the pending tree.
+    LayerImpl* root_impl = host_impl->sync_tree()->root_layer();
+    FakeDelegatedRendererLayerImpl* delegated_impl =
+        static_cast<FakeDelegatedRendererLayerImpl*>(root_impl->children()[0]);
+    delegated_impl->ReleaseResources();
+  }
+
+  void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override {
+    LayerImpl* root_impl = host_impl->active_tree()->root_layer();
+    FakeDelegatedRendererLayerImpl* delegated_impl =
+        static_cast<FakeDelegatedRendererLayerImpl*>(root_impl->children()[0]);
+
+    // Should not try to activate a frame without a child id. If we did try to
+    // activate we would crash.
+    EXPECT_FALSE(delegated_impl->ChildId());
+    EndTest();
+  }
+};
+
+MULTI_THREAD_IMPL_TEST_F(
+    LayerTreeHostDelegatedTestDontUseLostChildIdAfterCommit);
+
 // Test that we can gracefully handle invalid frames after the context was lost.
 // For example, we might be trying to use the previous frame in that case and
 // have to make sure we don't crash because our resource accounting goes wrong.
diff --git a/cc/trees/layer_tree_impl.cc b/cc/trees/layer_tree_impl.cc
index 276885914..01a4cfd 100644
--- a/cc/trees/layer_tree_impl.cc
+++ b/cc/trees/layer_tree_impl.cc
@@ -70,7 +70,8 @@
 }
 
 LayerTreeImpl::~LayerTreeImpl() {
-  BreakSwapPromises(SwapPromise::SWAP_FAILS);
+  BreakSwapPromises(IsActiveTree() ? SwapPromise::SWAP_FAILS
+                                   : SwapPromise::ACTIVATION_FAILS);
 
   // Need to explicitly clear the tree prior to destroying this so that
   // the LayerTreeImpl pointer is still valid in the LayerImpl dtor.
@@ -744,6 +745,8 @@
         root_layer(), [](LayerImpl* layer) { layer->DidBecomeActive(); });
   }
 
+  for (auto* swap_promise : swap_promise_list_)
+    swap_promise->DidActivate();
   devtools_instrumentation::DidActivateLayerTree(layer_tree_host_impl_->id(),
                                                  source_frame_number_);
 }
@@ -990,8 +993,8 @@
   state->EndArray();
 
   state->BeginArray("swap_promise_trace_ids");
-  for (size_t i = 0; i < swap_promise_list_.size(); i++)
-    state->AppendDouble(swap_promise_list_[i]->TraceId());
+  for (auto* swap_promise : swap_promise_list_)
+    state->AppendDouble(swap_promise->TraceId());
   state->EndArray();
 }
 
@@ -1072,20 +1075,20 @@
 
 void LayerTreeImpl::PassSwapPromises(
     ScopedPtrVector<SwapPromise>* new_swap_promise) {
-  swap_promise_list_.insert_and_take(swap_promise_list_.end(),
-                                     new_swap_promise);
-  new_swap_promise->clear();
+  // Any left over promises have failed to swap before the next frame.
+  BreakSwapPromises(SwapPromise::SWAP_FAILS);
+  swap_promise_list_.swap(*new_swap_promise);
 }
 
 void LayerTreeImpl::FinishSwapPromises(CompositorFrameMetadata* metadata) {
-  for (size_t i = 0; i < swap_promise_list_.size(); i++)
-    swap_promise_list_[i]->DidSwap(metadata);
+  for (auto* swap_promise : swap_promise_list_)
+    swap_promise->DidSwap(metadata);
   swap_promise_list_.clear();
 }
 
 void LayerTreeImpl::BreakSwapPromises(SwapPromise::DidNotSwapReason reason) {
-  for (size_t i = 0; i < swap_promise_list_.size(); i++)
-    swap_promise_list_[i]->DidNotSwap(reason);
+  for (auto* swap_promise : swap_promise_list_)
+    swap_promise->DidNotSwap(reason);
   swap_promise_list_.clear();
 }
 
diff --git a/chrome/VERSION b/chrome/VERSION
index d58fd78..53df3fab 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
-MAJOR=44
+MAJOR=45
 MINOR=0
-BUILD=2403
+BUILD=2405
 PATCH=0
diff --git a/chrome/android/java/res/menu/chrome_context_menu.xml b/chrome/android/java/res/menu/chrome_context_menu.xml
index c7256088..83bb617 100644
--- a/chrome/android/java/res/menu/chrome_context_menu.xml
+++ b/chrome/android/java/res/menu/chrome_context_menu.xml
@@ -20,6 +20,8 @@
             android:title="@string/contextmenu_save_link" />
     </group>
     <group android:id="@+id/contextmenu_group_image">
+        <item android:id="@+id/contextmenu_show_original_image"
+            android:title="@string/contextmenu_show_original_image"/>
         <item android:id="@+id/contextmenu_save_image"
             android:title="@string/contextmenu_save_image"/>
         <item android:id="@+id/contextmenu_open_image"
diff --git a/chrome/android/java/res/values/values.xml b/chrome/android/java/res/values/values.xml
index 6e3b4343..f6049288 100644
--- a/chrome/android/java/res/values/values.xml
+++ b/chrome/android/java/res/values/values.xml
@@ -11,7 +11,7 @@
     <item type="id" name="button_secondary" />
     <item type="id" name="button_tertiary" />
     <item type="id" name="infobar_extra_check" />
-    
+
     <!-- Menu Animation Constants -->
     <item type="fraction" format="fraction" name="menu_animation_pivot_x">95%</item>
 
@@ -41,5 +41,8 @@
 
     <!-- Cast notification -->
     <item type="id" name="remote_notification" />
-    
+
+    <!-- Sync UI constants -->
+    <item type="id" name="passphrase_type_list" />
+
 </resources>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/PasswordUIView.java b/chrome/android/java/src/org/chromium/chrome/browser/PasswordUIView.java
index c1eb3f0..adfb14f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/PasswordUIView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/PasswordUIView.java
@@ -146,6 +146,10 @@
         return nativeShouldDisplayManageAccountLink();
     }
 
+    public static boolean shouldUseSmartLockBranding() {
+        return nativeShouldUseSmartLockBranding();
+    }
+
     /**
      * Destroy the native object.
      */
@@ -180,6 +184,8 @@
 
     private static native boolean nativeShouldDisplayManageAccountLink();
 
+    private static native boolean nativeShouldUseSmartLockBranding();
+
     private native void nativeDestroy(long nativePasswordUIViewAndroid);
 
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/Tab.java b/chrome/android/java/src/org/chromium/chrome/browser/Tab.java
index e1875cf..41e3958 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/Tab.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/Tab.java
@@ -342,6 +342,11 @@
         }
 
         @Override
+        public void onShowOriginalImage() {
+            if (mNativeTabAndroid != 0) nativeShowOriginalImage(mNativeTabAndroid);
+        }
+
+        @Override
         public String getPageUrl() {
             return getUrl();
         }
@@ -2769,6 +2774,7 @@
     private native void nativeCreateHistoricalTab(long nativeTabAndroid);
     private native void nativeUpdateTopControlsState(
             long nativeTabAndroid, int constraints, int current, boolean animate);
+    private native void nativeShowOriginalImage(long nativeTabAndroid);
     private native void nativeSearchByImageInNewTabAsync(long nativeTabAndroid);
     private native long nativeGetBookmarkId(long nativeTabAndroid, boolean onlyEditable);
     private native void nativeSetInterceptNavigationDelegate(long nativeTabAndroid,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/WebsiteSettingsPopup.java b/chrome/android/java/src/org/chromium/chrome/browser/WebsiteSettingsPopup.java
index 806cb94..9d37ff6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/WebsiteSettingsPopup.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/WebsiteSettingsPopup.java
@@ -381,7 +381,7 @@
 
         SpannableStringBuilder urlBuilder = new SpannableStringBuilder(mFullUrl);
         OmniboxUrlEmphasizer.emphasizeUrl(urlBuilder, mContext.getResources(), mProfile,
-                mSecurityLevel, mIsInternalPage, true);
+                mSecurityLevel, mIsInternalPage, true, true);
         mUrlTitle.setText(urlBuilder);
 
         // Set the URL connection message now, and the URL after layout (so it
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuItemDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuItemDelegate.java
index 96d88b7b..3544fb0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuItemDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuItemDelegate.java
@@ -63,6 +63,11 @@
     void onOpenImageInNewTab(String url, Referrer referrer);
 
     /**
+     * Called when the original image should be shown.
+     */
+    void onShowOriginalImage();
+
+    /**
      * Called when the {@code text} should be saved to the clipboard.
      * @param text  The text to save to the clipboard.
      * @param isUrl Whether or not the text is a URL.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulator.java b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulator.java
index ab25498..7c02f17 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulator.java
@@ -41,6 +41,8 @@
     public void buildContextMenu(ContextMenu menu, Context context, ContextMenuParams params) {
         if (!TextUtils.isEmpty(params.getLinkUrl()) && !params.getLinkUrl().equals(BLANK_URL)) {
             menu.setHeaderTitle(params.getLinkUrl());
+        } else if (!TextUtils.isEmpty(params.getTitleText())) {
+            menu.setHeaderTitle(params.getTitleText());
         }
 
         if (mMenuInflater == null) mMenuInflater = new MenuInflater(context);
@@ -81,6 +83,10 @@
                 menu.findItem(R.id.contextmenu_open_original_image_in_new_tab).setVisible(false);
             }
 
+            if (!params.imageWasFetchedLoFi()) {
+                menu.findItem(R.id.contextmenu_show_original_image).setVisible(false);
+            }
+
             // Avoid showing open image option for same image which is already opened.
             if (mDelegate.getPageUrl().equals(params.getSrcUrl())) {
                 menu.findItem(R.id.contextmenu_open_image).setVisible(false);
@@ -114,6 +120,8 @@
         } else if (itemId == R.id.contextmenu_open_image_in_new_tab
                 || itemId == R.id.contextmenu_open_original_image_in_new_tab) {
             mDelegate.onOpenImageInNewTab(params.getSrcUrl(), params.getReferrer());
+        } else if (itemId == R.id.contextmenu_show_original_image) {
+            mDelegate.onShowOriginalImage();
         } else if (itemId == R.id.contextmenu_copy_link_address_text) {
             mDelegate.onSaveToClipboard(params.getUnfilteredLinkUrl(), true);
         } else if (itemId == R.id.contextmenu_copy_email_address) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuParams.java b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuParams.java
index 861cd9b..71d168f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuParams.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuParams.java
@@ -42,8 +42,10 @@
     private final String mPageUrl;
     private final String mLinkUrl;
     private final String mLinkText;
+    private final String mTitleText;
     private final String mUnfilteredLinkUrl;
     private final String mSrcUrl;
+    private final boolean mImageWasFetchedLoFi;
     private final boolean mIsEditable;
     private final Referrer mReferrer;
 
@@ -110,6 +112,13 @@
     }
 
     /**
+     * @return The title or alt attribute (if title is not available).
+     */
+    public String getTitleText() {
+        return mTitleText;
+    }
+
+    /**
      * @return The unfiltered link URL, if any.
      */
     public String getUnfilteredLinkUrl() {
@@ -124,6 +133,13 @@
     }
 
     /**
+     * @return Whether or not an image was fetched using Lo-Fi.
+     */
+    public boolean imageWasFetchedLoFi() {
+        return mImageWasFetchedLoFi;
+    }
+
+    /**
      * @return Whether or not the context menu is being shown for an editable piece of content.
      */
     public boolean isEditable() {
@@ -166,13 +182,15 @@
     }
 
     private ContextMenuParams(int mediaType, String pageUrl, String linkUrl, String linkText,
-            String unfilteredLinkUrl, String srcUrl, String selectionText, boolean isEditable,
-            Referrer referrer) {
+            String unfilteredLinkUrl, String srcUrl, String selectionText, String titleText,
+            boolean imageWasFetchedLoFi, boolean isEditable, Referrer referrer) {
         mPageUrl = pageUrl;
         mLinkUrl = linkUrl;
         mLinkText = linkText;
+        mTitleText = titleText;
         mUnfilteredLinkUrl = unfilteredLinkUrl;
         mSrcUrl = srcUrl;
+        mImageWasFetchedLoFi = imageWasFetchedLoFi;
         mIsEditable = isEditable;
         mReferrer = referrer;
 
@@ -185,11 +203,12 @@
     @CalledByNative
     private static ContextMenuParams create(int mediaType, String pageUrl, String linkUrl,
             String linkText, String unfilteredLinkUrl, String srcUrl, String selectionText,
-            boolean isEditable, String sanitizedReferrer, int referrerPolicy) {
+            String titleText, boolean imageWasFetchedLoFi, boolean isEditable,
+            String sanitizedReferrer, int referrerPolicy) {
         Referrer referrer = TextUtils.isEmpty(sanitizedReferrer)
                 ? null : new Referrer(sanitizedReferrer, referrerPolicy);
         return new ContextMenuParams(mediaType, pageUrl, linkUrl, linkText, unfilteredLinkUrl,
-                srcUrl, selectionText, isEditable, referrer);
+                srcUrl, selectionText, titleText, imageWasFetchedLoFi, isEditable, referrer);
     }
 
     @CalledByNative
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/EmptyChromeContextMenuItemDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/EmptyChromeContextMenuItemDelegate.java
index 26ec1ab3..d8b01ce 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/EmptyChromeContextMenuItemDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/EmptyChromeContextMenuItemDelegate.java
@@ -36,6 +36,10 @@
     }
 
     @Override
+    public void onShowOriginalImage() {
+    }
+
+    @Override
     public void onOpenInNewIncognitoTab(String url) {
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/feedback/ConnectivityChecker.java b/chrome/android/java/src/org/chromium/chrome/browser/feedback/ConnectivityChecker.java
index 4c370f84..2af5bd9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/feedback/ConnectivityChecker.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/feedback/ConnectivityChecker.java
@@ -4,18 +4,31 @@
 
 package org.chromium.chrome.browser.feedback;
 
+import android.os.AsyncTask;
+
 import org.chromium.base.CalledByNative;
 import org.chromium.base.JNINamespace;
+import org.chromium.base.Log;
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.VisibleForTesting;
 import org.chromium.chrome.browser.profiles.Profile;
 
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+
 /**
  * A utility class for checking if the device is currently connected to the Internet.
  */
 @JNINamespace("chrome::android")
 public final class ConnectivityChecker {
-    private static final String DEFAULT_NO_CONTENT_URL = "http://clients4.google.com/generate_204";
+    private static final String TAG = "ConnectivityChecker";
+
+    private static final String DEFAULT_HTTP_NO_CONTENT_URL =
+            "http://clients4.google.com/generate_204";
+    private static final String DEFAULT_HTTPS_NO_CONTENT_URL =
+            "https://clients4.google.com/generate_204";
 
     /**
      * A callback for whether the device is currently connected to the Internet.
@@ -29,8 +42,69 @@
 
     /**
      * Starts an asynchronous request for checking whether the device is currently connected to the
-     * Internet. The result passed to the callback denotes whether the attempt to connect to the
-     * server was successful.
+     * Internet using the Android system network stack. The result passed to the callback denotes
+     * whether the attempt to connect to the server was successful.
+     *
+     * If the profile or URL is invalid, the callback will be called with false.
+     * The server reply for the URL must respond with HTTP 204 without any redirects for the
+     * connectivity check to be successful.
+     *
+     * This method takes ownership of the callback object until the callback has happened.
+     * This method must be called on the main thread.
+     * @param timeoutMs number of milliseconds to wait before giving up waiting for a connection.
+     * @param callback the callback which will get the result.
+     */
+    public static void checkConnectivitySystemNetworkStack(
+            boolean useHttps, int timeoutMs, final ConnectivityCheckerCallback callback) {
+        try {
+            URL url = useHttps ? new URL(DEFAULT_HTTPS_NO_CONTENT_URL)
+                               : new URL(DEFAULT_HTTP_NO_CONTENT_URL);
+            checkConnectivitySystemNetworkStack(url, timeoutMs, callback);
+        } catch (MalformedURLException e) {
+            Log.w(TAG, "Failed to predefined URL: " + e);
+            ThreadUtils.postOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    callback.onResult(false);
+                }
+            });
+        }
+    }
+
+    static void checkConnectivitySystemNetworkStack(
+            final URL url, final int timeoutMs, final ConnectivityCheckerCallback callback) {
+        new AsyncTask<String, Void, Boolean>() {
+            @Override
+            protected Boolean doInBackground(String... strings) {
+                try {
+                    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
+                    conn.setInstanceFollowRedirects(false);
+                    conn.setRequestMethod("GET");
+                    conn.setDoInput(false);
+                    conn.setDoOutput(false);
+                    conn.setConnectTimeout(timeoutMs);
+                    conn.setReadTimeout(timeoutMs);
+
+                    conn.connect();
+                    int responseCode = conn.getResponseCode();
+                    return responseCode == HttpURLConnection.HTTP_NO_CONTENT;
+                } catch (IOException e) {
+                    return false;
+                }
+            }
+
+            @Override
+            protected void onPostExecute(Boolean connected) {
+                callback.onResult(connected);
+            }
+        }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+    }
+
+    /**
+     * Starts an asynchronous request for checking whether the device is currently connected to the
+     * Internet using the Chrome network stack. The result passed to the callback denotes whether
+     *the
+     * attempt to connect to the server was successful.
      *
      * If the profile or URL is invalid, the callback will be called with false.
      * The server reply for the URL must respond with HTTP 204 without any redirects for the
@@ -42,13 +116,14 @@
      * @param timeoutMs number of milliseconds to wait before giving up waiting for a connection.
      * @param callback the callback which will get the result.
      */
-    public static void checkConnectivity(
-            Profile profile, long timeoutMs, ConnectivityCheckerCallback callback) {
-        checkConnectivity(profile, DEFAULT_NO_CONTENT_URL, timeoutMs, callback);
+    public static void checkConnectivityChromeNetworkStack(Profile profile, boolean useHttps,
+            long timeoutMs, ConnectivityCheckerCallback callback) {
+        String url = useHttps ? DEFAULT_HTTPS_NO_CONTENT_URL : DEFAULT_HTTP_NO_CONTENT_URL;
+        checkConnectivityChromeNetworkStack(profile, url, timeoutMs, callback);
     }
 
     @VisibleForTesting
-    static void checkConnectivity(
+    static void checkConnectivityChromeNetworkStack(
             Profile profile, String url, long timeoutMs, ConnectivityCheckerCallback callback) {
         ThreadUtils.assertOnUiThread();
         nativeCheckConnectivity(profile, url, timeoutMs, callback);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/AppBannerInfoBarDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/AppBannerInfoBarDelegate.java
index c76db8c5..686fe8f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/AppBannerInfoBarDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/AppBannerInfoBarDelegate.java
@@ -14,6 +14,7 @@
 import org.chromium.base.ApplicationStatus;
 import org.chromium.base.CalledByNative;
 import org.chromium.base.JNINamespace;
+import org.chromium.base.VisibleForTesting;
 import org.chromium.chrome.browser.Tab;
 import org.chromium.chrome.browser.banners.AppData;
 import org.chromium.chrome.browser.banners.InstallerDelegate;
@@ -25,6 +26,9 @@
  */
 @JNINamespace("banners")
 public class AppBannerInfoBarDelegate {
+    /** PackageManager to use in place of the real one. */
+    private static PackageManager sPackageManagerForTests;
+
     /** Weak pointer to the native AppBannerInfoBarDelegate. */
     private long mNativePointer;
 
@@ -34,6 +38,12 @@
     /** Monitors for application state changes. */
     private final ApplicationStatus.ApplicationStateListener mListener;
 
+    /** Overrides the PackageManager for testing. */
+    @VisibleForTesting
+    public static void setPackageManagerForTesting(PackageManager manager) {
+        sPackageManagerForTests = manager;
+    }
+
     private AppBannerInfoBarDelegate(long nativePtr) {
         mNativePointer = nativePtr;
         mListener = createApplicationStateListener();
@@ -64,7 +74,7 @@
     private boolean installOrOpenNativeApp(Tab tab, AppData appData) {
         Context context = ApplicationStatus.getApplicationContext();
         String packageName = appData.packageName();
-        PackageManager packageManager = context.getPackageManager();
+        PackageManager packageManager = getPackageManager(context);
 
         if (InstallerDelegate.isInstalled(packageManager, packageName)) {
             // Open the app.
@@ -89,7 +99,7 @@
                 if (isInstalling) {
                     // Start monitoring the install.
                     PackageManager pm =
-                            ApplicationStatus.getApplicationContext().getPackageManager();
+                            getPackageManager(ApplicationStatus.getApplicationContext());
                     mInstallTask = new InstallerDelegate(
                             Looper.getMainLooper(), pm, createInstallerDelegateObserver(),
                             appData.packageName());
@@ -121,12 +131,17 @@
     private int determineInstallState(AppData data) {
         if (mInstallTask != null) return AppBannerInfoBar.INSTALL_STATE_INSTALLING;
 
-        PackageManager pm = ApplicationStatus.getApplicationContext().getPackageManager();
+        PackageManager pm = getPackageManager(ApplicationStatus.getApplicationContext());
         boolean isInstalled = InstallerDelegate.isInstalled(pm, data.packageName());
         return isInstalled ? AppBannerInfoBar.INSTALL_STATE_INSTALLED
                 : AppBannerInfoBar.INSTALL_STATE_NOT_INSTALLED;
     }
 
+    private PackageManager getPackageManager(Context context) {
+        if (sPackageManagerForTests != null) return sPackageManagerForTests;
+        return context.getPackageManager();
+    }
+
     @CalledByNative
     private static AppBannerInfoBarDelegate create(long nativePtr) {
         return new AppBannerInfoBarDelegate(nativePtr);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/OmniboxUrlEmphasizer.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/OmniboxUrlEmphasizer.java
index 9cf8e69..cfbffe0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/OmniboxUrlEmphasizer.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/OmniboxUrlEmphasizer.java
@@ -140,9 +140,15 @@
      * @param isInternalPage Whether this page is an internal Chrome page.
      * @param useDarkColors Whether the text colors should be dark (i.e.
      *                      appropriate for use on a light background).
+     * @param emphasizeHttpsScheme Whether the https scheme should be emphasized.
      */
     public static void emphasizeUrl(Spannable url, Resources resources, Profile profile,
-            int securityLevel, boolean isInternalPage, boolean useDarkColors) {
+            int securityLevel, boolean isInternalPage,
+            boolean useDarkColors, boolean emphasizeHttpsScheme) {
+        assert (securityLevel == ConnectionSecurityHelperSecurityLevel.SECURITY_ERROR
+                || securityLevel == ConnectionSecurityHelperSecurityLevel.SECURITY_WARNING)
+                ? emphasizeHttpsScheme : true;
+
         String urlString = url.toString();
 
         EmphasizeComponentsResponse emphasizeResponse =
@@ -163,10 +169,7 @@
         ForegroundColorSpan span;
         if (emphasizeResponse.hasScheme()) {
             int colorId = nonEmphasizedColorId;
-            if (!isInternalPage
-                    && (useDarkColors
-                               || securityLevel
-                                       == ConnectionSecurityHelperSecurityLevel.SECURITY_ERROR)) {
+            if (!isInternalPage && emphasizeHttpsScheme) {
                 switch (securityLevel) {
                     case ConnectionSecurityHelperSecurityLevel.NONE:
                         colorId = nonEmphasizedColorId;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/ManageSavedPasswordsPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/ManageSavedPasswordsPreferences.java
index 61da69c..863c9c7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/ManageSavedPasswordsPreferences.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/ManageSavedPasswordsPreferences.java
@@ -76,7 +76,11 @@
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        getActivity().setTitle(R.string.prefs_saved_passwords);
+        if (PasswordUIView.shouldUseSmartLockBranding()) {
+            getActivity().setTitle(R.string.prefs_smart_lock_for_passwords);
+        } else {
+            getActivity().setTitle(R.string.prefs_saved_passwords);
+        }
         setPreferenceScreen(getPreferenceManager().createPreferenceScreen(getActivity()));
         mPasswordManagerHandler.addObserver(this);
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/ui/PassphraseTypeDialogFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/sync/ui/PassphraseTypeDialogFragment.java
index 76f95f8..ce293ab4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/sync/ui/PassphraseTypeDialogFragment.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sync/ui/PassphraseTypeDialogFragment.java
@@ -31,6 +31,7 @@
  */
 public class PassphraseTypeDialogFragment extends DialogFragment implements
         DialogInterface.OnClickListener, OnItemClickListener {
+    private static final String TAG = "PassphraseTypeDialogFragment";
 
     interface Listener {
         void onPassphraseTypeSelected(PassphraseType type);
@@ -96,7 +97,11 @@
         return new Adapter(container, container.getDisplayNames());
     }
 
-    private class Adapter extends ArrayAdapter<String> {
+    /**
+     * The adapter for our ListView; only visible for testing purposes.
+     */
+    @VisibleForTesting
+    public class Adapter extends ArrayAdapter<String> {
 
         private final PassphraseTypeUiElementContainer mElementsContainer;
 
@@ -176,6 +181,7 @@
         ListView list = new ListView(getActivity());
         Adapter adapter = createAdapter(getCurrentTypeFromArguments());
         list.setAdapter(adapter);
+        list.setId(R.id.passphrase_type_list);
         list.setOnItemClickListener(this);
         list.setDividerHeight(0);
         PassphraseType currentType = getCurrentTypeFromArguments();
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd
index 95ec26b..f114c86 100644
--- a/chrome/android/java/strings/android_chrome_strings.grd
+++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -235,7 +235,10 @@
       <message name="IDS_PREFS_SAVED_PASSWORDS" desc="Title for the Saved Passwords preferences. [CHAR-LIMIT=32]">
         Save passwords
       </message>
-     <message name="IDS_PASSWORDS_AUTO_SIGNIN_TITLE" desc="Title for checkbox to enable automatically signing the user in to websites">
+      <message name="IDS_PREFS_SMART_LOCK_FOR_PASSWORDS" desc="The brand name of the password manager to be displayed in preferences instead of the title 'Save Passwords' when a user is signed in. [CHAR-LIMIT=32]">
+        Smart Lock for Passwords
+      </message>
+      <message name="IDS_PASSWORDS_AUTO_SIGNIN_TITLE" desc="Title for checkbox to enable automatically signing the user in to websites">
         Auto Sign-in
       </message>
       <message name="IDS_PASSWORDS_AUTO_SIGNIN_DESCRIPTION" desc="Text under 'Auto sign-in' checkbox">
@@ -248,7 +251,7 @@
         Never saved
       </message>
       <message name="IDS_MANAGE_PASSWORDS_TEXT" desc="Text for link to manage passwords on Account Central.">
-        Manage saved passwords in your <ph name="BEGIN_LINK">&lt;link&gt;</ph>Google Account<ph name="END_LINK">&lt;/link&gt;</ph>
+        View and manage saved passwords at <ph name="BEGIN_LINK">&lt;link&gt;</ph>passwords.google.com<ph name="END_LINK">&lt;/link&gt;</ph>
       </message>
       <message name="IDS_SAVED_PASSWORDS_NONE_TEXT" desc="Text when there are no saved passwords/exceptions.">
         Saved passwords will appear here.
@@ -1147,6 +1150,9 @@
       <message name="IDS_CONTEXTMENU_OPEN_ORIGINAL_IMAGE_IN_NEW_TAB" desc="Context sensitive menu item for opening/viewing the original version of the selected image in a new tab. [CHAR-LIMIT=30]">
         Open original image in new tab
       </message>
+      <message name="IDS_CONTEXTMENU_SHOW_ORIGINAL_IMAGE" desc="Context sensitive menu item for Data Saver low fidelity placeholder images that shows the original version in place. [CHAR-LIMIT=30]">
+        Show image
+      </message>
       <message name="IDS_CONTEXTMENU_SEARCH_WEB_FOR_IMAGE" desc="Context sensitive menu item for search-for-Image command in a new tab. [CHAR-LIMIT=30]">
         Search <ph name="SEARCH_ENGINE">%1$s<ex>Google</ex></ph> for this image
       </message>
diff --git a/chrome/android/javatests_shell/src/org/chromium/chrome/browser/banners/AppBannerManagerTest.java b/chrome/android/javatests_shell/src/org/chromium/chrome/browser/banners/AppBannerManagerTest.java
index 538c34bd..6107c0b6 100644
--- a/chrome/android/javatests_shell/src/org/chromium/chrome/browser/banners/AppBannerManagerTest.java
+++ b/chrome/android/javatests_shell/src/org/chromium/chrome/browser/banners/AppBannerManagerTest.java
@@ -4,11 +4,19 @@
 
 package org.chromium.chrome.browser.banners;
 
+import android.app.Activity;
+import android.app.Instrumentation.ActivityMonitor;
+import android.app.Instrumentation.ActivityResult;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageInfo;
 import android.net.Uri;
+import android.test.mock.MockPackageManager;
 import android.test.suitebuilder.annotation.MediumTest;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.text.TextUtils;
 import android.view.View;
+import android.widget.Button;
 import android.widget.TextView;
 
 import org.chromium.base.ThreadUtils;
@@ -18,6 +26,7 @@
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.infobar.AnimationHelper;
 import org.chromium.chrome.browser.infobar.AppBannerInfoBar;
+import org.chromium.chrome.browser.infobar.AppBannerInfoBarDelegate;
 import org.chromium.chrome.browser.infobar.InfoBar;
 import org.chromium.chrome.browser.infobar.InfoBarContainer;
 import org.chromium.chrome.shell.ChromeShellTestBase;
@@ -28,6 +37,7 @@
 import org.chromium.content.browser.test.util.TouchCommon;
 
 import java.util.ArrayList;
+import java.util.List;
 
 /**
  * Tests the app banners.
@@ -42,24 +52,33 @@
 
     private static final String NATIVE_APP_TITLE = "Mock app title";
 
+    private static final String NATIVE_APP_PACKAGE = "123456";
+
+    private static final String NATIVE_APP_INSTALL_TEXT = "Install this";
+
     private static final String WEB_APP_URL =
             TestHttpServerClient.getUrl("chrome/test/data/banners/manifest_test_page.html");
 
     private static final String WEB_APP_TITLE = "Manifest test app";
 
+    private static final String INSTALL_ACTION = "INSTALL_ACTION";
+
     private static class MockAppDetailsDelegate extends AppDetailsDelegate {
         private Observer mObserver;
         private AppData mAppData;
         private int mNumRetrieved;
+        private Intent mInstallIntent;
 
         @Override
         protected void getAppDetailsAsynchronously(
                 Observer observer, String url, String packageName, int iconSize) {
             mNumRetrieved += 1;
             mObserver = observer;
+            mInstallIntent = new Intent(INSTALL_ACTION);
+
             mAppData = new AppData(url, packageName);
-            mAppData.setPackageInfo(
-                    NATIVE_APP_TITLE, NATIVE_ICON_URL, 4.5f, "Install this", null, null);
+            mAppData.setPackageInfo(NATIVE_APP_TITLE, NATIVE_ICON_URL, 4.5f,
+                    NATIVE_APP_INSTALL_TEXT, null, mInstallIntent);
             ThreadUtils.runOnUiThread(new Runnable() {
                 @Override
                 public void run() {
@@ -73,6 +92,23 @@
         }
     }
 
+    private static class TestPackageManager extends MockPackageManager {
+        public boolean isInstalled = false;
+
+        @Override
+        public List<PackageInfo> getInstalledPackages(int flags) {
+            List<PackageInfo> packages = new ArrayList<PackageInfo>();
+
+            if (isInstalled) {
+                PackageInfo info = new PackageInfo();
+                info.packageName = NATIVE_APP_PACKAGE;
+                packages.add(info);
+            }
+
+            return packages;
+        }
+    }
+
     private static class InfobarListener implements InfoBarContainer.InfoBarAnimationListener {
         private boolean mDoneAnimating;
 
@@ -83,12 +119,15 @@
     }
 
     private MockAppDetailsDelegate mDetailsDelegate;
+    private TestPackageManager mPackageManager;
 
     @Override
     protected void setUp() throws Exception {
         mDetailsDelegate = new MockAppDetailsDelegate();
+        mPackageManager = new TestPackageManager();
         AppBannerManager.setAppDetailsDelegate(mDetailsDelegate);
         AppBannerManager.setIsEnabledForTesting(true);
+        AppBannerInfoBarDelegate.setPackageManagerForTesting(mPackageManager);
         clearAppData();
 
         super.setUp();
@@ -139,19 +178,63 @@
 
     @SmallTest
     @Feature({"AppBanners"})
-    public void testBannerAppears() throws Exception {
+    public void testFullNativeInstallPathway() throws Exception {
         // Visit a site that requests a banner.
         assertTrue(CriteriaHelper.pollForUIThreadCriteria(
                 new TabLoadObserver(getActivity().getActiveTab(), NATIVE_APP_URL)));
         assertTrue(waitUntilAppDetailsRetrieved(1));
         assertTrue(waitUntilNoInfoBarsExist());
 
-        // Indicate a day has passed, then revisit the page.
+        // Indicate a day has passed, then revisit the page to get the banner to appear.
+        InfoBarContainer container = getActivity().getActiveTab().getInfoBarContainer();
+        final InfobarListener listener = new InfobarListener();
+        container.setAnimationListener(listener);
         AppBannerManager.setTimeDeltaForTesting(1);
         assertTrue(CriteriaHelper.pollForUIThreadCriteria(
                 new TabLoadObserver(getActivity().getActiveTab(), NATIVE_APP_URL)));
         assertTrue(waitUntilAppDetailsRetrieved(2));
         assertTrue(waitUntilAppBannerInfoBarAppears(NATIVE_APP_TITLE));
+        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+            @Override
+            public boolean isSatisfied() {
+                return listener.mDoneAnimating;
+            }
+        }));
+
+        // Check that the button asks if the user wants to install the app.
+        InfoBar infobar = container.getInfoBars().get(0);
+        final Button button =
+                (Button) infobar.getContentWrapper().findViewById(R.id.button_primary);
+        assertEquals(NATIVE_APP_INSTALL_TEXT, button.getText());
+
+        // Click the button to trigger the install.
+        final ActivityMonitor activityMonitor = new ActivityMonitor(
+                new IntentFilter(INSTALL_ACTION), new ActivityResult(Activity.RESULT_OK, null),
+                true);
+        getInstrumentation().addMonitor(activityMonitor);
+        TouchCommon.singleClickView(button);
+
+        // Wait for the infobar to register that the app is installing.
+        final String installingText =
+                getInstrumentation().getTargetContext().getString(R.string.app_banner_installing);
+        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+            @Override
+            public boolean isSatisfied() {
+                return getInstrumentation().checkMonitorHit(activityMonitor, 1)
+                        && TextUtils.equals(button.getText(), installingText);
+            }
+        }));
+
+        // Say that the package is installed.  Infobar should say that the app is ready to open.
+        mPackageManager.isInstalled = true;
+        final String openText =
+                getInstrumentation().getTargetContext().getString(R.string.app_banner_open);
+        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+            @Override
+            public boolean isSatisfied() {
+                return TextUtils.equals(button.getText(), openText);
+            }
+        }));
     }
 
     @MediumTest
diff --git a/chrome/android/javatests_shell/src/org/chromium/chrome/browser/feedback/ConnectivityCheckerTest.java b/chrome/android/javatests_shell/src/org/chromium/chrome/browser/feedback/ConnectivityCheckerTest.java
index c05ee25..9ebf8c5 100644
--- a/chrome/android/javatests_shell/src/org/chromium/chrome/browser/feedback/ConnectivityCheckerTest.java
+++ b/chrome/android/javatests_shell/src/org/chromium/chrome/browser/feedback/ConnectivityCheckerTest.java
@@ -22,7 +22,9 @@
 import org.chromium.net.test.BaseHttpTestServer;
 
 import java.io.IOException;
+import java.net.MalformedURLException;
 import java.net.Socket;
+import java.net.URL;
 import java.util.concurrent.Semaphore;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
@@ -121,39 +123,78 @@
         }
     }
 
-    @MediumTest
-    public void testNoContentShouldWork() throws Exception {
-        executeTest(GENERATE_204_URL, true, TIMEOUT_MS);
+    private static URL getURLNoException(String url) {
+        try {
+            return new URL(url);
+        } catch (MalformedURLException e) {
+            return null;
+        }
     }
 
     @MediumTest
-    public void testSlowNoContentShouldNotWork() throws Exception {
+    public void testNoContentShouldWorkSystemStack() throws Exception {
+        executeTest(GENERATE_204_URL, true, TIMEOUT_MS, true);
+    }
+
+    @MediumTest
+    public void testNoContentShouldWorkChromeStack() throws Exception {
+        executeTest(GENERATE_204_URL, true, TIMEOUT_MS, false);
+    }
+
+    @MediumTest
+    public void testSlowNoContentShouldNotWorkSystemStack() throws Exception {
         // Force quick timeout. The server will wait TIMEOUT_MS, so this triggers well before.
-        executeTest(GENERATE_204_SLOW_URL, false, 100);
+        executeTest(GENERATE_204_SLOW_URL, false, 100, true);
     }
 
     @MediumTest
-    public void testHttpOKShouldFail() throws Exception {
-        executeTest(GENERATE_200_URL, false, TIMEOUT_MS);
+    public void testSlowNoContentShouldNotWorkChromeStack() throws Exception {
+        // Force quick timeout. The server will wait TIMEOUT_MS, so this triggers well before.
+        executeTest(GENERATE_204_SLOW_URL, false, 100, false);
     }
 
     @MediumTest
-    public void testMovedTemporarilyShouldFail() throws Exception {
-        executeTest(GENERATE_302_URL, false, TIMEOUT_MS);
+    public void testHttpOKShouldFailSystemStack() throws Exception {
+        executeTest(GENERATE_200_URL, false, TIMEOUT_MS, true);
     }
 
     @MediumTest
-    public void testNotFoundShouldFail() throws Exception {
-        executeTest(GENERATE_404_URL, false, TIMEOUT_MS);
+    public void testHttpOKShouldFailChromeStack() throws Exception {
+        executeTest(GENERATE_200_URL, false, TIMEOUT_MS, false);
     }
 
     @MediumTest
-    public void testInvalidURLShouldFail() throws Exception {
-        executeTest("http:google.com:foo", false, TIMEOUT_MS);
+    public void testMovedTemporarilyShouldFailSystemStack() throws Exception {
+        executeTest(GENERATE_302_URL, false, TIMEOUT_MS, true);
     }
 
-    private void executeTest(final String url, boolean expectedResult, final long timeoutMs)
-            throws Exception {
+    @MediumTest
+    public void testMovedTemporarilyShouldFailChromeStack() throws Exception {
+        executeTest(GENERATE_302_URL, false, TIMEOUT_MS, false);
+    }
+
+    @MediumTest
+    public void testNotFoundShouldFailSystemStack() throws Exception {
+        executeTest(GENERATE_404_URL, false, TIMEOUT_MS, true);
+    }
+
+    @MediumTest
+    public void testNotFoundShouldFailChromeStack() throws Exception {
+        executeTest(GENERATE_404_URL, false, TIMEOUT_MS, false);
+    }
+
+    @MediumTest
+    public void testInvalidURLShouldFailSystemStack() throws Exception {
+        executeTest("http:google.com:foo", false, TIMEOUT_MS, true);
+    }
+
+    @MediumTest
+    public void testInvalidURLShouldFailChromeStack() throws Exception {
+        executeTest("http:google.com:foo", false, TIMEOUT_MS, false);
+    }
+
+    private void executeTest(final String url, boolean expectedResult, final long timeoutMs,
+            final boolean useSystemStack) throws Exception {
         Context targetContext = getInstrumentation().getTargetContext();
         startChromeBrowserProcessSync(targetContext);
         ConnectivityTestServer testServer = new ConnectivityTestServer();
@@ -166,8 +207,13 @@
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
             @Override
             public void run() {
-                ConnectivityChecker.checkConnectivity(
-                        Profile.getLastUsedProfile(), url, timeoutMs, callback);
+                if (useSystemStack) {
+                    ConnectivityChecker.checkConnectivitySystemNetworkStack(
+                            getURLNoException(url), ((int) timeoutMs), callback);
+                } else {
+                    ConnectivityChecker.checkConnectivityChromeNetworkStack(
+                            Profile.getLastUsedProfile(), url, timeoutMs, callback);
+                }
             }
         });
 
diff --git a/chrome/android/javatests_shell/src/org/chromium/chrome/browser/omnibox/OmniboxUrlEmphasizerTest.java b/chrome/android/javatests_shell/src/org/chromium/chrome/browser/omnibox/OmniboxUrlEmphasizerTest.java
index 0173353c..46a1613 100644
--- a/chrome/android/javatests_shell/src/org/chromium/chrome/browser/omnibox/OmniboxUrlEmphasizerTest.java
+++ b/chrome/android/javatests_shell/src/org/chromium/chrome/browser/omnibox/OmniboxUrlEmphasizerTest.java
@@ -126,7 +126,7 @@
     public void testShortSecureHTTPSUrl() {
         Spannable url = new SpannableStringBuilder("https://www.google.com/");
         OmniboxUrlEmphasizer.emphasizeUrl(url, mResources, mProfile,
-                ConnectionSecurityHelperSecurityLevel.SECURE, false, true);
+                ConnectionSecurityHelperSecurityLevel.SECURE, false, true, true);
         EmphasizedUrlSpanHelper[] spans = EmphasizedUrlSpanHelper.getSpansForEmphasizedUrl(url);
 
         assertEquals("Unexpected number of spans:", 4, spans.length);
@@ -150,7 +150,7 @@
     public void testShortSecureHTTPSUrlWithLightColors() {
         Spannable url = new SpannableStringBuilder("https://www.google.com/");
         OmniboxUrlEmphasizer.emphasizeUrl(url, mResources, mProfile,
-                ConnectionSecurityHelperSecurityLevel.SECURE, false, false);
+                ConnectionSecurityHelperSecurityLevel.SECURE, false, false, false);
         EmphasizedUrlSpanHelper[] spans = EmphasizedUrlSpanHelper.getSpansForEmphasizedUrl(url);
 
         assertEquals("Unexpected number of spans:", 4, spans.length);
@@ -175,7 +175,7 @@
         Spannable url = new SpannableStringBuilder(
                 "https://www.google.com/q?query=abc123&results=1");
         OmniboxUrlEmphasizer.emphasizeUrl(url, mResources, mProfile,
-                ConnectionSecurityHelperSecurityLevel.SECURITY_ERROR, false, true);
+                ConnectionSecurityHelperSecurityLevel.SECURITY_ERROR, false, true, true);
         EmphasizedUrlSpanHelper[] spans = EmphasizedUrlSpanHelper.getSpansForEmphasizedUrl(url);
 
         assertEquals("Unexpected number of spans:", 5, spans.length);
@@ -200,7 +200,7 @@
     public void testVeryShortWarningHTTPSUrl() {
         Spannable url = new SpannableStringBuilder("https://www.dodgysite.com");
         OmniboxUrlEmphasizer.emphasizeUrl(url, mResources, mProfile,
-                ConnectionSecurityHelperSecurityLevel.SECURITY_WARNING, false, true);
+                ConnectionSecurityHelperSecurityLevel.SECURITY_WARNING, false, true, true);
         EmphasizedUrlSpanHelper[] spans = EmphasizedUrlSpanHelper.getSpansForEmphasizedUrl(url);
 
         assertEquals("Unexpected number of spans:", 3, spans.length);
@@ -221,8 +221,8 @@
     @Feature({"Browser", "Main"})
     public void testAboutPageUrl() {
         Spannable url = new SpannableStringBuilder("about:blank");
-        OmniboxUrlEmphasizer.emphasizeUrl(
-                url, mResources, mProfile, ConnectionSecurityHelperSecurityLevel.NONE, true, true);
+        OmniboxUrlEmphasizer.emphasizeUrl(url, mResources, mProfile,
+                ConnectionSecurityHelperSecurityLevel.NONE, true, true, true);
         EmphasizedUrlSpanHelper[] spans = EmphasizedUrlSpanHelper.getSpansForEmphasizedUrl(url);
 
         assertEquals("Unexpected number of spans:", 3, spans.length);
@@ -244,8 +244,8 @@
     public void testDataUrl() {
         Spannable url = new SpannableStringBuilder(
                 "data:text/plain;charset=utf-8;base64,VGVzdCBVUkw=");
-        OmniboxUrlEmphasizer.emphasizeUrl(
-                url, mResources, mProfile, ConnectionSecurityHelperSecurityLevel.NONE, true, true);
+        OmniboxUrlEmphasizer.emphasizeUrl(url, mResources, mProfile,
+                ConnectionSecurityHelperSecurityLevel.NONE, true, true, true);
         EmphasizedUrlSpanHelper[] spans = EmphasizedUrlSpanHelper.getSpansForEmphasizedUrl(url);
 
         assertEquals("Unexpected number of spans:", 1, spans.length);
@@ -262,8 +262,8 @@
     @Feature({"Browser", "Main"})
     public void testInternalChromePageUrl() {
         Spannable url = new SpannableStringBuilder("chrome://bookmarks");
-        OmniboxUrlEmphasizer.emphasizeUrl(
-                url, mResources, mProfile, ConnectionSecurityHelperSecurityLevel.NONE, true, true);
+        OmniboxUrlEmphasizer.emphasizeUrl(url, mResources, mProfile,
+                ConnectionSecurityHelperSecurityLevel.NONE, true, true, true);
         EmphasizedUrlSpanHelper[] spans = EmphasizedUrlSpanHelper.getSpansForEmphasizedUrl(url);
 
         assertEquals("Unexpected number of spans:", 3, spans.length);
@@ -284,8 +284,8 @@
     @Feature({"Browser", "Main"})
     public void testInternalChromeNativePageUrl() {
         Spannable url = new SpannableStringBuilder("chrome-native://bookmarks");
-        OmniboxUrlEmphasizer.emphasizeUrl(
-                url, mResources, mProfile, ConnectionSecurityHelperSecurityLevel.NONE, true, true);
+        OmniboxUrlEmphasizer.emphasizeUrl(url, mResources, mProfile,
+                ConnectionSecurityHelperSecurityLevel.NONE, true, true, true);
         EmphasizedUrlSpanHelper[] spans = EmphasizedUrlSpanHelper.getSpansForEmphasizedUrl(url);
 
         assertEquals("Unexpected number of spans:", 3, spans.length);
@@ -306,8 +306,8 @@
     @Feature({"Browser", "Main"})
     public void testInvalidUrl() {
         Spannable url = new SpannableStringBuilder("invalidurl");
-        OmniboxUrlEmphasizer.emphasizeUrl(
-                url, mResources, mProfile, ConnectionSecurityHelperSecurityLevel.NONE, true, true);
+        OmniboxUrlEmphasizer.emphasizeUrl(url, mResources, mProfile,
+                ConnectionSecurityHelperSecurityLevel.NONE, true, true, true);
         EmphasizedUrlSpanHelper[] spans = EmphasizedUrlSpanHelper.getSpansForEmphasizedUrl(url);
 
         assertEquals("Unexpected number of spans:", 1, spans.length);
diff --git a/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/SyncCustomizationFragmentTest.java b/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/SyncCustomizationFragmentTest.java
index 71016f8a..496f87d 100644
--- a/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/SyncCustomizationFragmentTest.java
+++ b/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/SyncCustomizationFragmentTest.java
@@ -12,13 +12,17 @@
 import android.preference.SwitchPreference;
 import android.preference.TwoStatePreference;
 import android.test.suitebuilder.annotation.SmallTest;
+import android.view.View;
+import android.widget.ListView;
 
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.test.util.Feature;
+import org.chromium.chrome.browser.sync.ui.PassphraseTypeDialogFragment;
 import org.chromium.chrome.browser.sync.ui.SyncCustomizationFragment;
 import org.chromium.chrome.shell.R;
 import org.chromium.chrome.test.util.browser.sync.SyncTestUtil;
 import org.chromium.sync.AndroidSyncSettings;
+import org.chromium.sync.internal_api.pub.PassphraseType;
 import org.chromium.sync.internal_api.pub.base.ModelType;
 
 import java.util.Collection;
@@ -138,6 +142,12 @@
         assertFalse(mAndroidSyncSettings.isChromeSyncEnabled());
     }
 
+    /**
+     * Make sure that the encryption UI presents the correct options.
+     *
+     * By default it should show the CUSTOM and KEYSTORE options, in that order.
+     * KEYSTORE should be selected but both should be enabled.
+     */
     @SmallTest
     @Feature({"Sync"})
     public void testSettingDataTypes() throws Exception {
@@ -167,6 +177,33 @@
         assertDataTypesAre(expectedTypes);
     }
 
+    @SmallTest
+    @Feature({"Sync"})
+    public void testDefaultEncryptionOptions() throws Exception {
+        setupTestAccountAndSignInToSync(CLIENT_ID);
+        startSync();
+        SyncCustomizationFragment fragment = startSyncCustomizationFragment();
+        Preference encryption = getEncryption(fragment);
+        clickPreference(encryption);
+
+        PassphraseTypeDialogFragment typeFragment = getPassphraseTypeDialogFragment();
+        ListView listView = (ListView) typeFragment.getDialog()
+                .findViewById(R.id.passphrase_type_list);
+        PassphraseTypeDialogFragment.Adapter adapter =
+                (PassphraseTypeDialogFragment.Adapter) listView.getAdapter();
+
+        // Confirm that correct types show up in the correct order.
+        assertEquals(PassphraseType.CUSTOM_PASSPHRASE, adapter.getType(0));
+        assertEquals(PassphraseType.KEYSTORE_PASSPHRASE, adapter.getType(1));
+        assertEquals(2, listView.getCount());
+        // Make sure they are both enabled and the correct on is selected.
+        View customView = listView.getChildAt(0);
+        View keystoreView = listView.getChildAt(1);
+        assertTrue(customView.isEnabled());
+        assertTrue(keystoreView.isEnabled());
+        assertEquals(keystoreView, listView.getSelectedView());
+    }
+
     private SyncCustomizationFragment startSyncCustomizationFragment() {
         SyncCustomizationFragment fragment = new SyncCustomizationFragment();
         Bundle args = new Bundle();
@@ -217,6 +254,11 @@
                 SyncCustomizationFragment.PREFERENCE_SYNC_MANAGE_DATA);
     }
 
+    private PassphraseTypeDialogFragment getPassphraseTypeDialogFragment() {
+        return (PassphraseTypeDialogFragment) mActivity.getFragmentManager()
+                .findFragmentByTag(SyncCustomizationFragment.FRAGMENT_PASSWORD_TYPE);
+    }
+
     private void assertDefaultSyncOnState(SyncCustomizationFragment fragment) {
         assertTrue("The sync switch should be on.", getSyncSwitch(fragment).isChecked());
         assertTrue("The sync switch should be enabled.", getSyncSwitch(fragment).isEnabled());
@@ -279,4 +321,14 @@
         });
         getInstrumentation().waitForIdleSync();
     }
+
+    private void clickPreference(final Preference pref) {
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                pref.getOnPreferenceClickListener().onPreferenceClick(pref);
+            }
+        });
+        getInstrumentation().waitForIdleSync();
+    }
 }
diff --git a/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/SyncTest.java b/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/SyncTest.java
index b0ec148..38b48a9 100644
--- a/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/SyncTest.java
+++ b/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/SyncTest.java
@@ -130,6 +130,22 @@
 
     @LargeTest
     @Feature({"Sync"})
+    public void testSignInAndOut() throws InterruptedException {
+        setupTestAccountAndSignInToSync(CLIENT_ID);
+        Account account =
+                AccountManagerHelper.createAccountFromName(SyncTestUtil.DEFAULT_TEST_ACCOUNT);
+
+        // Signing out should disable sync.
+        signOut();
+        SyncTestUtil.verifySyncIsSignedOut(mContext);
+
+        // Signing back in should re-enable sync.
+        signIn(account);
+        SyncTestUtil.verifySyncIsSignedIn(mContext, account);
+    }
+
+    @LargeTest
+    @Feature({"Sync"})
     public void testDisableAndEnableSyncThroughAndroid() throws InterruptedException {
         setupTestAccountAndSignInToSync(CLIENT_ID);
         SyncTestUtil.ensureSyncInitialized(mContext);
diff --git a/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/SyncTestBase.java b/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/SyncTestBase.java
index 6b429df3..f28ab17 100644
--- a/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/SyncTestBase.java
+++ b/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/SyncTestBase.java
@@ -5,7 +5,6 @@
 package org.chromium.chrome.browser.sync;
 
 import android.accounts.Account;
-import android.app.Activity;
 import android.content.Context;
 
 import org.chromium.base.ThreadUtils;
@@ -13,6 +12,7 @@
 import org.chromium.chrome.browser.identity.UniqueIdentificationGeneratorFactory;
 import org.chromium.chrome.browser.identity.UuidBasedUniqueIdentificationGenerator;
 import org.chromium.chrome.browser.signin.AccountIdProvider;
+import org.chromium.chrome.browser.signin.SigninManager;
 import org.chromium.chrome.shell.ChromeShellTestBase;
 import org.chromium.chrome.test.util.browser.sync.SyncTestUtil;
 import org.chromium.content.browser.test.util.Criteria;
@@ -131,15 +131,7 @@
                 }, true);
 
         SyncTestUtil.verifySyncIsSignedOut(getActivity());
-
-        final Activity activity = launchChromeShellWithBlankPage();
-        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
-            @Override
-            public void run() {
-                mSyncController.signIn(activity, SyncTestUtil.DEFAULT_TEST_ACCOUNT);
-            }
-        });
-
+        signIn(defaultTestAccount);
         SyncTestUtil.verifySyncIsSignedIn(mContext, defaultTestAccount);
         assertTrue("Sync everything should be enabled",
                 SyncTestUtil.isSyncEverythingEnabled(mContext));
@@ -165,6 +157,24 @@
         getInstrumentation().waitForIdleSync();
     }
 
+    protected void signIn(final Account account) {
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                mSyncController.signIn(getActivity(), account.name);
+            }
+        });
+    }
+
+    protected void signOut() throws InterruptedException {
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                SigninManager.get(mContext).signOut(getActivity(), null);
+            }
+        });
+    }
+
     protected void waitForSyncInitialized() throws InterruptedException {
         assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
             @Override
diff --git a/chrome/app/chrome_command_ids.h b/chrome/app/chrome_command_ids.h
index 3e91a9e..797e782 100644
--- a/chrome/app/chrome_command_ids.h
+++ b/chrome/app/chrome_command_ids.h
@@ -282,6 +282,7 @@
 #define IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB 50113
 #define IDC_CONTENT_CONTEXT_SEARCHWEBFORIMAGE 50114
 #define IDC_CONTENT_CONTEXT_OPEN_ORIGINAL_IMAGE_NEW_TAB 50115
+#define IDC_CONTENT_CONTEXT_SHOW_ORIGINAL_IMAGE 50116
 // Audio/video items.
 #define IDC_CONTENT_CONTEXT_SAVEAVAS 50120
 #define IDC_CONTENT_CONTEXT_COPYAVLOCATION 50121
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index 096d7037..65d4177d 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -6362,5 +6362,11 @@
   <message name="IDS_WEBSTORE_WIDGET_DEFAULT_ERROR" desc="Default message shown when Chrome Web Store Widget app window content fails to load (e.g. if it fails to load Chrome Web Store Gallery in a webview).">
     Could not connect to the Chrome Web Store.
   </message>
+  <message name="IDS_FLAGS_PRINTER_PROVIDER_SEARCH_APP_NAME" desc="Name of the flag used to enable launching Chrome Web Store Gallery widget app for searching for printer provider apps.">
+    Chrome Web Store Gallery app for printer drivers
+  </message>
+  <message name="IDS_FLAGS_PRINTER_PROVIDER_SEARCH_APP_DESCRIPTION" desc="Description of a flag in chrome://flags that enables launching Chrome Web Store Gallery widget app for searching for printer provider apps.">
+    Enables Chrome Web Store Gallery app for printer drivers. The app searches Chrome Web Store for extensions that support printing to a USB printer with specific USB ID.
+  </message>
 
 </grit-part>
diff --git a/chrome/app/chromium_strings.grd b/chrome/app/chromium_strings.grd
index 4d67e1cc..2b1f9f1a 100644
--- a/chrome/app/chromium_strings.grd
+++ b/chrome/app/chromium_strings.grd
@@ -460,8 +460,11 @@
         </message>
       </if>
       <!-- Password generation strings -->
-      <message name="IDS_PASSWORD_GENERATION_PROMPT" desc="Autofill dropdown text describing password generation. The text inside |bars| is link text.">
-        Chromium will store this in your |Google saved passwords| and remember it the next time you need it.
+      <message name="IDS_PASSWORD_GENERATION_PROMPT" desc="Autofill dropdown text describing password generation. The link text is a separate string in the translation console and appears here as placeholder text.">
+        Chromium will store this in your <ph name="SAVED_PASSWORD_LINK">$1<ex>Google saved passwords</ex></ph> and remember it the next time you need it.
+      </message>
+      <message name="IDS_PASSWORD_GENERATION_SMART_LOCK_PROMPT" desc="Autofill dropdown text describing password generation. Used when we change the branding to SmartLock.  The link text is a separate string in the translation console and appears here as placeholder text.">
+        Chromium will store this with <ph name="SAVED_PASSWORD_LINK">$1<ex>Google Smart Lock for Passwords</ex></ph> and remember it the next time you need it.
       </message>
       <message name="IDS_PASSWORD_GENERATION_SUGGESTION" desc="Text shown next to a generated password describing it as a suggestion.">
         Use password generated by Chromium
@@ -784,9 +787,12 @@
       </message>
 
       <if expr="enable_extensions">
-        <message name="IDS_EXTENSIONS_UNSUPPORTED_DISABLED_BODY" desc="Body of the dialog shown when unsupported extensions have been disabled">
+        <message name="IDS_EXTENSIONS_MULTIPLE_UNSUPPORTED_DISABLED_BODY" desc="Body of the dialog shown when multiple unsupported extensions have been disabled.">
           To make Chromium safer, we disabled some extensions that aren't listed in the <ph name="IDS_EXTENSION_WEB_STORE_TITLE">$1<ex>Chrome Web Store</ex></ph> and may have been added without your knowledge.
         </message>
+        <message name="IDS_EXTENSIONS_SINGLE_UNSUPPORTED_DISABLED_BODY" desc="Body of the dialog shown when a single unsupported extension has been disabled.">
+          To make Chromium safer, we disabled the following extension that isn't listed in the <ph name="IDS_EXTENSION_WEB_STORE_TITLE">$1<ex>Chrome Web Store</ex></ph> and may have been added without your knowledge.
+        </message>
       </if>
 
       <!-- Main Chrome menu -->
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 5687fb83..6462dc6 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -806,6 +806,9 @@
           <message name="IDS_CONTENT_CONTEXT_OPEN_ORIGINAL_IMAGE_NEW_TAB" desc="The name of the Open Original Image in New Tab command in the content area context menu">
             Open original &amp;image in new tab
           </message>
+          <message name="IDS_CONTENT_CONTEXT_SHOW_ORIGINAL_IMAGE" desc="The name of the Show Original Image command in the content area context menu">
+            Show image
+          </message>
 
           <message name="IDS_CONTENT_CONTEXT_LOOP" desc="The name of the Loop command for audio and video playback in the content area context menu">
             &amp;Loop
@@ -1009,6 +1012,9 @@
           <message name="IDS_CONTENT_CONTEXT_OPEN_ORIGINAL_IMAGE_NEW_TAB" desc="In Title Case: The name of the Open Original Image in New Tab command in the content area context menu">
             Open Original &amp;Image in New Tab
           </message>
+          <message name="IDS_CONTENT_CONTEXT_SHOW_ORIGINAL_IMAGE" desc="In Title Case: The name of the Show Original Image command in the content area context menu">
+            Show Image
+          </message>
 
           <message name="IDS_CONTENT_CONTEXT_LOOP" desc="In Title Case: The name of the Loop command for audio and video playback in the content area context menu">
             &amp;Loop
@@ -6379,8 +6385,11 @@
       <message name="IDS_PASSWORD_MANAGER_SMART_LOCK" desc="The brand name of the password manager for the title of the save password bubble when a user is signed in.">
         Google Smart Lock
       </message>
+      <message name="IDS_PASSWORD_MANAGER_SMART_LOCK_FOR_PASSWORDS" desc="The more descriptive brand name of the password manager when the user is signed in. Used in various UI elements, can be in link format.">
+        Google Smart Lock for Passwords
+      </message>
       <message name="IDS_PASSWORD_MANAGER_SMART_LOCK_ARTICLE" desc="URL of help center page explaining what the 'Google Smart Lock' is.">
-        https://support.google.com/chromebook/answer/6070209?hl=[GRITLANGCODE]
+        https://support.google.com/accounts/answer/6197437?hl=[GRITLANGCODE]
       </message>
       <message name="IDS_PASSWORD_MANAGER_SAVE_PASSWORD_SMART_LOCK_NO_THANKS_BUTTON" desc="Text for the button the user clicks to dismiss save password bubble.">
         No thanks
@@ -7655,6 +7664,9 @@
       <message name="IDS_PASSWORDS_EXCEPTIONS_WINDOW_TITLE" desc="Title for 'Passwords and exceptions dialog'">
         Passwords
       </message>
+      <message name="IDS_PASSWORDS_EXCEPTIONS_SMART_LOCK_WINDOW_TITLE" desc="Title for 'Passwords and exceptions dialog'">
+        Google Smart Lock for Passwords
+      </message>
       <message name="IDS_PASSWORDS_AUTO_SIGNIN_TITLE" desc="Title for 'Auto sign-in' checkbox in the password dialog">
         Auto Sign-in
       </message>
@@ -10552,6 +10564,9 @@
         <message name="IDS_OPTIONS_PASSWORD_MANAGER_ENABLE" desc="The label of the password manager checkbox">
           Offer to save your web passwords.
         </message>
+        <message name="IDS_OPTIONS_PASSWORD_MANAGER_SMART_LOCK_ENABLE" desc="The label of the password manager checkbox if Smart Lock is enabled.">
+          Offer to save passwords with Google Smart Lock for Passwords.
+        </message>
         <message name="IDS_OPTIONS_PASSWORDS_AUTOLOGIN" desc="The label of the 'autologinEnabled' checkbox">
           Offer to sign in to Google sites automatically with this account
         </message>
@@ -11673,10 +11688,6 @@
 
       <!-- Strings used for non-Android builds -->
       <if expr="not is_android">
-        <message name="IDS_NEW_TAB_SUGGESTIONS"
-                 desc="The name for the 'Suggestions' navigation control on the New Tab Page.">
-          Suggested
-        </message>
         <message name="IDS_APP_DEFAULT_PAGE_NAME"
                  desc="Default name for the first 'Apps' page on the New Tab Page.">
           Apps
@@ -13617,15 +13628,18 @@
       </if>
 
       <message name="IDS_MANAGE_PASSWORDS_CONFIRM_GENERATED_TITLE" desc="The title text that is used in the manage passwords bubble when the user has generated a password.">
-        Generated password saved
+        Password saved
       </message>
       <message name="IDS_MANAGE_PASSWORDS_CONFIRM_GENERATED_TEXT" desc="A message that the browser shows after saving a password it has autogenerated for the user. This message appears in a bubble and contains a link to all the user's saved autogenerated passwords. The link text is a separate string in the translation console and appears here as placeholder text.">
         You can access it and all your <ph name="SAVED_PASSWORDS_LINK">$1<ex>Google saved passwords</ex></ph> from any browser.
       </message>
-      <message name="IDS_MANAGE_PASSWORDS_CONFIRM_GENERATED_TEXT_INFOBAR" desc="A message that the browser shows after saving a password it has autogenerated for the user. This message appears in an infobar and contains a link to all the user's saved autogenerated passwords. The link text is a separate string in the translation console and appears here as placeholder text.">
-        Generated password saved. You can access it and all your <ph name="SAVED_PASSWORDS_LINK">$1<ex>Google saved passwords</ex></ph> from any browser.
+      <message name="IDS_MANAGE_PASSWORDS_CONFIRM_GENERATED_SMART_LOCK_TEXT" desc="A message that the browser shows after saving a password it has autogenerated for the user if Smart Lock branding is enabled. This message appears in a bubble and contains a link to all the user's saved autogenerated passwords.">
+        Access your passwords from any device at <ph name="MANAGEMENT_LINK">$1<ex>passwords.google.com</ex></ph>.
       </message>
-      <message name="IDS_MANAGE_PASSWORDS_CONFIRM_GENERATED_LINK" desc="The text for a link to the user's saved autogenerated passwords. This is inserted into an infobar or a bubble that the browser shows to the user after it saves an autogenerated password. The infobar and the bubble use a separate string in the translation console that has a placeholder for this link title.">
+      <message name="IDS_MANAGE_PASSWORDS_CONFIRM_GENERATED_TEXT_INFOBAR" desc="A message that the browser shows after saving a password it has autogenerated for the user. This message appears in an infobar and contains a link to all the user's saved autogenerated passwords. The link text is a separate string in the translation console and appears here as placeholder text.">
+        Password saved. You can access it and all your <ph name="SAVED_PASSWORDS_LINK">$1<ex>Google saved passwords</ex></ph> from any browser.
+      </message>
+      <message name="IDS_MANAGE_PASSWORDS_LINK" desc="The text for a link to the user's saved passwords. This is inserted into an infobar or a bubble that the browser shows to the user. The infobar and the bubble use a separate string in the translation console that has a placeholder for this link title.">
         Google saved passwords
       </message>
       <message name="IDS_MANAGE_PASSWORDS_TITLE" desc="The title text that is used in the manage passwords bubble when a password is autofilled or after a user has stored a password.">
@@ -13646,8 +13660,8 @@
       <message name="IDS_MANAGE_PASSWORDS_BLACKLIST_CONFIRMATION_BUTTON" desc="The confirmation button that is used in the manage passwords bubble when confirming blacklisting a site.">
         Delete saved passwords
       </message>
-      <message name="IDS_MANAGE_PASSWORDS_REMOTE_TEXT" desc="The text used to tell inform users of how to manage their passwords from a website. Text between |bars| is link text.">
-        Manage passwords remotely on your |Google Account|
+      <message name="IDS_MANAGE_PASSWORDS_REMOTE_TEXT" desc="The text used to tell inform users of how to manage their passwords from a website.">
+        Access your passwords from any device at <ph name="LINK_TEXT">$1<ex>passwords.google.com</ex></ph>
       </message>
 
       <message name="IDS_MANAGE_PASSWORDS_NO_PASSWORDS" desc="The text that is used in the manage passwords bubble when all passwords have been deleted.">
diff --git a/chrome/app/google_chrome_strings.grd b/chrome/app/google_chrome_strings.grd
index b63d643..2e849a2 100644
--- a/chrome/app/google_chrome_strings.grd
+++ b/chrome/app/google_chrome_strings.grd
@@ -383,8 +383,11 @@
         </message>
       </if>
       <!-- Password generation strings -->
-      <message name="IDS_PASSWORD_GENERATION_PROMPT" desc="Autofill dropdown text describing password generation. The text inside |bars| is link text.">
-        Chrome will store this in your |Google saved passwords| and remember it the next time you need it.
+      <message name="IDS_PASSWORD_GENERATION_PROMPT" desc="Autofill dropdown text describing password generation. The link text is a separate string in the translation console and appears here as placeholder text.">
+        Chrome will store this in your <ph name="SAVED_PASSWORDS_LINK">$1<ex>Google saved passwords</ex></ph> and remember it the next time you need it.
+      </message>
+      <message name="IDS_PASSWORD_GENERATION_SMART_LOCK_PROMPT" desc="Autofill dropdown text describing password generation. Used when we change the branding to SmartLock.  The link text is a separate string in the translation console and appears here as placeholder text.">
+        Chrome will store this with <ph name="SAVED_PASSWORD_LINK">$1<ex>Google Smart Lock for Passwords</ex></ph> and remember it the next time you need it.
       </message>
       <message name="IDS_PASSWORD_GENERATION_SUGGESTION" desc="Text shown next to a generated password describing it as a suggestion.">
         Use password generated by Chrome
@@ -707,9 +710,12 @@
       </message>
 
       <if expr="enable_extensions">
-        <message name="IDS_EXTENSIONS_UNSUPPORTED_DISABLED_BODY" desc="Body of the dialog shown when unsupported extensions have been disabled">
+        <message name="IDS_EXTENSIONS_MULTIPLE_UNSUPPORTED_DISABLED_BODY" desc="Body of the dialog shown when multiple unsupported extensions have been disabled.">
           To make Chrome safer, we disabled some extensions that aren't listed in the <ph name="IDS_EXTENSION_WEB_STORE_TITLE">$1<ex>Chrome Web Store</ex></ph> and may have been added without your knowledge.
         </message>
+        <message name="IDS_EXTENSIONS_SINGLE_UNSUPPORTED_DISABLED_BODY" desc="Body of the dialog shown when a single unsupported extension has been disabled.">
+          To make Chrome safer, we disabled the following extension that isn't listed in the <ph name="IDS_EXTENSION_WEB_STORE_TITLE">$1<ex>Chrome Web Store</ex></ph> and may have been added without your knowledge.
+        </message>
       </if>
 
       <!-- Wrench menu -->
diff --git a/chrome/app/resources/locale_settings_chromiumos.grd b/chrome/app/resources/locale_settings_chromiumos.grd
index 5e85a4e0..7f97e2b 100644
--- a/chrome/app/resources/locale_settings_chromiumos.grd
+++ b/chrome/app/resources/locale_settings_chromiumos.grd
@@ -214,7 +214,7 @@
       <!-- The default value for |WebPreference::fixed_font_family_map| for
            Japanese script. -->
       <message name="IDS_FIXED_FONT_FAMILY_JAPANESE" use_name_for_id="true">
-        IPAGothic
+        Noto Sans Mono CJK JP
       </message>
 
       <!-- The default value for |WebPreference::serif_font_family_map| for
@@ -238,7 +238,7 @@
       <!-- The default value for |WebPreference::fixed_font_family_map| for
            Korean script. -->
       <message name="IDS_FIXED_FONT_FAMILY_KOREAN" use_name_for_id="true">
-        Monospace
+        Noto Sans Mono CJK KR
       </message>
 
       <!-- The default value for |WebPreference::serif_font_family_map| for
@@ -262,7 +262,7 @@
       <!-- The default value for |WebPreference::fixed_font_family_map| for
            Simplified Chinese script. -->
       <message name="IDS_FIXED_FONT_FAMILY_SIMPLIFIED_HAN" use_name_for_id="true">
-        Noto Sans CJK SC
+        Noto Sans Mono CJK SC
       </message>
 
       <!-- The default value for |WebPreference::serif_font_family_map| for
@@ -280,7 +280,7 @@
       <!-- The default value for |WebPreference::standard_font_family_map| for
            Traditional Chinese script. -->
       <message name="IDS_STANDARD_FONT_FAMILY_TRADITIONAL_HAN" use_name_for_id="true">
-        Noto Sans CJK TC
+        Noto Sans Mono CJK TC
       </message>
 
       <!-- The default value for |WebPreference::fixed_font_family_map| for
diff --git a/chrome/app/resources/locale_settings_google_chromeos.grd b/chrome/app/resources/locale_settings_google_chromeos.grd
index 0a4ea4a..5aa2429 100644
--- a/chrome/app/resources/locale_settings_google_chromeos.grd
+++ b/chrome/app/resources/locale_settings_google_chromeos.grd
@@ -214,7 +214,7 @@
       <!-- The default value for |WebPreference::fixed_font_family_map| for
            Japanese script. -->
       <message name="IDS_FIXED_FONT_FAMILY_JAPANESE" use_name_for_id="true">
-        MotoyaG04GothicMono
+        Noto Sans Mono CJK JP
       </message>
 
       <!-- The default value for |WebPreference::serif_font_family_map| for
@@ -238,7 +238,7 @@
       <!-- The default value for |WebPreference::fixed_font_family_map| for
            Korean script. -->
       <message name="IDS_FIXED_FONT_FAMILY_KOREAN" use_name_for_id="true">
-        Monospace
+        Noto Sans Mono CJK KR
       </message>
 
       <!-- The default value for |WebPreference::serif_font_family_map| for
@@ -262,7 +262,7 @@
       <!-- The default value for |WebPreference::fixed_font_family_map| for
            Simplified Chinese script. -->
       <message name="IDS_FIXED_FONT_FAMILY_SIMPLIFIED_HAN" use_name_for_id="true">
-        Noto Sans CJK SC
+        Noto Sans Mono CJK SC
       </message>
 
       <!-- The default value for |WebPreference::serif_font_family_map| for
@@ -280,7 +280,7 @@
       <!-- The default value for |WebPreference::standard_font_family_map| for
            Traditional Chinese script. -->
       <message name="IDS_STANDARD_FONT_FAMILY_TRADITIONAL_HAN" use_name_for_id="true">
-        Noto Sans CJK TC
+        Noto Sans Mono CJK TC
       </message>
 
       <!-- The default value for |WebPreference::fixed_font_family_map| for
diff --git a/chrome/app/resources/platform_locale_settings/locale_settings_cros_ja.xtb b/chrome/app/resources/platform_locale_settings/locale_settings_cros_ja.xtb
index 94845c8..3df405be 100644
--- a/chrome/app/resources/platform_locale_settings/locale_settings_cros_ja.xtb
+++ b/chrome/app/resources/platform_locale_settings/locale_settings_cros_ja.xtb
@@ -4,7 +4,7 @@
 <translation id="IDS_STANDARD_FONT_FAMILY">Noto Sans CJK JP</translation>
 <translation id="IDS_SANS_SERIF_FONT_FAMILY">Noto Sans CJK JP</translation>
 <if expr="_google_chrome">
-  <translation id="IDS_FIXED_FONT_FAMILY">MotoyaG04GothicMono</translation>
+  <translation id="IDS_FIXED_FONT_FAMILY">Noto Sans Mono CJK JP</translation>
   <translation id="IDS_SERIF_FONT_FAMILY">MotoyaG04Mincho</translation>
 </if>
 <if expr="not _google_chrome">
diff --git a/chrome/app/resources/platform_locale_settings/locale_settings_cros_ko.xtb b/chrome/app/resources/platform_locale_settings/locale_settings_cros_ko.xtb
index 62ccd020..16b3c59e 100644
--- a/chrome/app/resources/platform_locale_settings/locale_settings_cros_ko.xtb
+++ b/chrome/app/resources/platform_locale_settings/locale_settings_cros_ko.xtb
@@ -3,7 +3,7 @@
 <translationbundle lang="ko">
 <!-- TODO(jungshik): remove this line once we fix bug 14691 -->
 <translation id="IDS_STANDARD_FONT_FAMILY">Noto Sans CJK KR</translation>
-<translation id="IDS_FIXED_FONT_FAMILY">Monospace</translation>
+<translation id="IDS_FIXED_FONT_FAMILY">Noto Sans Mono CJK KR</translation>
 <translation id="IDS_SERIF_FONT_FAMILY">NanumMyeongjo</translation>
 <translation id="IDS_SANS_SERIF_FONT_FAMILY">Noto Sans CJK KR</translation>
 <translation id="IDS_MINIMUM_FONT_SIZE">10</translation>
diff --git a/chrome/app/resources/platform_locale_settings/locale_settings_cros_zh-CN.xtb b/chrome/app/resources/platform_locale_settings/locale_settings_cros_zh-CN.xtb
index 167449d..9848e4c7 100644
--- a/chrome/app/resources/platform_locale_settings/locale_settings_cros_zh-CN.xtb
+++ b/chrome/app/resources/platform_locale_settings/locale_settings_cros_zh-CN.xtb
@@ -2,7 +2,7 @@
 <!DOCTYPE translationbundle>
 <translationbundle lang="zh-CN">
 <translation id="IDS_STANDARD_FONT_FAMILY">Noto Sans CJK SC</translation>
-<translation id="IDS_FIXED_FONT_FAMILY">Noto Sans CJK SC</translation>
+<translation id="IDS_FIXED_FONT_FAMILY">Noto Sans Mono CJK SC</translation>
 <translation id="IDS_SANS_SERIF_FONT_FAMILY">Noto Sans CJK SC</translation>
 <if expr="_google_chrome">
   <translation id="IDS_SERIF_FONT_FAMILY">MSung GB18030</translation>
diff --git a/chrome/app/resources/platform_locale_settings/locale_settings_cros_zh-TW.xtb b/chrome/app/resources/platform_locale_settings/locale_settings_cros_zh-TW.xtb
index 3f462ad..c7bcdbc 100644
--- a/chrome/app/resources/platform_locale_settings/locale_settings_cros_zh-TW.xtb
+++ b/chrome/app/resources/platform_locale_settings/locale_settings_cros_zh-TW.xtb
@@ -2,7 +2,7 @@
 <!DOCTYPE translationbundle>
 <translationbundle lang="zh-TW">
 <translation id="IDS_STANDARD_FONT_FAMILY">Noto Sans CJK TC</translation>
-<translation id="IDS_FIXED_FONT_FAMILY">Noto Sans CJK TC</translation>
+<translation id="IDS_FIXED_FONT_FAMILY">Noto Sans Mono CJK TC</translation>
 <translation id="IDS_SANS_SERIF_FONT_FAMILY">Noto Sans CJK TC</translation>
 <if expr="_google_chrome">
   <translation id="IDS_SERIF_FONT_FAMILY">MSung B5HK</translation>
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 7a7efe90..96b968b 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -795,7 +795,7 @@
     }
   }
   if (enable_media_router) {
-    defines += [ "ENABLE_MEDIA_ROUTER=1" ]
+    deps += [ "//chrome/browser/media/router" ]
   }
 }
 
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 4ccd43b..9d576acc 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -2341,7 +2341,8 @@
     IDS_FLAGS_V8_PAC_MOJO_OUT_OF_PROCESS_NAME,
     IDS_FLAGS_V8_PAC_MOJO_OUT_OF_PROCESS_DESCRIPTION,
     kOsDesktop,
-    SINGLE_VALUE_TYPE(switches::kV8PacMojoOutOfProcess),
+    ENABLE_DISABLE_VALUE_TYPE(switches::kV8PacMojoOutOfProcess,
+                              switches::kDisableOutOfProcessPac)
   },
 #if defined(ENABLE_MEDIA_ROUTER)
   {
@@ -2404,6 +2405,15 @@
     kOsAll,
     SINGLE_VALUE_TYPE(switches::kDisableNewVideoRenderer)
   },
+#if defined(OS_CHROMEOS)
+  {
+    "enable-printer-app-search",
+    IDS_FLAGS_PRINTER_PROVIDER_SEARCH_APP_NAME,
+    IDS_FLAGS_PRINTER_PROVIDER_SEARCH_APP_DESCRIPTION,
+    kOsCrOS,
+    SINGLE_VALUE_TYPE(chromeos::switches::kEnablePrinterAppSearch)
+  },
+#endif  // OS_CHROMEOS
   // Temporary flag to ease the transition to standard-compliant scrollTop
   // behavior.  Will be removed shortly after http://crbug.com/157855 ships.
   {
diff --git a/chrome/browser/android/password_ui_view_android.cc b/chrome/browser/android/password_ui_view_android.cc
index 2bd4850..7e0dd80b 100644
--- a/chrome/browser/android/password_ui_view_android.cc
+++ b/chrome/browser/android/password_ui_view_android.cc
@@ -11,6 +11,7 @@
 #include "base/prefs/pref_service.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/passwords/manage_passwords_view_utils.h"
+#include "chrome/browser/ui/passwords/password_bubble_experiment.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
 #include "components/autofill/core/common/password_form.h"
@@ -114,6 +115,12 @@
   return password_manager::ManageAccountLinkExperimentEnabled();
 }
 
+static jboolean ShouldUseSmartLockBranding(
+    JNIEnv* env, jclass) {
+  return password_bubble_experiment::IsSmartLockBrandingEnabled(
+      ProfileManager::GetLastUsedProfile());
+}
+
 // static
 static jlong Init(JNIEnv* env, jobject obj) {
   PasswordUIViewAndroid* controller = new PasswordUIViewAndroid(env, obj);
diff --git a/chrome/browser/android/tab_android.cc b/chrome/browser/android/tab_android.cc
index a0e0cbaa7..fc37e028 100644
--- a/chrome/browser/android/tab_android.cc
+++ b/chrome/browser/android/tab_android.cc
@@ -752,6 +752,12 @@
   }
 }
 
+void TabAndroid::ShowOriginalImage(JNIEnv* env, jobject obj) {
+  content::RenderFrameHost* render_frame_host = web_contents()->GetMainFrame();
+  render_frame_host->Send(new ChromeViewMsg_RequestReloadImageForContextNode(
+      render_frame_host->GetRoutingID()));
+}
+
 void TabAndroid::SearchByImageInNewTabAsync(JNIEnv* env, jobject obj) {
   content::RenderFrameHost* render_frame_host =
         web_contents()->GetMainFrame();
diff --git a/chrome/browser/android/tab_android.h b/chrome/browser/android/tab_android.h
index 3ff8b9b..220ae3ba 100644
--- a/chrome/browser/android/tab_android.h
+++ b/chrome/browser/android/tab_android.h
@@ -191,6 +191,8 @@
                               jint current,
                               jboolean animate);
 
+  void ShowOriginalImage(JNIEnv* env, jobject obj);
+
   void SearchByImageInNewTabAsync(JNIEnv* env, jobject obj);
 
   jlong GetBookmarkId(JNIEnv* env, jobject obj, jboolean only_editable);
diff --git a/chrome/browser/apps/custom_launcher_page_browsertest_views.cc b/chrome/browser/apps/custom_launcher_page_browsertest_views.cc
index 6ac62479..f39ec2e 100644
--- a/chrome/browser/apps/custom_launcher_page_browsertest_views.cc
+++ b/chrome/browser/apps/custom_launcher_page_browsertest_views.cc
@@ -315,10 +315,11 @@
       contents_view->IsStateActive(app_list::AppListModel::STATE_START));
 }
 
-IN_PROC_BROWSER_TEST_F(CustomLauncherPageBrowserTest,
-                       LauncherPageShow) {
+IN_PROC_BROWSER_TEST_F(CustomLauncherPageBrowserTest, LauncherPageShowAndHide) {
   const base::string16 kLauncherPageShowScript =
       base::ASCIIToUTF16("chrome.launcherPage.show();");
+  const base::string16 kLauncherPageHideScript =
+      base::ASCIIToUTF16("hideCustomLauncherPage()");
 
   LoadAndLaunchPlatformApp(kCustomLauncherPagePath, "Launched");
   app_list::AppListView* app_list_view = GetAppListView();
@@ -362,6 +363,29 @@
     EXPECT_TRUE(contents_view->IsStateActive(
         app_list::AppListModel::STATE_CUSTOM_LAUNCHER_PAGE));
   }
+
+  // Ensure launcherPage.hide() hides the launcher page when it's showing.
+  {
+    ExtensionTestMessageListener listener("onPageProgressAt0", false);
+    custom_page_frame->ExecuteJavaScript(kLauncherPageHideScript);
+
+    listener.WaitUntilSatisfied();
+
+    EXPECT_TRUE(
+        contents_view->IsStateActive(app_list::AppListModel::STATE_START));
+  }
+
+  // Nothing should happen if hide() is called from the apps page.
+  {
+    contents_view->SetActiveState(app_list::AppListModel::STATE_APPS, false);
+
+    ExtensionTestMessageListener listener("launcherPageHidden", false);
+    custom_page_frame->ExecuteJavaScript(kLauncherPageHideScript);
+    listener.WaitUntilSatisfied();
+
+    EXPECT_TRUE(
+        contents_view->IsStateActive(app_list::AppListModel::STATE_APPS));
+  }
 }
 
 IN_PROC_BROWSER_TEST_F(CustomLauncherPageBrowserTest, LauncherPageSetEnabled) {
diff --git a/chrome/browser/apps/guest_view/web_view_browsertest.cc b/chrome/browser/apps/guest_view/web_view_browsertest.cc
index 6fbd4c0..3920397 100644
--- a/chrome/browser/apps/guest_view/web_view_browsertest.cc
+++ b/chrome/browser/apps/guest_view/web_view_browsertest.cc
@@ -2139,17 +2139,17 @@
   EXPECT_FALSE(
       chromeos::AccessibilityManager::Get()->IsSpokenFeedbackEnabled());
 
+  chromeos::SpeechMonitor monitor;
+  chromeos::AccessibilityManager::Get()->EnableSpokenFeedback(
+      true, ui::A11Y_NOTIFICATION_NONE);
+  EXPECT_TRUE(monitor.SkipChromeVoxEnabledMessage());
+
   ASSERT_TRUE(StartEmbeddedTestServer());
   content::WebContents* guest_web_contents = LoadGuest(
       "/extensions/platform_apps/web_view/chromevox_injection/guest.html",
       "web_view/chromevox_injection");
   ASSERT_TRUE(guest_web_contents);
 
-  chromeos::SpeechMonitor monitor;
-  chromeos::AccessibilityManager::Get()->EnableSpokenFeedback(
-      true, ui::A11Y_NOTIFICATION_NONE);
-  EXPECT_TRUE(monitor.SkipChromeVoxEnabledMessage());
-
   EXPECT_EQ("chrome vox test title", monitor.GetNextUtterance());
 }
 #endif
diff --git a/chrome/browser/autocomplete/history_quick_provider.cc b/chrome/browser/autocomplete/history_quick_provider.cc
index 57c86ae..1871bf2 100644
--- a/chrome/browser/autocomplete/history_quick_provider.cc
+++ b/chrome/browser/autocomplete/history_quick_provider.cc
@@ -12,12 +12,10 @@
 #include "base/i18n/break_iterator.h"
 #include "base/logging.h"
 #include "base/metrics/field_trial.h"
-#include "base/metrics/histogram.h"
 #include "base/prefs/pref_service.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time/time.h"
 #include "chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.h"
 #include "chrome/browser/autocomplete/history_url_provider.h"
 #include "chrome/browser/autocomplete/in_memory_url_index.h"
@@ -75,16 +73,7 @@
   // someone unloads the history backend, we'll get inconsistent inline
   // autocomplete behavior here.
   if (in_memory_url_index_) {
-    base::TimeTicks start_time = base::TimeTicks::Now();
     DoAutocomplete();
-    if (input.text().length() < 6) {
-      base::TimeTicks end_time = base::TimeTicks::Now();
-      std::string name = "HistoryQuickProvider.QueryIndexTime." +
-          base::IntToString(input.text().length());
-      base::HistogramBase* counter = base::Histogram::FactoryGet(
-          name, 1, 1000, 50, base::Histogram::kUmaTargetedHistogramFlag);
-      counter->Add(static_cast<int>((end_time - start_time).InMilliseconds()));
-    }
   }
 }
 
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd
index e275dca..ed14ec7 100644
--- a/chrome/browser/browser_resources.grd
+++ b/chrome/browser/browser_resources.grd
@@ -279,13 +279,6 @@
       <if expr="enable_google_now">
         <include name="IDR_GOOGLE_NOW_MANIFEST" file="resources\google_now\manifest.json" type="BINDATA" />
       </if>
-      <if expr="not is_android">
-        <include name="IDR_SUGGESTIONS_INTERNALS_HTML" file="resources\suggestions_internals\suggestions_internals.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
-        <include name="IDR_SUGGESTIONS_INTERNALS_CSS" file="resources\suggestions_internals\suggestions_internals.css" type="BINDATA" />
-        <include name="IDR_SUGGESTIONS_INTERNALS_JS" file="resources\suggestions_internals\suggestions_internals.js" type="BINDATA" />
-        <include name="IDR_SUGGESTIONS_PAGE_CSS" file="resources\ntp4\suggestions_page.css" type="BINDATA" />
-        <include name="IDR_SUGGESTIONS_PAGE_JS" file="resources\ntp4\suggestions_page.js" type="BINDATA" />
-      </if>
       <include name="IDR_UBER_HTML" file="resources\uber\uber.html" flattenhtml="true" type="BINDATA" />
       <include name="IDR_UBER_JS" file="resources\uber\uber.js" type="BINDATA" />
       <include name="IDR_UBER_FRAME_HTML" file="resources\uber\uber_frame.html" flattenhtml="true" type="BINDATA" />
diff --git a/chrome/browser/caps/generate_state_json.cc b/chrome/browser/caps/generate_state_json.cc
index 3857d27..41a2a5d 100644
--- a/chrome/browser/caps/generate_state_json.cc
+++ b/chrome/browser/caps/generate_state_json.cc
@@ -90,7 +90,7 @@
 
     std::string json;
     auto options = base::JSONWriter::OPTIONS_PRETTY_PRINT;
-    if (!base::JSONWriter::WriteWithOptions(&dict, options, &json))
+    if (!base::JSONWriter::WriteWithOptions(dict, options, &json))
       return;
 
     file_.WriteAtCurrentPos(json.c_str(), json.size());
diff --git a/chrome/browser/chromeos/app_mode/kiosk_app_data.cc b/chrome/browser/chromeos/app_mode/kiosk_app_data.cc
index 5245aad4..22d73d3 100644
--- a/chrome/browser/chromeos/app_mode/kiosk_app_data.cc
+++ b/chrome/browser/chromeos/app_mode/kiosk_app_data.cc
@@ -76,7 +76,7 @@
   return false;
 }
 
-std::string ValueToString(const base::Value* value) {
+std::string ValueToString(const base::Value& value) {
   std::string json;
   base::JSONWriter::Write(value, &json);
   return json;
@@ -602,7 +602,7 @@
       icon_url_string);
   if (!icon_url.is_valid()) {
     LOG(ERROR) << "Webstore response error (icon url): "
-               << ValueToString(webstore_data.get());
+               << ValueToString(*webstore_data);
     OnWebstoreResponseParseFailure(kInvalidWebstoreResponseError);
     return;
   }
@@ -626,7 +626,7 @@
                                          std::string* value) {
   if (!response->GetString(key, value)) {
     LOG(ERROR) << "Webstore response error (" << key
-               << "): " << ValueToString(response);
+               << "): " << ValueToString(*response);
     OnWebstoreResponseParseFailure(kInvalidWebstoreResponseError);
     return false;
   }
diff --git a/chrome/browser/chromeos/bluetooth/bluetooth_pairing_dialog.cc b/chrome/browser/chromeos/bluetooth/bluetooth_pairing_dialog.cc
index ff089f38..68712f28 100644
--- a/chrome/browser/chromeos/bluetooth/bluetooth_pairing_dialog.cc
+++ b/chrome/browser/chromeos/bluetooth/bluetooth_pairing_dialog.cc
@@ -76,7 +76,7 @@
 
 std::string BluetoothPairingDialog::GetDialogArgs() const {
   std::string data;
-  base::JSONWriter::Write(&device_data_, &data);
+  base::JSONWriter::Write(device_data_, &data);
   return data;
 }
 
diff --git a/chrome/browser/chromeos/boot_times_recorder.cc b/chrome/browser/chromeos/boot_times_recorder.cc
index e9a3cec..268aef6 100644
--- a/chrome/browser/chromeos/boot_times_recorder.cc
+++ b/chrome/browser/chromeos/boot_times_recorder.cc
@@ -152,7 +152,7 @@
   dictionary.SetString(kDisk, disk_);
 
   std::string result;
-  if (!base::JSONWriter::Write(&dictionary, &result)) {
+  if (!base::JSONWriter::Write(dictionary, &result)) {
     LOG(WARNING) << "BootTimesRecorder::Stats::SerializeToString(): failed.";
     return std::string();
   }
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
index ee6e257..a69241b 100644
--- a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
+++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
@@ -767,6 +767,9 @@
 
   g_browser_process->platform_part()->DestroyChromeUserManager();
 
+  // Make sure that there is no pending URLRequests.
+  UserSessionManager::GetInstance()->Shutdown();
+
   g_browser_process->platform_part()->ShutdownSessionManager();
 }
 
diff --git a/chrome/browser/chromeos/events/OWNERS b/chrome/browser/chromeos/events/OWNERS
new file mode 100644
index 0000000..3b4e32e6
--- /dev/null
+++ b/chrome/browser/chromeos/events/OWNERS
@@ -0,0 +1,3 @@
+sadrul@chromium.org
+
+per-file *event_rewriter* = kpschoedel@chromium.org
diff --git a/chrome/browser/chromeos/extensions/accessibility_features_apitest.cc b/chrome/browser/chromeos/extensions/accessibility_features_apitest.cc
index 8245a9e4..25765814 100644
--- a/chrome/browser/chromeos/extensions/accessibility_features_apitest.cc
+++ b/chrome/browser/chromeos/extensions/accessibility_features_apitest.cc
@@ -158,7 +158,7 @@
       disabled_list->AppendString(disabled_features[i]);
     test_arg.Set(kDisabledFeaturesKey, disabled_list.release());
 
-    return base::JSONWriter::Write(&test_arg, result);
+    return base::JSONWriter::Write(test_arg, result);
   }
 };
 
diff --git a/chrome/browser/chromeos/extensions/file_manager/file_manager_private_apitest.cc b/chrome/browser/chromeos/extensions/file_manager/file_manager_private_apitest.cc
index 32523c1..3653a7f5 100644
--- a/chrome/browser/chromeos/extensions/file_manager/file_manager_private_apitest.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/file_manager_private_apitest.cc
@@ -8,7 +8,9 @@
 #include "chrome/browser/chromeos/extensions/file_manager/event_router.h"
 #include "chrome/browser/chromeos/file_manager/drive_test_util.h"
 #include "chrome/browser/chromeos/file_manager/file_watcher.h"
+#include "chrome/browser/chromeos/file_system_provider/provided_file_system_info.h"
 #include "chrome/browser/extensions/extension_apitest.h"
+#include "chrome/common/extensions/api/file_system_provider_capabilities/file_system_provider_capabilities_handler.h"
 #include "chrome/test/base/testing_profile.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "chromeos/dbus/cros_disks_client.h"
@@ -311,6 +313,17 @@
   file_manager::test_util::WaitUntilDriveMountPointIsAdded(
       browser()->profile());
 
+  // Add a provided file system, to test passing the |configurable| and
+  // |source| flags properly down to Files app.
+  chromeos::file_system_provider::ProvidedFileSystemInfo info(
+      "testing-extension-id", chromeos::file_system_provider::MountOptions(),
+      base::FilePath(), true /* configurable */, extensions::SOURCE_NETWORK);
+
+  file_manager::VolumeManager::Get(browser()->profile())
+      ->AddVolumeForTesting(
+          make_linked_ptr(file_manager::Volume::CreateForProvidedFileSystem(
+              info, file_manager::MOUNT_CONTEXT_AUTO)));
+
   // We will call fileManagerPrivate.unmountVolume once. To test that method, we
   // check that UnmountPath is really called with the same value.
   EXPECT_CALL(*disk_mount_manager_mock_, UnmountPath(_, _, _))
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc
index 06e9cfa5..6cbc10b 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc
@@ -492,15 +492,14 @@
   return RespondNow(NoArguments());
 }
 
-FileManagerPrivateConfigureProvidedFileSystemFunction::
-    FileManagerPrivateConfigureProvidedFileSystemFunction()
+FileManagerPrivateConfigureVolumeFunction::
+    FileManagerPrivateConfigureVolumeFunction()
     : chrome_details_(this) {
 }
 
 ExtensionFunction::ResponseAction
-FileManagerPrivateConfigureProvidedFileSystemFunction::Run() {
-  using extensions::api::file_manager_private::ConfigureProvidedFileSystem::
-      Params;
+FileManagerPrivateConfigureVolumeFunction::Run() {
+  using extensions::api::file_manager_private::ConfigureVolume::Params;
   const scoped_ptr<Params> params(Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params);
 
@@ -512,24 +511,32 @@
       volume_manager->FindVolumeById(params->volume_id);
   if (!volume.get())
     return RespondNow(Error("Volume not found."));
+  if (!volume->configurable())
+    return RespondNow(Error("Volume not configurable."));
 
-  using chromeos::file_system_provider::Service;
-  Service* const service = Service::Get(chrome_details_.GetProfile());
-  DCHECK(service);
+  switch (volume->type()) {
+    case file_manager::VOLUME_TYPE_PROVIDED: {
+      using chromeos::file_system_provider::Service;
+      Service* const service = Service::Get(chrome_details_.GetProfile());
+      DCHECK(service);
 
-  using chromeos::file_system_provider::ProvidedFileSystemInterface;
-  ProvidedFileSystemInterface* const file_system =
-      service->GetProvidedFileSystem(volume->extension_id(),
-                                     volume->file_system_id());
-  DCHECK(file_system);
+      using chromeos::file_system_provider::ProvidedFileSystemInterface;
+      ProvidedFileSystemInterface* const file_system =
+          service->GetProvidedFileSystem(volume->extension_id(),
+                                         volume->file_system_id());
+      if (file_system)
+        file_system->Configure(base::Bind(
+            &FileManagerPrivateConfigureVolumeFunction::OnCompleted, this));
+      break;
+    }
+    default:
+      NOTIMPLEMENTED();
+  }
 
-  file_system->Configure(base::Bind(
-      &FileManagerPrivateConfigureProvidedFileSystemFunction::OnCompleted,
-      this));
   return RespondLater();
 }
 
-void FileManagerPrivateConfigureProvidedFileSystemFunction::OnCompleted(
+void FileManagerPrivateConfigureVolumeFunction::OnCompleted(
     base::File::Error result) {
   if (result != base::File::FILE_OK) {
     Respond(Error("Failed to complete configuration."));
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_misc.h b/chrome/browser/chromeos/extensions/file_manager/private_api_misc.h
index c744bf43..e681280 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_misc.h
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_misc.h
@@ -225,23 +225,22 @@
   DISALLOW_COPY_AND_ASSIGN(FileManagerPrivateAddProvidedFileSystemFunction);
 };
 
-// Implements the chrome.fileManagerPrivate.addProvidedFileSystem method.
-class FileManagerPrivateConfigureProvidedFileSystemFunction
+// Implements the chrome.fileManagerPrivate.configureVolume method.
+class FileManagerPrivateConfigureVolumeFunction
     : public UIThreadExtensionFunction {
  public:
-  FileManagerPrivateConfigureProvidedFileSystemFunction();
-  DECLARE_EXTENSION_FUNCTION("fileManagerPrivate.configureProvidedFileSystem",
-                             FILEMANAGERPRIVATE_CONFIGUREPROVIDEDFILESYSTEM)
+  FileManagerPrivateConfigureVolumeFunction();
+  DECLARE_EXTENSION_FUNCTION("fileManagerPrivate.configureVolume",
+                             FILEMANAGERPRIVATE_CONFIGUREVOLUME)
  protected:
-  ~FileManagerPrivateConfigureProvidedFileSystemFunction() override {}
+  ~FileManagerPrivateConfigureVolumeFunction() override {}
 
  private:
   ResponseAction Run() override;
   void OnCompleted(base::File::Error result);
 
   const ChromeExtensionFunctionDetails chrome_details_;
-  DISALLOW_COPY_AND_ASSIGN(
-      FileManagerPrivateConfigureProvidedFileSystemFunction);
+  DISALLOW_COPY_AND_ASSIGN(FileManagerPrivateConfigureVolumeFunction);
 };
 
 }  // namespace extensions
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_util.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_util.cc
index fdcfdc6..9447ae6 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_util.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_util.cc
@@ -182,6 +182,25 @@
         new std::string(volume.source_path().AsUTF8Unsafe()));
   }
 
+  switch (volume.source()) {
+    case SOURCE_FILE:
+      volume_metadata->source = file_manager_private::SOURCE_FILE;
+      break;
+    case SOURCE_DEVICE:
+      volume_metadata->source = file_manager_private::SOURCE_DEVICE;
+      break;
+    case SOURCE_NETWORK:
+      volume_metadata->source =
+          extensions::api::file_manager_private::SOURCE_NETWORK;
+      break;
+    case SOURCE_SYSTEM:
+      volume_metadata->source =
+          extensions::api::file_manager_private::SOURCE_SYSTEM;
+      break;
+  }
+
+  volume_metadata->configurable = volume.configurable();
+
   if (volume.type() == VOLUME_TYPE_PROVIDED) {
     volume_metadata->extension_id.reset(new std::string(volume.extension_id()));
     volume_metadata->file_system_id.reset(
diff --git a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
index 1aa481f..f4aab53c 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
+++ b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
@@ -681,13 +681,15 @@
 
   if (name == "getRootPaths") {
     // Pass the root paths.
-    const scoped_ptr<base::DictionaryValue> res(new base::DictionaryValue());
-    res->SetString("downloads",
-        "/" + util::GetDownloadsMountPointName(profile()));
-    res->SetString("drive",
-        "/" + drive::util::GetDriveMountPointPath(profile()
-            ).BaseName().AsUTF8Unsafe() + "/root");
-    base::JSONWriter::Write(res.get(), output);
+    base::DictionaryValue res;
+    res.SetString("downloads",
+                  "/" + util::GetDownloadsMountPointName(profile()));
+    res.SetString("drive", "/" +
+                               drive::util::GetDriveMountPointPath(profile())
+                                   .BaseName()
+                                   .AsUTF8Unsafe() +
+                               "/root");
+    base::JSONWriter::Write(res, output);
     return;
   }
 
@@ -707,10 +709,10 @@
     if (*origin.rbegin() == '/')
       origin.resize(origin.length() - 1);
 
-    const scoped_ptr<base::DictionaryValue> res(new base::DictionaryValue());
-    res->SetString("url", url.spec());
-    res->SetString("origin", origin);
-    base::JSONWriter::Write(res.get(), output);
+    base::DictionaryValue res;
+    res.SetString("url", url.spec());
+    res.SetString("origin", origin);
+    base::JSONWriter::Write(res, output);
     return;
   }
 
diff --git a/chrome/browser/chromeos/file_manager/url_util.cc b/chrome/browser/chromeos/file_manager/url_util.cc
index 088751b..1f3e9d86 100644
--- a/chrome/browser/chromeos/file_manager/url_util.cc
+++ b/chrome/browser/chromeos/file_manager/url_util.cc
@@ -111,7 +111,7 @@
                        !file_types || !file_types->support_drive);
 
   std::string json_args;
-  base::JSONWriter::Write(&arg_value, &json_args);
+  base::JSONWriter::Write(arg_value, &json_args);
 
   std::string url = GetFileManagerMainPageUrl().spec() + '?' +
       net::EscapeUrlEncodedData(json_args,
diff --git a/chrome/browser/chromeos/file_manager/url_util_unittest.cc b/chrome/browser/chromeos/file_manager/url_util_unittest.cc
index 1360d00..569617dc 100644
--- a/chrome/browser/chromeos/file_manager/url_util_unittest.cc
+++ b/chrome/browser/chromeos/file_manager/url_util_unittest.cc
@@ -23,9 +23,8 @@
       query, net::UnescapeRule::SPACES | net::UnescapeRule::URL_SPECIAL_CHARS);
   scoped_ptr<base::Value> value(base::JSONReader::Read(json));
   std::string pretty_json;
-  base::JSONWriter::WriteWithOptions(value.get(),
-                                     base::JSONWriter::OPTIONS_PRETTY_PRINT,
-                                     &pretty_json);
+  base::JSONWriter::WriteWithOptions(
+      *value, base::JSONWriter::OPTIONS_PRETTY_PRINT, &pretty_json);
   return pretty_json;
 }
 
diff --git a/chrome/browser/chromeos/file_manager/volume_manager.cc b/chrome/browser/chromeos/file_manager/volume_manager.cc
index 6f0e6efb..e03e5bc 100644
--- a/chrome/browser/chromeos/file_manager/volume_manager.cc
+++ b/chrome/browser/chromeos/file_manager/volume_manager.cc
@@ -130,13 +130,15 @@
 }  // namespace
 
 Volume::Volume()
-    : type_(VOLUME_TYPE_GOOGLE_DRIVE),
+    : source_(SOURCE_FILE),
+      type_(VOLUME_TYPE_GOOGLE_DRIVE),
       device_type_(chromeos::DEVICE_TYPE_UNKNOWN),
       mount_condition_(chromeos::disks::MOUNT_CONDITION_NONE),
       mount_context_(MOUNT_CONTEXT_UNKNOWN),
       is_parent_(false),
       is_read_only_(false),
-      has_media_(false) {
+      has_media_(false),
+      configurable_(false) {
 }
 
 Volume::~Volume() {
@@ -150,11 +152,9 @@
   volume->type_ = VOLUME_TYPE_GOOGLE_DRIVE;
   volume->device_type_ = chromeos::DEVICE_TYPE_UNKNOWN;
   volume->source_path_ = drive_path;
+  volume->source_ = SOURCE_NETWORK;
   volume->mount_path_ = drive_path;
   volume->mount_condition_ = chromeos::disks::MOUNT_CONDITION_NONE;
-  volume->is_parent_ = false;
-  volume->is_read_only_ = false;
-  volume->has_media_ = false;
   volume->volume_id_ = GenerateVolumeId(*volume);
   return volume;
 }
@@ -165,11 +165,9 @@
   volume->type_ = VOLUME_TYPE_DOWNLOADS_DIRECTORY;
   volume->device_type_ = chromeos::DEVICE_TYPE_UNKNOWN;
   // Keep source_path empty.
+  volume->source_ = SOURCE_SYSTEM;
   volume->mount_path_ = downloads_path;
   volume->mount_condition_ = chromeos::disks::MOUNT_CONDITION_NONE;
-  volume->is_parent_ = false;
-  volume->is_read_only_ = false;
-  volume->has_media_ = false;
   volume->volume_id_ = GenerateVolumeId(*volume);
   return volume;
 }
@@ -181,6 +179,9 @@
   Volume* const volume = new Volume;
   volume->type_ = MountTypeToVolumeType(mount_point.mount_type);
   volume->source_path_ = base::FilePath(mount_point.source_path);
+  volume->source_ = mount_point.mount_type == chromeos::MOUNT_TYPE_ARCHIVE
+                        ? SOURCE_FILE
+                        : SOURCE_DEVICE;
   volume->mount_path_ = base::FilePath(mount_point.mount_path);
   volume->mount_condition_ = mount_point.mount_condition;
   volume->volume_label_ = volume->mount_path().BaseName().AsUTF8Unsafe();
@@ -192,10 +193,8 @@
     volume->has_media_ = disk->has_media();
   } else {
     volume->device_type_ = chromeos::DEVICE_TYPE_UNKNOWN;
-    volume->is_parent_ = false;
     volume->is_read_only_ =
         (mount_point.mount_type == chromeos::MOUNT_TYPE_ARCHIVE);
-    volume->has_media_ = false;
   }
   volume->volume_id_ = GenerateVolumeId(*volume);
   return volume;
@@ -209,6 +208,17 @@
   Volume* const volume = new Volume;
   volume->file_system_id_ = file_system_info.file_system_id();
   volume->extension_id_ = file_system_info.extension_id();
+  switch (file_system_info.source()) {
+    case extensions::SOURCE_FILE:
+      volume->source_ = SOURCE_FILE;
+      break;
+    case extensions::SOURCE_DEVICE:
+      volume->source_ = SOURCE_DEVICE;
+      break;
+    case extensions::SOURCE_NETWORK:
+      volume->source_ = SOURCE_NETWORK;
+      break;
+  }
   volume->volume_label_ = file_system_info.display_name();
   volume->type_ = VOLUME_TYPE_PROVIDED;
   volume->mount_path_ = file_system_info.mount_path();
@@ -216,7 +226,7 @@
   volume->mount_context_ = mount_context;
   volume->is_parent_ = true;
   volume->is_read_only_ = !file_system_info.writable();
-  volume->has_media_ = false;
+  volume->configurable_ = file_system_info.configurable();
   volume->volume_id_ = GenerateVolumeId(*volume);
   return volume;
 }
@@ -234,6 +244,7 @@
   volume->volume_id_ = kMtpVolumeIdPrefix + label;
   volume->volume_label_ = label;
   volume->source_path_ = mount_path;
+  volume->source_ = SOURCE_DEVICE;
   volume->device_type_ = chromeos::DEVICE_TYPE_MOBILE;
   return volume;
 }
@@ -247,11 +258,10 @@
   volume->type_ = volume_type;
   volume->device_type_ = device_type;
   // Keep source_path empty.
+  volume->source_ = SOURCE_DEVICE;
   volume->mount_path_ = path;
   volume->mount_condition_ = chromeos::disks::MOUNT_CONDITION_NONE;
-  volume->is_parent_ = false;
   volume->is_read_only_ = read_only;
-  volume->has_media_ = false;
   volume->volume_id_ = GenerateVolumeId(*volume);
   return volume;
 }
@@ -421,6 +431,11 @@
                    path, volume_type, device_type, read_only)));
 }
 
+void VolumeManager::AddVolumeForTesting(const linked_ptr<Volume>& volume) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  DoMountEvent(chromeos::MOUNT_ERROR_NONE, volume);
+}
+
 void VolumeManager::OnFileSystemMounted() {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
@@ -785,7 +800,7 @@
 }
 
 void VolumeManager::DoMountEvent(chromeos::MountError error_code,
-                                 linked_ptr<Volume> volume) {
+                                 const linked_ptr<Volume>& volume) {
   // Archive files are mounted globally in system. We however don't want to show
   // archives from profile-specific folders (Drive/Downloads) of other users in
   // multi-profile session. To this end, we filter out archives not on the
@@ -821,7 +836,7 @@
 }
 
 void VolumeManager::DoUnmountEvent(chromeos::MountError error_code,
-                                   linked_ptr<Volume> volume) {
+                                   const linked_ptr<Volume>& volume) {
   if (mounted_volumes_.find(volume->volume_id()) == mounted_volumes_.end())
     return;
   if (error_code == chromeos::MOUNT_ERROR_NONE)
diff --git a/chrome/browser/chromeos/file_manager/volume_manager.h b/chrome/browser/chromeos/file_manager/volume_manager.h
index efaf20f..2e19149 100644
--- a/chrome/browser/chromeos/file_manager/volume_manager.h
+++ b/chrome/browser/chromeos/file_manager/volume_manager.h
@@ -66,6 +66,9 @@
   MOUNT_CONTEXT_UNKNOWN
 };
 
+// Source of a volume's data.
+enum Source { SOURCE_FILE, SOURCE_DEVICE, SOURCE_NETWORK, SOURCE_SYSTEM };
+
 // Represents a volume (mount point) in the volume manager. Validity of the data
 // is guaranteed by the weak pointer. Simply saying, the weak pointer should be
 // valid as long as the volume is mounted.
@@ -97,6 +100,7 @@
   const std::string& volume_id() const { return volume_id_; }
   const std::string& file_system_id() const { return file_system_id_; }
   const std::string& extension_id() const { return extension_id_; }
+  Source source() const { return source_; }
   VolumeType type() const { return type_; }
   chromeos::DeviceType device_type() const { return device_type_; }
   const base::FilePath& source_path() const { return source_path_; }
@@ -112,6 +116,7 @@
   bool is_parent() const { return is_parent_; }
   bool is_read_only() const { return is_read_only_; }
   bool has_media() const { return has_media_; }
+  bool configurable() const { return configurable_; }
 
  private:
   Volume();
@@ -127,6 +132,9 @@
   // to an empty string.
   std::string extension_id_;
 
+  // The source of the volume's data.
+  Source source_;
+
   // The type of mounted volume.
   VolumeType type_;
 
@@ -170,6 +178,9 @@
   // True if the volume contains media.
   bool has_media_;
 
+  // True if the volume is configurable.
+  bool configurable_;
+
   DISALLOW_COPY_AND_ASSIGN(Volume);
 };
 
@@ -228,6 +239,9 @@
                            chromeos::DeviceType device_type,
                            bool read_only);
 
+  // For testing purpose, adds the volume info to the volume manager.
+  void AddVolumeForTesting(const linked_ptr<Volume>& volume);
+
   // drive::DriveIntegrationServiceObserver overrides.
   void OnFileSystemMounted() override;
   void OnFileSystemBeingUnmounted() override;
@@ -271,9 +285,10 @@
  private:
   void OnDiskMountManagerRefreshed(bool success);
   void OnStorageMonitorInitialized();
-  void DoMountEvent(chromeos::MountError error_code, linked_ptr<Volume> volume);
+  void DoMountEvent(chromeos::MountError error_code,
+                    const linked_ptr<Volume>& volume);
   void DoUnmountEvent(chromeos::MountError error_code,
-                      linked_ptr<Volume> volume);
+                      const linked_ptr<Volume>& volume);
 
   Profile* profile_;
   drive::DriveIntegrationService* drive_integration_service_;  // Not owned.
diff --git a/chrome/browser/chromeos/file_system_provider/mount_path_util_unittest.cc b/chrome/browser/chromeos/file_system_provider/mount_path_util_unittest.cc
index ae8be916..7c5ee2d8 100644
--- a/chrome/browser/chromeos/file_system_provider/mount_path_util_unittest.cc
+++ b/chrome/browser/chromeos/file_system_provider/mount_path_util_unittest.cc
@@ -15,6 +15,7 @@
 #include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
 #include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/common/extensions/api/file_system_provider_capabilities/file_system_provider_capabilities_handler.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile.h"
 #include "chrome/test/base/testing_profile_manager.h"
@@ -177,9 +178,9 @@
 
 TEST_F(FileSystemProviderMountPathUtilTest, Parser_WrongUrl) {
   const ProvidedFileSystemInfo file_system_info(
-      kExtensionId,
-      MountOptions(kFileSystemId, kDisplayName),
-      GetMountPath(profile_, kExtensionId, kFileSystemId));
+      kExtensionId, MountOptions(kFileSystemId, kDisplayName),
+      GetMountPath(profile_, kExtensionId, kFileSystemId),
+      false /* configurable */, extensions::SOURCE_FILE);
 
   const base::FilePath kFilePath = base::FilePath(FILE_PATH_LITERAL("/hello"));
   const storage::FileSystemURL url =
diff --git a/chrome/browser/chromeos/file_system_provider/operations/abort_unittest.cc b/chrome/browser/chromeos/file_system_provider/operations/abort_unittest.cc
index ad0c31c..27b016f54 100644
--- a/chrome/browser/chromeos/file_system_provider/operations/abort_unittest.cc
+++ b/chrome/browser/chromeos/file_system_provider/operations/abort_unittest.cc
@@ -14,6 +14,7 @@
 #include "chrome/browser/chromeos/file_system_provider/operations/test_util.h"
 #include "chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h"
 #include "chrome/common/extensions/api/file_system_provider.h"
+#include "chrome/common/extensions/api/file_system_provider_capabilities/file_system_provider_capabilities_handler.h"
 #include "chrome/common/extensions/api/file_system_provider_internal.h"
 #include "extensions/browser/event_router.h"
 #include "storage/browser/fileapi/async_file_util.h"
@@ -38,9 +39,8 @@
 
   void SetUp() override {
     file_system_info_ = ProvidedFileSystemInfo(
-        kExtensionId,
-        MountOptions(kFileSystemId, "" /* display_name */),
-        base::FilePath());
+        kExtensionId, MountOptions(kFileSystemId, "" /* display_name */),
+        base::FilePath(), false /* configurable */, extensions::SOURCE_FILE);
   }
 
   ProvidedFileSystemInfo file_system_info_;
diff --git a/chrome/browser/chromeos/file_system_provider/operations/add_watcher_unittest.cc b/chrome/browser/chromeos/file_system_provider/operations/add_watcher_unittest.cc
index 0707d533..c076b002 100644
--- a/chrome/browser/chromeos/file_system_provider/operations/add_watcher_unittest.cc
+++ b/chrome/browser/chromeos/file_system_provider/operations/add_watcher_unittest.cc
@@ -14,6 +14,7 @@
 #include "chrome/browser/chromeos/file_system_provider/operations/test_util.h"
 #include "chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h"
 #include "chrome/common/extensions/api/file_system_provider.h"
+#include "chrome/common/extensions/api/file_system_provider_capabilities/file_system_provider_capabilities_handler.h"
 #include "chrome/common/extensions/api/file_system_provider_internal.h"
 #include "extensions/browser/event_router.h"
 #include "storage/browser/fileapi/async_file_util.h"
@@ -39,9 +40,8 @@
 
   void SetUp() override {
     file_system_info_ = ProvidedFileSystemInfo(
-        kExtensionId,
-        MountOptions(kFileSystemId, "" /* display_name */),
-        base::FilePath());
+        kExtensionId, MountOptions(kFileSystemId, "" /* display_name */),
+        base::FilePath(), false /* configurable */, extensions::SOURCE_FILE);
   }
 
   ProvidedFileSystemInfo file_system_info_;
diff --git a/chrome/browser/chromeos/file_system_provider/operations/close_file_unittest.cc b/chrome/browser/chromeos/file_system_provider/operations/close_file_unittest.cc
index 2be3706..e46657f 100644
--- a/chrome/browser/chromeos/file_system_provider/operations/close_file_unittest.cc
+++ b/chrome/browser/chromeos/file_system_provider/operations/close_file_unittest.cc
@@ -13,6 +13,7 @@
 #include "chrome/browser/chromeos/file_system_provider/operations/test_util.h"
 #include "chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h"
 #include "chrome/common/extensions/api/file_system_provider.h"
+#include "chrome/common/extensions/api/file_system_provider_capabilities/file_system_provider_capabilities_handler.h"
 #include "chrome/common/extensions/api/file_system_provider_internal.h"
 #include "extensions/browser/event_router.h"
 #include "storage/browser/fileapi/async_file_util.h"
@@ -37,9 +38,8 @@
 
   void SetUp() override {
     file_system_info_ = ProvidedFileSystemInfo(
-        kExtensionId,
-        MountOptions(kFileSystemId, "" /* display_name */),
-        base::FilePath());
+        kExtensionId, MountOptions(kFileSystemId, "" /* display_name */),
+        base::FilePath(), false /* configurable */, extensions::SOURCE_FILE);
   }
 
   ProvidedFileSystemInfo file_system_info_;
diff --git a/chrome/browser/chromeos/file_system_provider/operations/configure_unittest.cc b/chrome/browser/chromeos/file_system_provider/operations/configure_unittest.cc
index 984ca847..03b52a626 100644
--- a/chrome/browser/chromeos/file_system_provider/operations/configure_unittest.cc
+++ b/chrome/browser/chromeos/file_system_provider/operations/configure_unittest.cc
@@ -13,6 +13,7 @@
 #include "chrome/browser/chromeos/file_system_provider/operations/test_util.h"
 #include "chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h"
 #include "chrome/common/extensions/api/file_system_provider.h"
+#include "chrome/common/extensions/api/file_system_provider_capabilities/file_system_provider_capabilities_handler.h"
 #include "chrome/common/extensions/api/file_system_provider_internal.h"
 #include "extensions/browser/event_router.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -36,7 +37,7 @@
   void SetUp() override {
     file_system_info_ = ProvidedFileSystemInfo(
         kExtensionId, MountOptions(kFileSystemId, "" /* display_name */),
-        base::FilePath());
+        base::FilePath(), false /* configurable */, extensions::SOURCE_FILE);
   }
 
   ProvidedFileSystemInfo file_system_info_;
diff --git a/chrome/browser/chromeos/file_system_provider/operations/copy_entry_unittest.cc b/chrome/browser/chromeos/file_system_provider/operations/copy_entry_unittest.cc
index 8a5654ed..f864780 100644
--- a/chrome/browser/chromeos/file_system_provider/operations/copy_entry_unittest.cc
+++ b/chrome/browser/chromeos/file_system_provider/operations/copy_entry_unittest.cc
@@ -14,6 +14,7 @@
 #include "chrome/browser/chromeos/file_system_provider/operations/test_util.h"
 #include "chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h"
 #include "chrome/common/extensions/api/file_system_provider.h"
+#include "chrome/common/extensions/api/file_system_provider_capabilities/file_system_provider_capabilities_handler.h"
 #include "chrome/common/extensions/api/file_system_provider_internal.h"
 #include "extensions/browser/event_router.h"
 #include "storage/browser/fileapi/async_file_util.h"
@@ -42,8 +43,9 @@
   void SetUp() override {
     MountOptions mount_options(kFileSystemId, "" /* display_name */);
     mount_options.writable = true;
-    file_system_info_ =
-        ProvidedFileSystemInfo(kExtensionId, mount_options, base::FilePath());
+    file_system_info_ = ProvidedFileSystemInfo(
+        kExtensionId, mount_options, base::FilePath(), false /* configurable */,
+        extensions::SOURCE_FILE);
   }
 
   ProvidedFileSystemInfo file_system_info_;
@@ -102,9 +104,9 @@
   util::StatusCallbackLog callback_log;
 
   const ProvidedFileSystemInfo read_only_file_system_info(
-      kExtensionId,
-      MountOptions(kFileSystemId, "" /* display_name */),
-      base::FilePath() /* mount_path */);
+      kExtensionId, MountOptions(kFileSystemId, "" /* display_name */),
+      base::FilePath() /* mount_path */, false /* configurable */,
+      extensions::SOURCE_FILE);
 
   CopyEntry copy_entry(NULL, read_only_file_system_info,
                        base::FilePath(kSourcePath), base::FilePath(kTargetPath),
diff --git a/chrome/browser/chromeos/file_system_provider/operations/create_directory_unittest.cc b/chrome/browser/chromeos/file_system_provider/operations/create_directory_unittest.cc
index c5d31797..d7d2274 100644
--- a/chrome/browser/chromeos/file_system_provider/operations/create_directory_unittest.cc
+++ b/chrome/browser/chromeos/file_system_provider/operations/create_directory_unittest.cc
@@ -14,6 +14,7 @@
 #include "chrome/browser/chromeos/file_system_provider/operations/test_util.h"
 #include "chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h"
 #include "chrome/common/extensions/api/file_system_provider.h"
+#include "chrome/common/extensions/api/file_system_provider_capabilities/file_system_provider_capabilities_handler.h"
 #include "chrome/common/extensions/api/file_system_provider_internal.h"
 #include "extensions/browser/event_router.h"
 #include "storage/browser/fileapi/async_file_util.h"
@@ -40,8 +41,9 @@
   void SetUp() override {
     MountOptions mount_options(kFileSystemId, "" /* display_name */);
     mount_options.writable = true;
-    file_system_info_ =
-        ProvidedFileSystemInfo(kExtensionId, mount_options, base::FilePath());
+    file_system_info_ = ProvidedFileSystemInfo(
+        kExtensionId, mount_options, base::FilePath(), false /* configurable */,
+        extensions::SOURCE_FILE);
   }
 
   ProvidedFileSystemInfo file_system_info_;
@@ -103,9 +105,9 @@
   util::StatusCallbackLog callback_log;
 
   const ProvidedFileSystemInfo read_only_file_system_info(
-      kExtensionId,
-      MountOptions(kFileSystemId, "" /* display_name */),
-      base::FilePath() /* mount_path */);
+      kExtensionId, MountOptions(kFileSystemId, "" /* display_name */),
+      base::FilePath() /* mount_path */, false /* configurable */,
+      extensions::SOURCE_FILE);
 
   CreateDirectory create_directory(
       NULL, read_only_file_system_info, base::FilePath(kDirectoryPath),
diff --git a/chrome/browser/chromeos/file_system_provider/operations/create_file_unittest.cc b/chrome/browser/chromeos/file_system_provider/operations/create_file_unittest.cc
index 3b38e0c..3e40b90 100644
--- a/chrome/browser/chromeos/file_system_provider/operations/create_file_unittest.cc
+++ b/chrome/browser/chromeos/file_system_provider/operations/create_file_unittest.cc
@@ -14,6 +14,7 @@
 #include "chrome/browser/chromeos/file_system_provider/operations/test_util.h"
 #include "chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h"
 #include "chrome/common/extensions/api/file_system_provider.h"
+#include "chrome/common/extensions/api/file_system_provider_capabilities/file_system_provider_capabilities_handler.h"
 #include "chrome/common/extensions/api/file_system_provider_internal.h"
 #include "extensions/browser/event_router.h"
 #include "storage/browser/fileapi/async_file_util.h"
@@ -40,8 +41,9 @@
   void SetUp() override {
     MountOptions mount_options(kFileSystemId, "" /* display_name */);
     mount_options.writable = true;
-    file_system_info_ =
-        ProvidedFileSystemInfo(kExtensionId, mount_options, base::FilePath());
+    file_system_info_ = ProvidedFileSystemInfo(
+        kExtensionId, mount_options, base::FilePath(), false /* configurable */,
+        extensions::SOURCE_FILE);
   }
 
   ProvidedFileSystemInfo file_system_info_;
@@ -98,9 +100,9 @@
   util::StatusCallbackLog callback_log;
 
   const ProvidedFileSystemInfo read_only_file_system_info(
-      kExtensionId,
-      MountOptions(kFileSystemId, "" /* display_name */),
-      base::FilePath() /* mount_path */);
+      kExtensionId, MountOptions(kFileSystemId, "" /* display_name */),
+      base::FilePath() /* mount_path */, false /* configurable */,
+      extensions::SOURCE_FILE);
 
   CreateFile create_file(NULL, read_only_file_system_info,
                          base::FilePath(kFilePath),
diff --git a/chrome/browser/chromeos/file_system_provider/operations/delete_entry_unittest.cc b/chrome/browser/chromeos/file_system_provider/operations/delete_entry_unittest.cc
index faaae1f..a7067e1 100644
--- a/chrome/browser/chromeos/file_system_provider/operations/delete_entry_unittest.cc
+++ b/chrome/browser/chromeos/file_system_provider/operations/delete_entry_unittest.cc
@@ -14,6 +14,7 @@
 #include "chrome/browser/chromeos/file_system_provider/operations/test_util.h"
 #include "chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h"
 #include "chrome/common/extensions/api/file_system_provider.h"
+#include "chrome/common/extensions/api/file_system_provider_capabilities/file_system_provider_capabilities_handler.h"
 #include "chrome/common/extensions/api/file_system_provider_internal.h"
 #include "extensions/browser/event_router.h"
 #include "storage/browser/fileapi/async_file_util.h"
@@ -40,8 +41,9 @@
   void SetUp() override {
     MountOptions mount_options(kFileSystemId, "" /* display_name */);
     mount_options.writable = true;
-    file_system_info_ =
-        ProvidedFileSystemInfo(kExtensionId, mount_options, base::FilePath());
+    file_system_info_ = ProvidedFileSystemInfo(
+        kExtensionId, mount_options, base::FilePath(), false /* configurable */,
+        extensions::SOURCE_FILE);
   }
 
   ProvidedFileSystemInfo file_system_info_;
@@ -101,9 +103,9 @@
   util::StatusCallbackLog callback_log;
 
   const ProvidedFileSystemInfo read_only_file_system_info(
-      kExtensionId,
-      MountOptions(kFileSystemId, "" /* display_name */),
-      base::FilePath() /* mount_path */);
+      kExtensionId, MountOptions(kFileSystemId, "" /* display_name */),
+      base::FilePath() /* mount_path */, false /* configurable */,
+      extensions::SOURCE_FILE);
 
   DeleteEntry delete_entry(NULL, read_only_file_system_info,
                            base::FilePath(kEntryPath), true /* recursive */,
diff --git a/chrome/browser/chromeos/file_system_provider/operations/get_metadata_unittest.cc b/chrome/browser/chromeos/file_system_provider/operations/get_metadata_unittest.cc
index 60e269a..f8f2545 100644
--- a/chrome/browser/chromeos/file_system_provider/operations/get_metadata_unittest.cc
+++ b/chrome/browser/chromeos/file_system_provider/operations/get_metadata_unittest.cc
@@ -14,6 +14,7 @@
 #include "base/values.h"
 #include "chrome/browser/chromeos/file_system_provider/operations/test_util.h"
 #include "chrome/common/extensions/api/file_system_provider.h"
+#include "chrome/common/extensions/api/file_system_provider_capabilities/file_system_provider_capabilities_handler.h"
 #include "chrome/common/extensions/api/file_system_provider_internal.h"
 #include "extensions/browser/event_router.h"
 #include "storage/browser/fileapi/async_file_util.h"
@@ -98,9 +99,8 @@
 
   void SetUp() override {
     file_system_info_ = ProvidedFileSystemInfo(
-        kExtensionId,
-        MountOptions(kFileSystemId, "" /* display_name */),
-        base::FilePath());
+        kExtensionId, MountOptions(kFileSystemId, "" /* display_name */),
+        base::FilePath(), false /* configurable */, extensions::SOURCE_FILE);
   }
 
   ProvidedFileSystemInfo file_system_info_;
diff --git a/chrome/browser/chromeos/file_system_provider/operations/move_entry_unittest.cc b/chrome/browser/chromeos/file_system_provider/operations/move_entry_unittest.cc
index 9ebce8d..63518205 100644
--- a/chrome/browser/chromeos/file_system_provider/operations/move_entry_unittest.cc
+++ b/chrome/browser/chromeos/file_system_provider/operations/move_entry_unittest.cc
@@ -14,6 +14,8 @@
 #include "chrome/browser/chromeos/file_system_provider/operations/test_util.h"
 #include "chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h"
 #include "chrome/common/extensions/api/file_system_provider.h"
+#include "chrome/common/extensions/api/file_system_provider_capabilities/file_system_provider_capabilities_handler.h"
+#include "chrome/common/extensions/api/file_system_provider_capabilities/file_system_provider_capabilities_handler.h"
 #include "chrome/common/extensions/api/file_system_provider_internal.h"
 #include "extensions/browser/event_router.h"
 #include "storage/browser/fileapi/async_file_util.h"
@@ -42,8 +44,9 @@
   void SetUp() override {
     MountOptions mount_options(kFileSystemId, "" /* display_name */);
     mount_options.writable = true;
-    file_system_info_ =
-        ProvidedFileSystemInfo(kExtensionId, mount_options, base::FilePath());
+    file_system_info_ = ProvidedFileSystemInfo(
+        kExtensionId, mount_options, base::FilePath(), false /* configurable */,
+        extensions::SOURCE_FILE);
   }
 
   ProvidedFileSystemInfo file_system_info_;
@@ -102,9 +105,9 @@
   util::StatusCallbackLog callback_log;
 
   const ProvidedFileSystemInfo read_only_file_system_info(
-      kExtensionId,
-      MountOptions(kFileSystemId, "" /* display_name */),
-      base::FilePath() /* mount_path */);
+      kExtensionId, MountOptions(kFileSystemId, "" /* display_name */),
+      base::FilePath() /* mount_path */, false /* configurable */,
+      extensions::SOURCE_FILE);
 
   MoveEntry move_entry(NULL, read_only_file_system_info,
                        base::FilePath(kSourcePath), base::FilePath(kTargetPath),
diff --git a/chrome/browser/chromeos/file_system_provider/operations/open_file_unittest.cc b/chrome/browser/chromeos/file_system_provider/operations/open_file_unittest.cc
index 8cc3088..f6bd6d9b 100644
--- a/chrome/browser/chromeos/file_system_provider/operations/open_file_unittest.cc
+++ b/chrome/browser/chromeos/file_system_provider/operations/open_file_unittest.cc
@@ -14,6 +14,7 @@
 #include "chrome/browser/chromeos/file_system_provider/operations/test_util.h"
 #include "chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h"
 #include "chrome/common/extensions/api/file_system_provider.h"
+#include "chrome/common/extensions/api/file_system_provider_capabilities/file_system_provider_capabilities_handler.h"
 #include "chrome/common/extensions/api/file_system_provider_internal.h"
 #include "extensions/browser/event_router.h"
 #include "storage/browser/fileapi/async_file_util.h"
@@ -73,9 +74,8 @@
 
   void SetUp() override {
     file_system_info_ = ProvidedFileSystemInfo(
-        kExtensionId,
-        MountOptions(kFileSystemId, "" /* display_name */),
-        base::FilePath());
+        kExtensionId, MountOptions(kFileSystemId, "" /* display_name */),
+        base::FilePath(), false /* configurable */, extensions::SOURCE_FILE);
   }
 
   ProvidedFileSystemInfo file_system_info_;
@@ -137,9 +137,9 @@
   CallbackLogger callback_logger;
 
   const ProvidedFileSystemInfo read_only_file_system_info(
-      kExtensionId,
-      MountOptions(kFileSystemId, "" /* display_name */),
-      base::FilePath() /* mount_path */);
+      kExtensionId, MountOptions(kFileSystemId, "" /* display_name */),
+      base::FilePath() /* mount_path */, false /* configurable */,
+      extensions::SOURCE_FILE);
 
   // Opening for read on a read-only file system is allowed.
   {
diff --git a/chrome/browser/chromeos/file_system_provider/operations/read_directory_unittest.cc b/chrome/browser/chromeos/file_system_provider/operations/read_directory_unittest.cc
index 3855147..ecf38a1 100644
--- a/chrome/browser/chromeos/file_system_provider/operations/read_directory_unittest.cc
+++ b/chrome/browser/chromeos/file_system_provider/operations/read_directory_unittest.cc
@@ -15,6 +15,7 @@
 #include "chrome/browser/chromeos/file_system_provider/operations/get_metadata.h"
 #include "chrome/browser/chromeos/file_system_provider/operations/test_util.h"
 #include "chrome/common/extensions/api/file_system_provider.h"
+#include "chrome/common/extensions/api/file_system_provider_capabilities/file_system_provider_capabilities_handler.h"
 #include "chrome/common/extensions/api/file_system_provider_internal.h"
 #include "extensions/browser/event_router.h"
 #include "storage/browser/fileapi/async_file_util.h"
@@ -102,9 +103,8 @@
 
   void SetUp() override {
     file_system_info_ = ProvidedFileSystemInfo(
-        kExtensionId,
-        MountOptions(kFileSystemId, "" /* display_name */),
-        base::FilePath());
+        kExtensionId, MountOptions(kFileSystemId, "" /* display_name */),
+        base::FilePath(), false /* configurable */, extensions::SOURCE_FILE);
   }
 
   ProvidedFileSystemInfo file_system_info_;
diff --git a/chrome/browser/chromeos/file_system_provider/operations/read_file_unittest.cc b/chrome/browser/chromeos/file_system_provider/operations/read_file_unittest.cc
index 6a83834..b9d28f2 100644
--- a/chrome/browser/chromeos/file_system_provider/operations/read_file_unittest.cc
+++ b/chrome/browser/chromeos/file_system_provider/operations/read_file_unittest.cc
@@ -14,6 +14,7 @@
 #include "base/values.h"
 #include "chrome/browser/chromeos/file_system_provider/operations/test_util.h"
 #include "chrome/common/extensions/api/file_system_provider.h"
+#include "chrome/common/extensions/api/file_system_provider_capabilities/file_system_provider_capabilities_handler.h"
 #include "chrome/common/extensions/api/file_system_provider_internal.h"
 #include "extensions/browser/event_router.h"
 #include "net/base/io_buffer.h"
@@ -77,9 +78,8 @@
 
   void SetUp() override {
     file_system_info_ = ProvidedFileSystemInfo(
-        kExtensionId,
-        MountOptions(kFileSystemId, "" /* display_name */),
-        base::FilePath());
+        kExtensionId, MountOptions(kFileSystemId, "" /* display_name */),
+        base::FilePath(), false /* configurable */, extensions::SOURCE_FILE);
     io_buffer_ = make_scoped_refptr(new net::IOBuffer(kOffset + kLength));
   }
 
diff --git a/chrome/browser/chromeos/file_system_provider/operations/remove_watcher_unittest.cc b/chrome/browser/chromeos/file_system_provider/operations/remove_watcher_unittest.cc
index d72fcef..56f488d7 100644
--- a/chrome/browser/chromeos/file_system_provider/operations/remove_watcher_unittest.cc
+++ b/chrome/browser/chromeos/file_system_provider/operations/remove_watcher_unittest.cc
@@ -14,6 +14,7 @@
 #include "chrome/browser/chromeos/file_system_provider/operations/test_util.h"
 #include "chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h"
 #include "chrome/common/extensions/api/file_system_provider.h"
+#include "chrome/common/extensions/api/file_system_provider_capabilities/file_system_provider_capabilities_handler.h"
 #include "chrome/common/extensions/api/file_system_provider_internal.h"
 #include "extensions/browser/event_router.h"
 #include "storage/browser/fileapi/async_file_util.h"
@@ -39,9 +40,8 @@
 
   void SetUp() override {
     file_system_info_ = ProvidedFileSystemInfo(
-        kExtensionId,
-        MountOptions(kFileSystemId, "" /* display_name */),
-        base::FilePath());
+        kExtensionId, MountOptions(kFileSystemId, "" /* display_name */),
+        base::FilePath(), false /* configurable */, extensions::SOURCE_FILE);
   }
 
   ProvidedFileSystemInfo file_system_info_;
diff --git a/chrome/browser/chromeos/file_system_provider/operations/truncate_unittest.cc b/chrome/browser/chromeos/file_system_provider/operations/truncate_unittest.cc
index 54012e5..6439602 100644
--- a/chrome/browser/chromeos/file_system_provider/operations/truncate_unittest.cc
+++ b/chrome/browser/chromeos/file_system_provider/operations/truncate_unittest.cc
@@ -14,6 +14,7 @@
 #include "chrome/browser/chromeos/file_system_provider/operations/test_util.h"
 #include "chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h"
 #include "chrome/common/extensions/api/file_system_provider.h"
+#include "chrome/common/extensions/api/file_system_provider_capabilities/file_system_provider_capabilities_handler.h"
 #include "chrome/common/extensions/api/file_system_provider_internal.h"
 #include "extensions/browser/event_router.h"
 #include "storage/browser/fileapi/async_file_util.h"
@@ -41,8 +42,9 @@
   void SetUp() override {
     MountOptions mount_options(kFileSystemId, "" /* display_name */);
     mount_options.writable = true;
-    file_system_info_ =
-        ProvidedFileSystemInfo(kExtensionId, mount_options, base::FilePath());
+    file_system_info_ = ProvidedFileSystemInfo(
+        kExtensionId, mount_options, base::FilePath(), false /* configurable */,
+        extensions::SOURCE_FILE);
   }
 
   ProvidedFileSystemInfo file_system_info_;
@@ -101,9 +103,9 @@
   util::StatusCallbackLog callback_log;
 
   const ProvidedFileSystemInfo read_only_file_system_info(
-      kExtensionId,
-      MountOptions(kFileSystemId, "" /* display_name */),
-      base::FilePath() /* mount_path */);
+      kExtensionId, MountOptions(kFileSystemId, "" /* display_name */),
+      base::FilePath() /* mount_path */, false /* configurable */,
+      extensions::SOURCE_FILE);
 
   Truncate truncate(NULL, file_system_info_, base::FilePath(kFilePath),
                     kTruncateLength,
diff --git a/chrome/browser/chromeos/file_system_provider/operations/unmount_unittest.cc b/chrome/browser/chromeos/file_system_provider/operations/unmount_unittest.cc
index e53bda4..4ae1f94 100644
--- a/chrome/browser/chromeos/file_system_provider/operations/unmount_unittest.cc
+++ b/chrome/browser/chromeos/file_system_provider/operations/unmount_unittest.cc
@@ -13,6 +13,7 @@
 #include "chrome/browser/chromeos/file_system_provider/operations/test_util.h"
 #include "chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h"
 #include "chrome/common/extensions/api/file_system_provider.h"
+#include "chrome/common/extensions/api/file_system_provider_capabilities/file_system_provider_capabilities_handler.h"
 #include "chrome/common/extensions/api/file_system_provider_internal.h"
 #include "extensions/browser/event_router.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -35,9 +36,8 @@
 
   void SetUp() override {
     file_system_info_ = ProvidedFileSystemInfo(
-        kExtensionId,
-        MountOptions(kFileSystemId, "" /* display_name */),
-        base::FilePath());
+        kExtensionId, MountOptions(kFileSystemId, "" /* display_name */),
+        base::FilePath(), false /* configurable */, extensions::SOURCE_FILE);
   }
 
   ProvidedFileSystemInfo file_system_info_;
diff --git a/chrome/browser/chromeos/file_system_provider/operations/write_file_unittest.cc b/chrome/browser/chromeos/file_system_provider/operations/write_file_unittest.cc
index f1aac0af..e6d576f 100644
--- a/chrome/browser/chromeos/file_system_provider/operations/write_file_unittest.cc
+++ b/chrome/browser/chromeos/file_system_provider/operations/write_file_unittest.cc
@@ -16,6 +16,7 @@
 #include "base/values.h"
 #include "chrome/browser/chromeos/file_system_provider/operations/test_util.h"
 #include "chrome/common/extensions/api/file_system_provider.h"
+#include "chrome/common/extensions/api/file_system_provider_capabilities/file_system_provider_capabilities_handler.h"
 #include "chrome/common/extensions/api/file_system_provider_internal.h"
 #include "extensions/browser/event_router.h"
 #include "net/base/io_buffer.h"
@@ -44,8 +45,9 @@
   void SetUp() override {
     MountOptions mount_options(kFileSystemId, "" /* display_name */);
     mount_options.writable = true;
-    file_system_info_ =
-        ProvidedFileSystemInfo(kExtensionId, mount_options, base::FilePath());
+    file_system_info_ = ProvidedFileSystemInfo(
+        kExtensionId, mount_options, base::FilePath(), false /* configurable */,
+        extensions::SOURCE_FILE);
     io_buffer_ = make_scoped_refptr(new net::StringIOBuffer(kWriteData));
   }
 
@@ -117,9 +119,9 @@
   util::StatusCallbackLog callback_log;
 
   const ProvidedFileSystemInfo read_only_file_system_info(
-      kExtensionId,
-      MountOptions(kFileSystemId, "" /* display_name */),
-      base::FilePath() /* mount_path */);
+      kExtensionId, MountOptions(kFileSystemId, "" /* display_name */),
+      base::FilePath() /* mount_path */, false /* configurable */,
+      extensions::SOURCE_FILE);
 
   WriteFile write_file(NULL,
                        read_only_file_system_info,
diff --git a/chrome/browser/chromeos/file_system_provider/provided_file_system_info.cc b/chrome/browser/chromeos/file_system_provider/provided_file_system_info.cc
index db8d82d..a35c5c5 100644
--- a/chrome/browser/chromeos/file_system_provider/provided_file_system_info.cc
+++ b/chrome/browser/chromeos/file_system_provider/provided_file_system_info.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "chrome/browser/chromeos/file_system_provider/provided_file_system_info.h"
+
 #include "base/logging.h"
 
 namespace chromeos {
@@ -24,20 +25,27 @@
 }
 
 ProvidedFileSystemInfo::ProvidedFileSystemInfo()
-    : writable_(false), supports_notify_tag_(false) {
+    : writable_(false),
+      supports_notify_tag_(false),
+      configurable_(false),
+      source_(extensions::SOURCE_FILE) {
 }
 
 ProvidedFileSystemInfo::ProvidedFileSystemInfo(
     const std::string& extension_id,
     const MountOptions& mount_options,
-    const base::FilePath& mount_path)
+    const base::FilePath& mount_path,
+    bool configurable,
+    extensions::FileSystemProviderSource source)
     : extension_id_(extension_id),
       file_system_id_(mount_options.file_system_id),
       display_name_(mount_options.display_name),
       writable_(mount_options.writable),
       supports_notify_tag_(mount_options.supports_notify_tag),
       opened_files_limit_(mount_options.opened_files_limit),
-      mount_path_(mount_path) {
+      mount_path_(mount_path),
+      configurable_(configurable),
+      source_(source) {
   DCHECK_LE(0, mount_options.opened_files_limit);
 }
 
diff --git a/chrome/browser/chromeos/file_system_provider/provided_file_system_info.h b/chrome/browser/chromeos/file_system_provider/provided_file_system_info.h
index 795577ce..f2b51e6e 100644
--- a/chrome/browser/chromeos/file_system_provider/provided_file_system_info.h
+++ b/chrome/browser/chromeos/file_system_provider/provided_file_system_info.h
@@ -8,6 +8,7 @@
 #include <string>
 
 #include "base/files/file_path.h"
+#include "chrome/common/extensions/api/file_system_provider_capabilities/file_system_provider_capabilities_handler.h"
 
 namespace chromeos {
 namespace file_system_provider {
@@ -34,7 +35,9 @@
 
   ProvidedFileSystemInfo(const std::string& extension_id,
                          const MountOptions& mount_options,
-                         const base::FilePath& mount_path);
+                         const base::FilePath& mount_path,
+                         bool configurable,
+                         extensions::FileSystemProviderSource source);
 
   ~ProvidedFileSystemInfo();
 
@@ -45,6 +48,8 @@
   bool supports_notify_tag() const { return supports_notify_tag_; }
   int opened_files_limit() const { return opened_files_limit_; }
   const base::FilePath& mount_path() const { return mount_path_; }
+  const bool configurable() const { return configurable_; }
+  extensions::FileSystemProviderSource source() const { return source_; }
 
  private:
   // ID of the extension providing this file system.
@@ -67,6 +72,12 @@
 
   // Mount path of the underlying file system.
   base::FilePath mount_path_;
+
+  // Whether the file system is configurable.
+  bool configurable_;
+
+  // Source of the file system's data.
+  extensions::FileSystemProviderSource source_;
 };
 
 }  // namespace file_system_provider
diff --git a/chrome/browser/chromeos/file_system_provider/provided_file_system_unittest.cc b/chrome/browser/chromeos/file_system_provider/provided_file_system_unittest.cc
index 3c1f14b..2a4488f1 100644
--- a/chrome/browser/chromeos/file_system_provider/provided_file_system_unittest.cc
+++ b/chrome/browser/chromeos/file_system_provider/provided_file_system_unittest.cc
@@ -22,6 +22,7 @@
 #include "chrome/browser/chromeos/file_system_provider/request_manager.h"
 #include "chrome/browser/chromeos/file_system_provider/watcher.h"
 #include "chrome/common/extensions/api/file_system_provider.h"
+#include "chrome/common/extensions/api/file_system_provider_capabilities/file_system_provider_capabilities_handler.h"
 #include "chrome/common/extensions/api/file_system_provider_internal.h"
 #include "chrome/test/base/testing_profile.h"
 #include "content/public/test/test_browser_thread_bundle.h"
@@ -231,8 +232,9 @@
     mount_options.display_name = kDisplayName;
     mount_options.supports_notify_tag = true;
     mount_options.writable = true;
-    file_system_info_.reset(
-        new ProvidedFileSystemInfo(kExtensionId, mount_options, mount_path));
+    file_system_info_.reset(new ProvidedFileSystemInfo(
+        kExtensionId, mount_options, mount_path, false /* configurable */,
+        extensions::SOURCE_FILE));
     provided_file_system_.reset(
         new ProvidedFileSystem(profile_.get(), *file_system_info_.get()));
     event_router_.reset(
@@ -411,7 +413,8 @@
     mount_options.display_name = kDisplayName;
     mount_options.supports_notify_tag = false;
     ProvidedFileSystemInfo file_system_info(
-        kExtensionId, mount_options, mount_path);
+        kExtensionId, mount_options, mount_path, false /* configurable */,
+        extensions::SOURCE_FILE);
     ProvidedFileSystem simple_provided_file_system(profile_.get(),
                                                    file_system_info);
     simple_provided_file_system.SetEventRouterForTesting(event_router_.get());
diff --git a/chrome/browser/chromeos/file_system_provider/registry_unittest.cc b/chrome/browser/chromeos/file_system_provider/registry_unittest.cc
index b02359f..a2c914d 100644
--- a/chrome/browser/chromeos/file_system_provider/registry_unittest.cc
+++ b/chrome/browser/chromeos/file_system_provider/registry_unittest.cc
@@ -10,6 +10,7 @@
 #include "base/files/file_path.h"
 #include "base/memory/scoped_ptr.h"
 #include "chrome/browser/chromeos/file_system_provider/provided_file_system_info.h"
+#include "chrome/common/extensions/api/file_system_provider_capabilities/file_system_provider_capabilities_handler.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_pref_service_syncable.h"
@@ -157,7 +158,8 @@
   options.opened_files_limit = kOpenedFilesLimit;
 
   ProvidedFileSystemInfo file_system_info(
-      kExtensionId, options, base::FilePath(FILE_PATH_LITERAL("/a/b/c")));
+      kExtensionId, options, base::FilePath(FILE_PATH_LITERAL("/a/b/c")),
+      false /* configurable */, extensions::SOURCE_FILE);
 
   Watchers watchers;
   watchers[WatcherKey(fake_watcher_.entry_path, fake_watcher_.recursive)] =
@@ -272,7 +274,8 @@
   options.supports_notify_tag = true;
 
   ProvidedFileSystemInfo file_system_info(
-      kExtensionId, options, base::FilePath(FILE_PATH_LITERAL("/a/b/c")));
+      kExtensionId, options, base::FilePath(FILE_PATH_LITERAL("/a/b/c")),
+      false /* configurable */, extensions::SOURCE_FILE);
 
   Watchers watchers;
   watchers[WatcherKey(fake_watcher_.entry_path, fake_watcher_.recursive)] =
diff --git a/chrome/browser/chromeos/file_system_provider/service.cc b/chrome/browser/chromeos/file_system_provider/service.cc
index 94ef49dd..faa6ce5c 100644
--- a/chrome/browser/chromeos/file_system_provider/service.cc
+++ b/chrome/browser/chromeos/file_system_provider/service.cc
@@ -160,6 +160,9 @@
     return base::File::FILE_ERROR_INVALID_OPERATION;
   }
 
+  ProvidingExtensionInfo provider_info;
+  // TODO(mtomasz): Set up a testing extension in unit tests.
+  GetProvidingExtensionInfo(extension_id, &provider_info);
   // Store the file system descriptor. Use the mount point name as the file
   // system provider file system id.
   // Examples:
@@ -168,7 +171,12 @@
   //   writable = false
   //   supports_notify_tag = false
   //   mount_path = /provided/b33f1337-hello_world-5aa5
-  ProvidedFileSystemInfo file_system_info(extension_id, options, mount_path);
+  //   configurable = true
+  //   source = SOURCE_FILE
+  ProvidedFileSystemInfo file_system_info(
+      extension_id, options, mount_path,
+      provider_info.capabilities.configurable(),
+      provider_info.capabilities.source());
 
   ProvidedFileSystemInterface* file_system =
       file_system_factory_.Run(profile_, file_system_info);
@@ -310,24 +318,39 @@
 
   std::vector<ProvidingExtensionInfo> result;
   for (const auto& extension : registry->enabled_extensions()) {
-    if (!extension->permissions_data()->HasAPIPermission(
-            extensions::APIPermission::kFileSystemProvider)) {
-      continue;
-    }
-
     ProvidingExtensionInfo info;
-    info.extension_id = extension->id();
-    info.name = extension->name();
-    const extensions::FileSystemProviderCapabilities* const capabilities =
-        extensions::FileSystemProviderCapabilities::Get(extension.get());
-    DCHECK(capabilities);
-    info.capabilities = *capabilities;
-    result.push_back(info);
+    if (GetProvidingExtensionInfo(extension->id(), &info))
+      result.push_back(info);
   }
 
   return result;
 }
 
+bool Service::GetProvidingExtensionInfo(const std::string& extension_id,
+                                        ProvidingExtensionInfo* result) const {
+  DCHECK(result);
+  extensions::ExtensionRegistry* const registry =
+      extensions::ExtensionRegistry::Get(profile_);
+  DCHECK(registry);
+
+  const extensions::Extension* const extension = registry->GetExtensionById(
+      extension_id, extensions::ExtensionRegistry::ENABLED);
+  if (!extension ||
+      !extension->permissions_data()->HasAPIPermission(
+          extensions::APIPermission::kFileSystemProvider)) {
+    return false;
+  }
+
+  result->extension_id = extension->id();
+  result->name = extension->name();
+  const extensions::FileSystemProviderCapabilities* const capabilities =
+      extensions::FileSystemProviderCapabilities::Get(extension);
+  DCHECK(capabilities);
+  result->capabilities = *capabilities;
+
+  return true;
+}
+
 void Service::OnExtensionUnloaded(
     content::BrowserContext* browser_context,
     const extensions::Extension* extension,
diff --git a/chrome/browser/chromeos/file_system_provider/service.h b/chrome/browser/chromeos/file_system_provider/service.h
index 54d6bf3..d072bd9 100644
--- a/chrome/browser/chromeos/file_system_provider/service.h
+++ b/chrome/browser/chromeos/file_system_provider/service.h
@@ -133,6 +133,12 @@
   // extensions.
   std::vector<ProvidingExtensionInfo> GetProvidingExtensionInfoList() const;
 
+  // Fills information of the specified providing extension and returns true.
+  // If the extension is not a provider, or it doesn't exist, then false is
+  // returned.
+  bool GetProvidingExtensionInfo(const std::string& extension_id,
+                                 ProvidingExtensionInfo* result) const;
+
   // Adds and removes observers.
   void AddObserver(Observer* observer);
   void RemoveObserver(Observer* observer);
diff --git a/chrome/browser/chromeos/file_system_provider/service_unittest.cc b/chrome/browser/chromeos/file_system_provider/service_unittest.cc
index ccee9c36..db7c33d 100644
--- a/chrome/browser/chromeos/file_system_provider/service_unittest.cc
+++ b/chrome/browser/chromeos/file_system_provider/service_unittest.cc
@@ -18,6 +18,7 @@
 #include "chrome/browser/chromeos/file_system_provider/registry_interface.h"
 #include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
 #include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h"
+#include "chrome/common/extensions/api/file_system_provider_capabilities/file_system_provider_capabilities_handler.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_pref_service_syncable.h"
 #include "chrome/test/base/testing_profile.h"
@@ -415,7 +416,8 @@
   MountOptions options(kFileSystemId, kDisplayName);
   options.supports_notify_tag = true;
   ProvidedFileSystemInfo file_system_info(
-      kExtensionId, options, base::FilePath(FILE_PATH_LITERAL("/a/b/c")));
+      kExtensionId, options, base::FilePath(FILE_PATH_LITERAL("/a/b/c")),
+      false /* configurable */, extensions::SOURCE_FILE);
   Watchers fake_watchers;
   fake_watchers[WatcherKey(fake_watcher_.entry_path, fake_watcher_.recursive)] =
       fake_watcher_;
diff --git a/chrome/browser/chromeos/file_system_provider/throttled_file_system_unittest.cc b/chrome/browser/chromeos/file_system_provider/throttled_file_system_unittest.cc
index 5b65a75a..d9333085 100644
--- a/chrome/browser/chromeos/file_system_provider/throttled_file_system_unittest.cc
+++ b/chrome/browser/chromeos/file_system_provider/throttled_file_system_unittest.cc
@@ -13,6 +13,7 @@
 #include "chrome/browser/chromeos/file_system_provider/abort_callback.h"
 #include "chrome/browser/chromeos/file_system_provider/fake_provided_file_system.h"
 #include "chrome/browser/chromeos/file_system_provider/provided_file_system_info.h"
+#include "chrome/common/extensions/api/file_system_provider_capabilities/file_system_provider_capabilities_handler.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -52,8 +53,9 @@
     MountOptions options(kFileSystemId, kDisplayName);
     options.opened_files_limit = limit;
 
-    ProvidedFileSystemInfo file_system_info(kExtensionId, options,
-                                            base::FilePath() /* mount_path */);
+    ProvidedFileSystemInfo file_system_info(
+        kExtensionId, options, base::FilePath() /* mount_path */,
+        false /* configurable */, extensions::SOURCE_FILE);
 
     file_system_.reset(new ThrottledFileSystem(
         make_scoped_ptr(new FakeProvidedFileSystem(file_system_info))));
diff --git a/chrome/browser/chromeos/first_run/first_run.cc b/chrome/browser/chromeos/first_run/first_run.cc
index 27b94fa..81c860d 100644
--- a/chrome/browser/chromeos/first_run/first_run.cc
+++ b/chrome/browser/chromeos/first_run/first_run.cc
@@ -10,6 +10,7 @@
 #include "chrome/browser/chromeos/first_run/first_run_controller.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/prefs/pref_service_syncable.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/extensions/app_launch_params.h"
 #include "chrome/browser/ui/extensions/application_launch.h"
@@ -76,8 +77,13 @@
     bool first_run_forced = command_line->HasSwitch(switches::kForceFirstRunUI);
     bool first_run_seen =
         profile_->GetPrefs()->GetBoolean(prefs::kFirstRunTutorialShown);
+    bool is_pref_synced =
+        PrefServiceSyncable::FromProfile(profile_)->IsPrioritySyncing();
+    bool is_user_ephemeral = user_manager::UserManager::Get()
+                                 ->IsCurrentUserNonCryptohomeDataEphemeral();
     if (!launched_in_telemetry &&
-        ((is_user_new && !first_run_seen && !launched_in_test) ||
+        ((is_user_new && !first_run_seen &&
+          (is_pref_synced || !is_user_ephemeral) && !launched_in_test) ||
          first_run_forced)) {
       LaunchDialogForProfile(profile_);
     }
diff --git a/chrome/browser/chromeos/login/existing_user_controller.cc b/chrome/browser/chromeos/login/existing_user_controller.cc
index e9367efc..9866456 100644
--- a/chrome/browser/chromeos/login/existing_user_controller.cc
+++ b/chrome/browser/chromeos/login/existing_user_controller.cc
@@ -44,6 +44,7 @@
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/chromeos/settings/cros_settings.h"
 #include "chrome/browser/chromeos/system/device_disabling_manager.h"
+#include "chrome/browser/signin/chrome_signin_client.h"
 #include "chrome/browser/signin/easy_unlock_service.h"
 #include "chrome/browser/ui/aura/accessibility/automation_manager_aura.h"
 #include "chrome/browser/ui/webui/chromeos/login/l10n_util.h"
@@ -1119,7 +1120,20 @@
   continuation.Run();
 }
 
-void ExistingUserController::DoCompleteLogin(const UserContext& user_context) {
+void ExistingUserController::DoCompleteLogin(
+    const UserContext& user_context_wo_device_id) {
+  UserContext user_context = user_context_wo_device_id;
+  std::string device_id =
+      user_manager::UserManager::Get()->GetKnownUserDeviceId(
+          user_context.GetUserID());
+  if (device_id.empty()) {
+    bool is_ephemeral =
+        ChromeUserManager::Get()->AreEphemeralUsersEnabled() &&
+        user_context.GetUserID() != ChromeUserManager::Get()->GetOwnerEmail();
+    device_id = ChromeSigninClient::GenerateSigninScopedDeviceID(is_ephemeral);
+  }
+  user_context.SetDeviceId(device_id);
+
   PerformPreLoginActions(user_context);
 
   if (!time_init_.is_null()) {
@@ -1236,38 +1250,8 @@
     OnAuthFailure(AuthFailure(AuthFailure::FAILED_TO_INITIALIZE_TOKEN));
     return;
   }
-  if (StartupUtils::IsWebviewSigninEnabled() && TokenHandlesEnabled()) {
-    if (!token_handle_util_.get()) {
-      token_handle_util_.reset(
-          new TokenHandleUtil(user_manager::UserManager::Get()));
-    }
-    if (token_handle_util_->ShouldObtainHandle(user_context.GetUserID())) {
-      token_handle_util_->GetTokenHandle(
-          user_context.GetUserID(), user_context.GetAccessToken(),
-          base::Bind(&ExistingUserController::OnTokenHandleObtained,
-                     weak_factory_.GetWeakPtr()));
-    }
-  }
+  UserSessionManager::GetInstance()->OnOAuth2TokensFetched(user_context);
   PerformLogin(user_context, LoginPerformer::AUTH_MODE_EXTENSION);
 }
 
-void ExistingUserController::OnTokenHandleObtained(
-    const user_manager::UserID& id,
-    TokenHandleUtil::TokenHandleStatus status) {
-  if (status != TokenHandleUtil::VALID) {
-    LOG(ERROR) << "OAuth2 token handle fetch failed.";
-    return;
-  }
-}
-
-bool ExistingUserController::TokenHandlesEnabled() {
-  bool ephemeral_users_enabled = false;
-  bool show_names_on_signin = true;
-  cros_settings_->GetBoolean(kAccountsPrefEphemeralUsersEnabled,
-                             &ephemeral_users_enabled);
-  cros_settings_->GetBoolean(kAccountsPrefShowUserNamesOnSignIn,
-                             &show_names_on_signin);
-  return show_names_on_signin && !ephemeral_users_enabled;
-}
-
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/existing_user_controller.h b/chrome/browser/chromeos/login/existing_user_controller.h
index eea1471d..0eb01b89 100644
--- a/chrome/browser/chromeos/login/existing_user_controller.h
+++ b/chrome/browser/chromeos/login/existing_user_controller.h
@@ -18,7 +18,6 @@
 #include "base/timer/timer.h"
 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
 #include "chrome/browser/chromeos/login/session/user_session_manager.h"
-#include "chrome/browser/chromeos/login/signin/token_handle_util.h"
 #include "chrome/browser/chromeos/login/ui/login_display.h"
 #include "chrome/browser/chromeos/settings/cros_settings.h"
 #include "chrome/browser/chromeos/settings/device_settings_service.h"
@@ -243,13 +242,6 @@
   // Callback invoked when |oauth2_token_initializer_| has finished.
   void OnOAuth2TokensFetched(bool success, const UserContext& user_context);
 
-  // Callback invoked when |token_handle_util_| has finished.
-  void OnTokenHandleObtained(const user_manager::UserID& id,
-                             TokenHandleUtil::TokenHandleStatus status);
-
-  // Returns |true| if token handles should be used on this device.
-  bool TokenHandlesEnabled();
-
   // Public session auto-login timer.
   scoped_ptr<base::OneShotTimer<ExistingUserController> > auto_login_timer_;
 
@@ -338,7 +330,6 @@
       bootstrap_user_context_initializer_;
 
   scoped_ptr<OAuth2TokenInitializer> oauth2_token_initializer_;
-  scoped_ptr<TokenHandleUtil> token_handle_util_;
 
   FRIEND_TEST_ALL_PREFIXES(ExistingUserControllerTest, ExistingUserLogin);
 
diff --git a/chrome/browser/chromeos/login/screens/user_image_screen.cc b/chrome/browser/chromeos/login/screens/user_image_screen.cc
index f450f9e..7805543 100644
--- a/chrome/browser/chromeos/login/screens/user_image_screen.cc
+++ b/chrome/browser/chromeos/login/screens/user_image_screen.cc
@@ -109,6 +109,11 @@
 }
 
 void UserImageScreen::HideCurtain() {
+  // Skip user image selection for ephemeral users.
+  if (user_manager::UserManager::Get()->IsUserNonCryptohomeDataEphemeral(
+          GetUser()->GetUserID())) {
+    ExitScreen();
+  }
   if (view_)
     view_->HideCurtain();
 }
@@ -125,6 +130,7 @@
 
 void UserImageScreen::OnInitialSync(bool local_image_updated) {
   DCHECK(sync_timer_);
+  ReportSyncResult(SyncResult::SUCCEEDED);
   if (!local_image_updated) {
     sync_timer_.reset();
     GetSyncObserver()->RemoveObserver(this);
@@ -136,6 +142,7 @@
 }
 
 void UserImageScreen::OnSyncTimeout() {
+  ReportSyncResult(SyncResult::TIMED_OUT);
   sync_timer_.reset();
   GetSyncObserver()->RemoveObserver(this);
   if (is_screen_ready_)
@@ -261,8 +268,10 @@
 
   if (GetUser()->CanSyncImage()) {
     if (UserImageSyncObserver* sync_observer = GetSyncObserver()) {
+      sync_waiting_start_time_ = base::Time::Now();
       // We have synced image already.
       if (sync_observer->is_synced()) {
+        ReportSyncResult(SyncResult::SUCCEEDED);
         ExitScreen();
         return;
       }
@@ -342,4 +351,12 @@
   Finish(BaseScreenDelegate::USER_IMAGE_SELECTED);
 }
 
+void UserImageScreen::ReportSyncResult(SyncResult timed_out) const {
+  base::TimeDelta duration = base::Time::Now() - sync_waiting_start_time_;
+  UMA_HISTOGRAM_TIMES("Login.NewUserPriorityPrefsSyncTime", duration);
+  UMA_HISTOGRAM_ENUMERATION("Login.NewUserPriorityPrefsSyncResult",
+                            static_cast<int>(timed_out),
+                            static_cast<int>(SyncResult::COUNT));
+}
+
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/screens/user_image_screen.h b/chrome/browser/chromeos/login/screens/user_image_screen.h
index 8afe9c29..5050f99 100644
--- a/chrome/browser/chromeos/login/screens/user_image_screen.h
+++ b/chrome/browser/chromeos/login/screens/user_image_screen.h
@@ -7,6 +7,7 @@
 
 #include "base/compiler_specific.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/time/time.h"
 #include "chrome/browser/chromeos/camera_presence_notifier.h"
 #include "chrome/browser/chromeos/login/screens/base_screen.h"
 #include "chrome/browser/chromeos/login/screens/user_image_model.h"
@@ -75,6 +76,15 @@
   bool user_selected_image() const { return user_has_selected_image_; }
 
  private:
+  // Must be kept synced with |NewUserPriorityPrefsSyncResult| enum from
+  // histograms.xml.
+  enum class SyncResult {
+    SUCCEEDED,
+    TIMED_OUT,
+    // Keeps a number of different sync results. Should be the last in the list.
+    COUNT
+  };
+
   // Called when whaiting for sync timed out.
   void OnSyncTimeout();
 
@@ -101,6 +111,9 @@
   // Closes the screen.
   void ExitScreen();
 
+  // Reports sync duration and result to UMA.
+  void ReportSyncResult(SyncResult timed_out) const;
+
   content::NotificationRegistrar notification_registrar_;
 
   scoped_ptr<policy::PolicyChangeRegistrar> policy_registrar_;
@@ -127,6 +140,9 @@
   // True if user has explicitly selected some image.
   bool user_has_selected_image_;
 
+  // The time when we started wait for user image sync.
+  base::Time sync_waiting_start_time_;
+
   DISALLOW_COPY_AND_ASSIGN(UserImageScreen);
 };
 
diff --git a/chrome/browser/chromeos/login/session/user_session_manager.cc b/chrome/browser/chromeos/login/session/user_session_manager.cc
index edecf3a..a07149b 100644
--- a/chrome/browser/chromeos/login/session/user_session_manager.cc
+++ b/chrome/browser/chromeos/login/session/user_session_manager.cc
@@ -423,6 +423,12 @@
   // TODO(nkostylev): Notify UserLoggedIn() after profile is actually
   // ready to be used (http://crbug.com/361528).
   NotifyUserLoggedIn();
+
+  if (!user_context.GetDeviceId().empty()) {
+    user_manager::UserManager::Get()->SetKnownUserDeviceId(
+        user_context.GetUserID(), user_context.GetDeviceId());
+  }
+
   PrepareProfile();
 }
 
@@ -896,20 +902,6 @@
     ChromeUserManager::Get()->SetIsCurrentUserNew(true);
   }
 
-  std::string device_id = profile->GetPrefs()->GetString(
-      prefs::kGoogleServicesSigninScopedDeviceId);
-  if (device_id.empty()) {
-    device_id = user_context.GetDeviceId();
-    if (!device_id.empty()) {
-      profile->GetPrefs()->SetString(prefs::kGoogleServicesSigninScopedDeviceId,
-                                     device_id);
-    }
-  }
-  if (!device_id.empty()) {
-    user_manager::UserManager::Get()->SetKnownUserDeviceId(user->GetUserID(),
-                                                           device_id);
-  }
-
   if (user->is_active()) {
     input_method::InputMethodManager* manager =
         input_method::InputMethodManager::Get();
@@ -1121,10 +1113,8 @@
 
   user_manager::UserManager* user_manager = user_manager::UserManager::Get();
 
-  bool can_show_getstarted_guide =
-      user_manager->GetActiveUser()->GetType() ==
-          user_manager::USER_TYPE_REGULAR &&
-      !user_manager->IsCurrentUserNonCryptohomeDataEphemeral();
+  bool can_show_getstarted_guide = user_manager->GetActiveUser()->GetType() ==
+                                   user_manager::USER_TYPE_REGULAR;
 
   // Skip the default first-run behavior for public accounts.
   if (!user_manager->IsLoggedInAsPublicAccount()) {
@@ -1672,4 +1662,43 @@
                             NUM_USER_PODS_DISPLAY);
 }
 
+void UserSessionManager::OnOAuth2TokensFetched(UserContext context) {
+  if (StartupUtils::IsWebviewSigninEnabled() && TokenHandlesEnabled()) {
+    if (!token_handle_util_.get()) {
+      token_handle_util_.reset(
+          new TokenHandleUtil(user_manager::UserManager::Get()));
+    }
+    if (token_handle_util_->ShouldObtainHandle(context.GetUserID())) {
+      token_handle_util_->GetTokenHandle(
+          context.GetUserID(), context.GetAccessToken(),
+          base::Bind(&UserSessionManager::OnTokenHandleObtained,
+                     weak_factory_.GetWeakPtr()));
+    }
+  }
+}
+
+void UserSessionManager::OnTokenHandleObtained(
+    const user_manager::UserID& id,
+    TokenHandleUtil::TokenHandleStatus status) {
+  if (status != TokenHandleUtil::VALID) {
+    LOG(ERROR) << "OAuth2 token handle fetch failed.";
+    return;
+  }
+}
+
+bool UserSessionManager::TokenHandlesEnabled() {
+  bool ephemeral_users_enabled = false;
+  bool show_names_on_signin = true;
+  auto cros_settings = CrosSettings::Get();
+  cros_settings->GetBoolean(kAccountsPrefEphemeralUsersEnabled,
+                            &ephemeral_users_enabled);
+  cros_settings->GetBoolean(kAccountsPrefShowUserNamesOnSignIn,
+                            &show_names_on_signin);
+  return show_names_on_signin && !ephemeral_users_enabled;
+}
+
+void UserSessionManager::Shutdown() {
+  token_handle_util_.reset();
+}
+
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/session/user_session_manager.h b/chrome/browser/chromeos/login/session/user_session_manager.h
index b86b2034..b1e7466 100644
--- a/chrome/browser/chromeos/login/session/user_session_manager.h
+++ b/chrome/browser/chromeos/login/session/user_session_manager.h
@@ -15,6 +15,7 @@
 #include "base/observer_list.h"
 #include "chrome/browser/chromeos/base/locale_util.h"
 #include "chrome/browser/chromeos/login/signin/oauth2_login_manager.h"
+#include "chrome/browser/chromeos/login/signin/token_handle_util.h"
 #include "chromeos/dbus/session_manager_client.h"
 #include "chromeos/login/auth/authenticator.h"
 #include "chromeos/login/auth/user_context.h"
@@ -218,6 +219,9 @@
 
   void ActiveUserChanged(const user_manager::User* active_user) override;
 
+  // This method will be called when user have obtained oauth2 tokens.
+  void OnOAuth2TokensFetched(UserContext context);
+
   // Returns default IME state for user session.
   scoped_refptr<input_method::InputMethodManager::State> GetDefaultIMEState(
       Profile* profile);
@@ -237,6 +241,8 @@
   const UserContext& user_context() const { return user_context_; }
   bool has_auth_cookies() const { return has_auth_cookies_; }
 
+  void Shutdown();
+
  private:
   friend class test::UserSessionManagerTestApi;
   friend struct DefaultSingletonTraits<UserSessionManager>;
@@ -360,6 +366,13 @@
       InputEventsBlocker* input_events_blocker,
       const locale_util::LanguageSwitchResult& result);
 
+  // Callback invoked when |token_handle_util_| has finished.
+  void OnTokenHandleObtained(const user_manager::UserID& id,
+                             TokenHandleUtil::TokenHandleStatus status);
+
+  // Returns |true| if token handles should be used on this device.
+  bool TokenHandlesEnabled();
+
   // Test API methods.
 
   // Injects |user_context| that will be used to create StubAuthenticator
@@ -444,6 +457,8 @@
   bool running_easy_unlock_key_ops_;
   base::Closure easy_unlock_key_ops_finished_callback_;
 
+  scoped_ptr<TokenHandleUtil> token_handle_util_;
+
   // Whether should launch browser, tests may override this value.
   bool should_launch_browser_;
 
diff --git a/chrome/browser/chromeos/login/signin/oauth2_token_fetcher.cc b/chrome/browser/chromeos/login/signin/oauth2_token_fetcher.cc
index b898018f..c98f7905f 100644
--- a/chrome/browser/chromeos/login/signin/oauth2_token_fetcher.cc
+++ b/chrome/browser/chromeos/login/signin/oauth2_token_fetcher.cc
@@ -68,9 +68,11 @@
 }
 
 void OAuth2TokenFetcher::StartExchangeFromAuthCode(
-    const std::string& auth_code) {
+    const std::string& auth_code,
+    const std::string& signin_scoped_device_id) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   auth_code_ = auth_code;
+  signin_scoped_device_id_ = signin_scoped_device_id;
   // Delay the verification if the network is not connected or on a captive
   // portal.
   const NetworkState* default_network =
@@ -81,13 +83,13 @@
     VLOG(1) << "Network is offline.  Deferring OAuth2 token fetch.";
     BrowserThread::PostDelayedTask(
         BrowserThread::UI, FROM_HERE,
-        base::Bind(&OAuth2TokenFetcher::StartExchangeFromAuthCode,
-                   AsWeakPtr(),
-                   auth_code),
+        base::Bind(&OAuth2TokenFetcher::StartExchangeFromAuthCode, AsWeakPtr(),
+                   auth_code, signin_scoped_device_id),
         base::TimeDelta::FromMilliseconds(kRequestRestartDelay));
     return;
   }
-  auth_fetcher_.StartAuthCodeForOAuth2TokenExchange(auth_code);
+  auth_fetcher_.StartAuthCodeForOAuth2TokenExchangeWithDeviceId(
+      auth_code, signin_scoped_device_id);
 }
 
 void OAuth2TokenFetcher::OnClientOAuthSuccess(
@@ -102,17 +104,15 @@
 void OAuth2TokenFetcher::OnClientOAuthFailure(
     const GoogleServiceAuthError& error) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  RetryOnError(error,
-               auth_code_.empty()
-                   ? base::Bind(&OAuth2TokenFetcher::StartExchangeFromCookies,
-                                AsWeakPtr(),
-                                session_index_,
-                                signin_scoped_device_id_)
-                   : base::Bind(&OAuth2TokenFetcher::StartExchangeFromAuthCode,
-                                AsWeakPtr(),
-                                auth_code_),
-               base::Bind(&Delegate::OnOAuth2TokensFetchFailed,
-                          base::Unretained(delegate_)));
+  RetryOnError(
+      error,
+      auth_code_.empty()
+          ? base::Bind(&OAuth2TokenFetcher::StartExchangeFromCookies,
+                       AsWeakPtr(), session_index_, signin_scoped_device_id_)
+          : base::Bind(&OAuth2TokenFetcher::StartExchangeFromAuthCode,
+                       AsWeakPtr(), auth_code_, signin_scoped_device_id_),
+      base::Bind(&Delegate::OnOAuth2TokensFetchFailed,
+                 base::Unretained(delegate_)));
 }
 
 void OAuth2TokenFetcher::RetryOnError(const GoogleServiceAuthError& error,
diff --git a/chrome/browser/chromeos/login/signin/oauth2_token_fetcher.h b/chrome/browser/chromeos/login/signin/oauth2_token_fetcher.h
index 5dd2e6d7..3cea28b8f 100644
--- a/chrome/browser/chromeos/login/signin/oauth2_token_fetcher.h
+++ b/chrome/browser/chromeos/login/signin/oauth2_token_fetcher.h
@@ -40,7 +40,8 @@
 
   void StartExchangeFromCookies(const std::string& session_index,
                                 const std::string& signin_scoped_device_id);
-  void StartExchangeFromAuthCode(const std::string& auth_code);
+  void StartExchangeFromAuthCode(const std::string& auth_code,
+                                 const std::string& signin_scoped_device_id);
 
  private:
   // Decides how to proceed on GAIA |error|. If the error looks temporary,
diff --git a/chrome/browser/chromeos/login/signin/oauth2_token_initializer.cc b/chrome/browser/chromeos/login/signin/oauth2_token_initializer.cc
index c0bcbc9..953c5d5 100644
--- a/chrome/browser/chromeos/login/signin/oauth2_token_initializer.cc
+++ b/chrome/browser/chromeos/login/signin/oauth2_token_initializer.cc
@@ -21,7 +21,10 @@
   user_context_ = user_context;
   oauth2_token_fetcher_.reset(new OAuth2TokenFetcher(
       this, g_browser_process->system_request_context()));
-  oauth2_token_fetcher_->StartExchangeFromAuthCode(user_context.GetAuthCode());
+  if (user_context.GetDeviceId().empty())
+    NOTREACHED() << "Device ID is not set";
+  oauth2_token_fetcher_->StartExchangeFromAuthCode(user_context.GetAuthCode(),
+                                                   user_context.GetDeviceId());
 }
 
 void OAuth2TokenInitializer::OnOAuth2TokensAvailable(
diff --git a/chrome/browser/chromeos/login/users/avatar/user_image_manager_browsertest.cc b/chrome/browser/chromeos/login/users/avatar/user_image_manager_browsertest.cc
index b3542385..63cab01 100644
--- a/chrome/browser/chromeos/login/users/avatar/user_image_manager_browsertest.cc
+++ b/chrome/browser/chromeos/login/users/avatar/user_image_manager_browsertest.cc
@@ -656,10 +656,12 @@
       ADD_FAILURE();
     }
     std::string policy;
-    base::JSONWriter::Write(policy::test::ConstructExternalDataReference(
-        embedded_test_server()->GetURL(std::string("/") + relative_path).spec(),
-        image_data).get(),
-        &policy);
+    base::JSONWriter::Write(*policy::test::ConstructExternalDataReference(
+                                embedded_test_server()
+                                    ->GetURL(std::string("/") + relative_path)
+                                    .spec(),
+                                image_data),
+                            &policy);
     return policy;
   }
 
diff --git a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager_policy_browsertest.cc b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager_policy_browsertest.cc
index 576d9f3c..8455a40e 100644
--- a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager_policy_browsertest.cc
+++ b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager_policy_browsertest.cc
@@ -220,10 +220,12 @@
       ADD_FAILURE();
     }
     std::string policy;
-    base::JSONWriter::Write(policy::test::ConstructExternalDataReference(
-        embedded_test_server()->GetURL(std::string("/") + relative_path).spec(),
-        image_data).get(),
-        &policy);
+    base::JSONWriter::Write(*policy::test::ConstructExternalDataReference(
+                                embedded_test_server()
+                                    ->GetURL(std::string("/") + relative_path)
+                                    .spec(),
+                                image_data),
+                            &policy);
     return policy;
   }
 
diff --git a/chrome/browser/chromeos/login/wizard_controller.cc b/chrome/browser/chromeos/login/wizard_controller.cc
index 493fabb..2677dc9 100644
--- a/chrome/browser/chromeos/login/wizard_controller.cc
+++ b/chrome/browser/chromeos/login/wizard_controller.cc
@@ -401,9 +401,12 @@
 void WizardController::ShowUserImageScreen() {
   const user_manager::UserManager* user_manager =
       user_manager::UserManager::Get();
-  // Skip user image selection for public sessions and ephemeral logins.
+  // Skip user image selection for public sessions and ephemeral non-regual user
+  // logins.
   if (user_manager->IsLoggedInAsPublicAccount() ||
-      user_manager->IsCurrentUserNonCryptohomeDataEphemeral()) {
+      (user_manager->IsCurrentUserNonCryptohomeDataEphemeral() &&
+       user_manager->GetLoggedInUser()->GetType() !=
+           user_manager::USER_TYPE_REGULAR)) {
     OnUserImageSkipped();
     return;
   }
diff --git a/chrome/browser/chromeos/net/onc_utils.cc b/chrome/browser/chromeos/net/onc_utils.cc
index abcd08a3..2e4194eb 100644
--- a/chrome/browser/chromeos/net/onc_utils.cc
+++ b/chrome/browser/chromeos/net/onc_utils.cc
@@ -228,7 +228,7 @@
     base::DictionaryValue ui_data_dict;
     ui_data->FillDictionary(&ui_data_dict);
     std::string ui_data_json;
-    base::JSONWriter::Write(&ui_data_dict, &ui_data_json);
+    base::JSONWriter::Write(ui_data_dict, &ui_data_json);
     shill_dict->SetStringWithoutPathExpansion(shill::kUIDataProperty,
                                               ui_data_json);
 
diff --git a/chrome/browser/chromeos/net/proxy_config_handler.cc b/chrome/browser/chromeos/net/proxy_config_handler.cc
index 4fa3d662..0351f34 100644
--- a/chrome/browser/chromeos/net/proxy_config_handler.cc
+++ b/chrome/browser/chromeos/net/proxy_config_handler.cc
@@ -112,7 +112,7 @@
                    network_handler::ErrorCallback()));
   } else {
     std::string proxy_config_str;
-    base::JSONWriter::Write(&proxy_config.GetDictionary(), &proxy_config_str);
+    base::JSONWriter::Write(proxy_config.GetDictionary(), &proxy_config_str);
     shill_service_client->SetProperty(
         dbus::ObjectPath(network.path()),
         shill::kProxyConfigProperty,
diff --git a/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.cc b/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.cc
index 8e1cff3d..6058ba9 100644
--- a/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.cc
+++ b/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.cc
@@ -28,6 +28,7 @@
 #include "chrome/browser/chromeos/policy/device_network_configuration_updater.h"
 #include "chrome/browser/chromeos/policy/enrollment_config.h"
 #include "chrome/browser/chromeos/policy/enterprise_install_attributes.h"
+#include "chrome/browser/chromeos/policy/remote_commands/affiliated_remote_commands_invalidator.h"
 #include "chrome/browser/chromeos/policy/server_backed_state_keys_broker.h"
 #include "chrome/browser/chromeos/settings/cros_settings.h"
 #include "chrome/browser/chromeos/settings/device_settings_service.h"
@@ -198,6 +199,10 @@
         enterprise_management::DeviceRegisterRequest::DEVICE,
         device_cloud_policy_manager_->core(),
         affiliated_invalidation_service_provider_.get()));
+    device_remote_commands_invalidator_.reset(
+        new AffiliatedRemoteCommandsInvalidator(
+            device_cloud_policy_manager_->core(),
+            affiliated_invalidation_service_provider_.get()));
   }
 
   SetTimezoneIfPolicyAvailable();
diff --git a/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h b/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h
index 347a4e3..fe342d8c 100644
--- a/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h
+++ b/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h
@@ -24,10 +24,11 @@
 
 namespace policy {
 
+class AffiliatedCloudPolicyInvalidator;
 class AffiliatedInvalidationServiceProvider;
+class AffiliatedRemoteCommandsInvalidator;
 class ConsumerManagementService;
 class DeviceCloudPolicyInitializer;
-class AffiliatedCloudPolicyInvalidator;
 class DeviceLocalAccountPolicyService;
 class DeviceManagementService;
 struct EnrollmentConfig;
@@ -164,6 +165,8 @@
   scoped_ptr<DeviceLocalAccountPolicyService>
       device_local_account_policy_service_;
   scoped_ptr<AffiliatedCloudPolicyInvalidator> device_cloud_policy_invalidator_;
+  scoped_ptr<AffiliatedRemoteCommandsInvalidator>
+      device_remote_commands_invalidator_;
 
   // This policy provider is used on Chrome OS to feed user policy into the
   // global PolicyService instance. This works by installing the cloud policy
diff --git a/chrome/browser/chromeos/policy/cloud_external_data_policy_observer_unittest.cc b/chrome/browser/chromeos/policy/cloud_external_data_policy_observer_unittest.cc
index 292507f5..aa26956 100644
--- a/chrome/browser/chromeos/policy/cloud_external_data_policy_observer_unittest.cc
+++ b/chrome/browser/chromeos/policy/cloud_external_data_policy_observer_unittest.cc
@@ -82,8 +82,7 @@
       test_data_dir.Append("chromeos").Append(file_name),
       policy_data));
   base::JSONWriter::Write(
-      test::ConstructExternalDataReference(url, *policy_data).get(),
-      policy);
+      *test::ConstructExternalDataReference(url, *policy_data), policy);
 }
 
 }  // namespace
diff --git a/chrome/browser/chromeos/policy/configuration_policy_handler_chromeos.cc b/chrome/browser/chromeos/policy/configuration_policy_handler_chromeos.cc
index 6530914c..f62b6c3 100644
--- a/chrome/browser/chromeos/policy/configuration_policy_handler_chromeos.cc
+++ b/chrome/browser/chromeos/policy/configuration_policy_handler_chromeos.cc
@@ -298,9 +298,8 @@
       *toplevel_dict,
       kPlaceholder);
 
-  base::JSONWriter::WriteWithOptions(toplevel_dict.get(),
-                                     base::JSONWriter::OPTIONS_PRETTY_PRINT,
-                                     &json_string);
+  base::JSONWriter::WriteWithOptions(
+      *toplevel_dict, base::JSONWriter::OPTIONS_PRETTY_PRINT, &json_string);
   return new base::StringValue(json_string);
 }
 
diff --git a/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h b/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h
index 2035c5e..33f11a84 100644
--- a/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h
+++ b/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h
@@ -105,7 +105,9 @@
     return device_store_.get();
   }
 
-  bool HasStatusUploaderForTest() { return status_uploader_; }
+  // Return the StatusUploader used to communicate device status to the
+  // policy server.
+  StatusUploader* GetStatusUploader() const { return status_uploader_.get(); }
 
  private:
   // Saves the state keys received from |session_manager_client_|.
diff --git a/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos_unittest.cc b/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos_unittest.cc
index dae7074dd..b3f626eb 100644
--- a/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos_unittest.cc
+++ b/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos_unittest.cc
@@ -262,7 +262,7 @@
   Mock::VerifyAndClearExpectations(&device_management_service_);
   ASSERT_TRUE(policy_fetch_job);
   // Should create a status uploader for reporting on enrolled devices.
-  EXPECT_TRUE(manager_->HasStatusUploaderForTest());
+  EXPECT_TRUE(manager_->GetStatusUploader());
   VerifyPolicyPopulated();
 
   manager_->Shutdown();
@@ -301,7 +301,7 @@
   ASSERT_TRUE(policy_fetch_job);
   // Should create a status provider for reporting on enrolled devices, even
   // those that aren't managed.
-  EXPECT_TRUE(manager_->HasStatusUploaderForTest());
+  EXPECT_TRUE(manager_->GetStatusUploader());
 
   // Switch back to ACTIVE, service the policy fetch and let it propagate.
   device_policy_.policy_data().set_state(em::PolicyData::ACTIVE);
@@ -329,7 +329,7 @@
   ConnectManager();
   EXPECT_TRUE(manager_->policies().Equals(bundle));
   // Should not create a status provider for reporting on consumer devices.
-  EXPECT_FALSE(manager_->HasStatusUploaderForTest());
+  EXPECT_FALSE(manager_->GetStatusUploader());
 
   manager_->Shutdown();
   EXPECT_TRUE(manager_->policies().Equals(bundle));
diff --git a/chrome/browser/chromeos/policy/device_local_account_browsertest.cc b/chrome/browser/chromeos/policy/device_local_account_browsertest.cc
index 108ac77..24509fc 100644
--- a/chrome/browser/chromeos/policy/device_local_account_browsertest.cc
+++ b/chrome/browser/chromeos/policy/device_local_account_browsertest.cc
@@ -1279,7 +1279,7 @@
   scoped_ptr<base::DictionaryValue> metadata =
       test::ConstructExternalDataReference(kExternalDataURL, kExternalData);
   std::string policy;
-  base::JSONWriter::Write(metadata.get(), &policy);
+  base::JSONWriter::Write(*metadata, &policy);
   device_local_account_policy_.payload().mutable_useravatarimage()->set_value(
       policy);
   UploadAndInstallDeviceLocalAccountPolicy();
@@ -1362,10 +1362,13 @@
       &image_data));
 
   std::string policy;
-  base::JSONWriter::Write(test::ConstructExternalDataReference(
-      embedded_test_server()->GetURL(std::string("/") +
-          chromeos::test::kUserAvatarImage1RelativePath).spec(),
-      image_data).get(),
+  base::JSONWriter::Write(
+      *test::ConstructExternalDataReference(
+          embedded_test_server()
+              ->GetURL(std::string("/") +
+                       chromeos::test::kUserAvatarImage1RelativePath)
+              .spec(),
+          image_data),
       &policy);
   device_local_account_policy_.payload().mutable_useravatarimage()->set_value(
       policy);
diff --git a/chrome/browser/chromeos/policy/device_status_collector.h b/chrome/browser/chromeos/policy/device_status_collector.h
index 4f31b298..47656a9b 100644
--- a/chrome/browser/chromeos/policy/device_status_collector.h
+++ b/chrome/browser/chromeos/policy/device_status_collector.h
@@ -95,6 +95,12 @@
 
   static void RegisterPrefs(PrefRegistrySimple* registry);
 
+  // Returns the DeviceLocalAccount associated with the currently active
+  // kiosk session, if the session was auto-launched with zero delay
+  // (this enables functionality such as network reporting).
+  // Virtual to allow mocking.
+  virtual scoped_ptr<DeviceLocalAccount> GetAutoLaunchedKioskSessionInfo();
+
   // How often, in seconds, to poll to see if the user is idle.
   static const unsigned int kIdlePollIntervalSeconds = 30;
 
@@ -111,12 +117,6 @@
   // Callback which receives the results of the idle state check.
   void IdleStateCallback(ui::IdleState state);
 
-  // Returns the DeviceLocalAccount associated with the currently active
-  // kiosk session, if the session was auto-launched with zero delay
-  // (this enables functionality such as network reporting).
-  // Virtual to allow mocking.
-  virtual scoped_ptr<DeviceLocalAccount> GetAutoLaunchedKioskSessionInfo();
-
   // Gets the version of the passed app. Virtual to allow mocking.
   virtual std::string GetAppVersion(const std::string& app_id);
 
diff --git a/chrome/browser/chromeos/policy/login_policy_test_base.cc b/chrome/browser/chromeos/policy/login_policy_test_base.cc
index 710b0bda..7fb6adac 100644
--- a/chrome/browser/chromeos/policy/login_policy_test_base.cc
+++ b/chrome/browser/chromeos/policy/login_policy_test_base.cc
@@ -54,10 +54,10 @@
   root_dict.SetString("policy_user", account);
   root_dict.SetInteger("current_key_index", 0);
 
-  std::string jsonPolicy;
+  std::string json_policy;
   base::JSONWriter::WriteWithOptions(
-      &root_dict, base::JSONWriter::OPTIONS_PRETTY_PRINT, &jsonPolicy);
-  return jsonPolicy;
+      root_dict, base::JSONWriter::OPTIONS_PRETTY_PRINT, &json_policy);
+  return json_policy;
 }
 
 }  // namespace
diff --git a/chrome/browser/chromeos/policy/proto/chrome_device_policy.proto b/chrome/browser/chromeos/policy/proto/chrome_device_policy.proto
index ceee1d05..bb4e8e99 100644
--- a/chrome/browser/chromeos/policy/proto/chrome_device_policy.proto
+++ b/chrome/browser/chromeos/policy/proto/chrome_device_policy.proto
@@ -610,7 +610,8 @@
 }
 
 message ExtensionCacheSizeProto {
-  // Specifies the maximum extension cache size, in bytes.
+  // Specifies the maximum extension cache size, in bytes. The default is 256
+  // MiB. The minimum allowed value is 1 MiB, smaller values will get ignored.
   optional int64 extension_cache_size = 1;
 }
 
diff --git a/chrome/browser/chromeos/policy/remote_commands/affiliated_remote_commands_invalidator.cc b/chrome/browser/chromeos/policy/remote_commands/affiliated_remote_commands_invalidator.cc
new file mode 100644
index 0000000..63bb35a
--- /dev/null
+++ b/chrome/browser/chromeos/policy/remote_commands/affiliated_remote_commands_invalidator.cc
@@ -0,0 +1,37 @@
+// 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/chromeos/policy/remote_commands/affiliated_remote_commands_invalidator.h"
+
+#include "chrome/browser/policy/cloud/remote_commands_invalidator_impl.h"
+
+namespace policy {
+
+AffiliatedRemoteCommandsInvalidator::AffiliatedRemoteCommandsInvalidator(
+    CloudPolicyCore* core,
+    AffiliatedInvalidationServiceProvider* invalidation_service_provider)
+    : core_(core),
+      invalidation_service_provider_(invalidation_service_provider) {
+  invalidation_service_provider_->RegisterConsumer(this);
+}
+
+AffiliatedRemoteCommandsInvalidator::~AffiliatedRemoteCommandsInvalidator() {
+  invalidation_service_provider_->UnregisterConsumer(this);
+}
+
+void AffiliatedRemoteCommandsInvalidator::OnInvalidationServiceSet(
+    invalidation::InvalidationService* invalidation_service) {
+  // Destroy this invalidator if it exists.
+  if (invalidator_) {
+    invalidator_->Shutdown();
+    invalidator_.reset();
+  }
+  // Create a new one if required.
+  if (invalidation_service) {
+    invalidator_.reset(new RemoteCommandsInvalidatorImpl(core_));
+    invalidator_->Initialize(invalidation_service);
+  }
+}
+
+}  // namespace policy
diff --git a/chrome/browser/chromeos/policy/remote_commands/affiliated_remote_commands_invalidator.h b/chrome/browser/chromeos/policy/remote_commands/affiliated_remote_commands_invalidator.h
new file mode 100644
index 0000000..c981377
--- /dev/null
+++ b/chrome/browser/chromeos/policy/remote_commands/affiliated_remote_commands_invalidator.h
@@ -0,0 +1,42 @@
+// 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_CHROMEOS_POLICY_REMOTE_COMMANDS_AFFILIATED_REMOTE_COMMANDS_INVALIDATOR_H_
+#define CHROME_BROWSER_CHROMEOS_POLICY_REMOTE_COMMANDS_AFFILIATED_REMOTE_COMMANDS_INVALIDATOR_H_
+
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "chrome/browser/chromeos/policy/affiliated_invalidation_service_provider.h"
+
+namespace policy {
+
+class CloudPolicyCore;
+class RemoteCommandsInvalidatorImpl;
+
+// This is a wrapper class to be used for device commands and device-local
+// account commands.
+class AffiliatedRemoteCommandsInvalidator
+    : public AffiliatedInvalidationServiceProvider::Consumer {
+ public:
+  AffiliatedRemoteCommandsInvalidator(
+      CloudPolicyCore* core,
+      AffiliatedInvalidationServiceProvider* invalidation_service_provider);
+  ~AffiliatedRemoteCommandsInvalidator() override;
+
+  // AffiliatedInvalidationServiceProvider::Consumer:
+  void OnInvalidationServiceSet(
+      invalidation::InvalidationService* invalidation_service) override;
+
+ private:
+  CloudPolicyCore* const core_;
+  AffiliatedInvalidationServiceProvider* const invalidation_service_provider_;
+
+  scoped_ptr<RemoteCommandsInvalidatorImpl> invalidator_;
+
+  DISALLOW_COPY_AND_ASSIGN(AffiliatedRemoteCommandsInvalidator);
+};
+
+}  // namespace policy
+
+#endif  // CHROME_BROWSER_CHROMEOS_POLICY_REMOTE_COMMANDS_AFFILIATED_REMOTE_COMMANDS_INVALIDATOR_H_
diff --git a/chrome/browser/chromeos/policy/remote_commands/device_command_screenshot_job.cc b/chrome/browser/chromeos/policy/remote_commands/device_command_screenshot_job.cc
index 3a03d6c..28deddf 100644
--- a/chrome/browser/chromeos/policy/remote_commands/device_command_screenshot_job.cc
+++ b/chrome/browser/chromeos/policy/remote_commands/device_command_screenshot_job.cc
@@ -81,8 +81,8 @@
 DeviceCommandScreenshotJob::Payload::Payload(ResultCode result_code) {
   base::DictionaryValue root_dict;
   if (result_code != SUCCESS)
-    root_dict.Set(kResultFieldName, new base::FundamentalValue(result_code));
-  base::JSONWriter::Write(&root_dict, &payload_);
+    root_dict.SetInteger(kResultFieldName, result_code);
+  base::JSONWriter::Write(root_dict, &payload_);
 }
 
 scoped_ptr<std::string> DeviceCommandScreenshotJob::Payload::Serialize() {
@@ -189,8 +189,13 @@
   succeeded_callback_ = succeeded_callback;
   failed_callback_ = failed_callback;
 
-  upload_job_ = screenshot_delegate_->CreateUploadJob(upload_url_, this);
-  DCHECK(upload_job_);
+  // Fail if the delegate says screenshots are not allowed in this session.
+  if (!screenshot_delegate_->IsScreenshotAllowed()) {
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE,
+        base::Bind(failed_callback_, base::Passed(make_scoped_ptr(
+                                         new Payload(FAILURE_USER_INPUT)))));
+  }
 
   aura::Window::Windows root_windows = ash::Shell::GetAllRootWindows();
 
@@ -213,6 +218,9 @@
     return;
   }
 
+  upload_job_ = screenshot_delegate_->CreateUploadJob(upload_url_, this);
+  DCHECK(upload_job_);
+
   // Post tasks to the sequenced worker pool for taking screenshots on each
   // attached screen.
   num_pending_screenshots_ = root_windows.size();
diff --git a/chrome/browser/chromeos/policy/remote_commands/device_command_screenshot_job.h b/chrome/browser/chromeos/policy/remote_commands/device_command_screenshot_job.h
index fb8aa79..49032be 100644
--- a/chrome/browser/chromeos/policy/remote_commands/device_command_screenshot_job.h
+++ b/chrome/browser/chromeos/policy/remote_commands/device_command_screenshot_job.h
@@ -65,6 +65,12 @@
    public:
     virtual ~Delegate() {}
 
+    // Returns true if screenshots are allowed in this session. Returns false
+    // if the current session is not an auto-launched kiosk session, or there
+    // have been certain types of user input that may result in leaking private
+    // information.
+    virtual bool IsScreenshotAllowed() = 0;
+
     // Acquires a snapshot of |source_rect| in |window| and invokes |callback|
     // with the PNG data. The passed-in callback will not be invoked after the
     // delegate has been destroyed. See e.g. ScreenshotDelegate.
diff --git a/chrome/browser/chromeos/policy/remote_commands/device_command_screenshot_job_unittest.cc b/chrome/browser/chromeos/policy/remote_commands/device_command_screenshot_job_unittest.cc
index cc4b51b2..8b07687 100644
--- a/chrome/browser/chromeos/policy/remote_commands/device_command_screenshot_job_unittest.cc
+++ b/chrome/browser/chromeos/policy/remote_commands/device_command_screenshot_job_unittest.cc
@@ -49,8 +49,8 @@
   command_proto.set_age_of_command(age_of_command.InMilliseconds());
   std::string payload;
   base::DictionaryValue root_dict;
-  root_dict.Set(kUploadUrlFieldName, new base::StringValue(upload_url));
-  base::JSONWriter::Write(&root_dict, &payload);
+  root_dict.SetString(kUploadUrlFieldName, upload_url);
+  base::JSONWriter::Write(root_dict, &payload);
   command_proto.set_payload(payload);
   return command_proto;
 }
@@ -137,10 +137,11 @@
 
 class MockScreenshotDelegate : public DeviceCommandScreenshotJob::Delegate {
  public:
-  MockScreenshotDelegate(
-      scoped_ptr<UploadJob::ErrorCode> upload_job_error_code);
+  MockScreenshotDelegate(scoped_ptr<UploadJob::ErrorCode> upload_job_error_code,
+                         bool screenshot_allowed);
   ~MockScreenshotDelegate() override;
 
+  bool IsScreenshotAllowed() override;
   void TakeSnapshot(
       gfx::NativeWindow window,
       const gfx::Rect& source_rect,
@@ -150,16 +151,23 @@
 
  private:
   scoped_ptr<UploadJob::ErrorCode> upload_job_error_code_;
+  bool screenshot_allowed_;
 };
 
 MockScreenshotDelegate::MockScreenshotDelegate(
-    scoped_ptr<UploadJob::ErrorCode> upload_job_error_code)
-    : upload_job_error_code_(upload_job_error_code.Pass()) {
+    scoped_ptr<UploadJob::ErrorCode> upload_job_error_code,
+    bool screenshot_allowed)
+    : upload_job_error_code_(upload_job_error_code.Pass()),
+      screenshot_allowed_(screenshot_allowed) {
 }
 
 MockScreenshotDelegate::~MockScreenshotDelegate() {
 }
 
+bool MockScreenshotDelegate::IsScreenshotAllowed() {
+  return screenshot_allowed_;
+}
+
 void MockScreenshotDelegate::TakeSnapshot(
     gfx::NativeWindow window,
     const gfx::Rect& source_rect,
@@ -238,7 +246,7 @@
   base::DictionaryValue root_dict;
   if (result_code != DeviceCommandScreenshotJob::SUCCESS)
     root_dict.Set(kResultFieldName, new base::FundamentalValue(result_code));
-  base::JSONWriter::Write(&root_dict, &payload);
+  base::JSONWriter::Write(root_dict, &payload);
   return payload;
 }
 
@@ -257,7 +265,7 @@
 
 TEST_F(DeviceCommandScreenshotTest, Success) {
   scoped_ptr<RemoteCommandJob> job(new DeviceCommandScreenshotJob(
-      make_scoped_ptr(new MockScreenshotDelegate(nullptr))));
+      make_scoped_ptr(new MockScreenshotDelegate(nullptr, true))));
   InitializeScreenshotJob(job.get(), kUniqueID, test_start_time_,
                           kMockUploadUrl);
   bool success = job->Run(
@@ -270,12 +278,28 @@
   run_loop_.Run();
 }
 
+TEST_F(DeviceCommandScreenshotTest, FailureUserInput) {
+  scoped_ptr<RemoteCommandJob> job(new DeviceCommandScreenshotJob(
+      make_scoped_ptr(new MockScreenshotDelegate(nullptr, false))));
+  InitializeScreenshotJob(job.get(), kUniqueID, test_start_time_,
+                          kMockUploadUrl);
+  bool success =
+      job->Run(base::TimeTicks::Now(),
+               base::Bind(&DeviceCommandScreenshotTest::VerifyResults,
+                          base::Unretained(this), base::Unretained(job.get()),
+                          RemoteCommandJob::FAILED,
+                          CreatePayloadFromResultCode(
+                              DeviceCommandScreenshotJob::FAILURE_USER_INPUT)));
+  EXPECT_TRUE(success);
+  run_loop_.Run();
+}
+
 TEST_F(DeviceCommandScreenshotTest, Failure) {
   using ErrorCode = UploadJob::ErrorCode;
   scoped_ptr<ErrorCode> error_code(
       new ErrorCode(UploadJob::AUTHENTICATION_ERROR));
   scoped_ptr<RemoteCommandJob> job(new DeviceCommandScreenshotJob(
-      make_scoped_ptr(new MockScreenshotDelegate(error_code.Pass()))));
+      make_scoped_ptr(new MockScreenshotDelegate(error_code.Pass(), true))));
   InitializeScreenshotJob(job.get(), kUniqueID, test_start_time_,
                           kMockUploadUrl);
   bool success = job->Run(
diff --git a/chrome/browser/chromeos/policy/remote_commands/screenshot_delegate.cc b/chrome/browser/chromeos/policy/remote_commands/screenshot_delegate.cc
index b850a59..c431d68 100644
--- a/chrome/browser/chromeos/policy/remote_commands/screenshot_delegate.cc
+++ b/chrome/browser/chromeos/policy/remote_commands/screenshot_delegate.cc
@@ -5,6 +5,9 @@
 #include "chrome/browser/chromeos/policy/remote_commands/screenshot_delegate.h"
 
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
+#include "chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h"
+#include "chrome/browser/chromeos/policy/status_uploader.h"
 #include "chrome/browser/chromeos/policy/upload_job_impl.h"
 #include "chrome/browser/chromeos/settings/device_oauth2_token_service.h"
 #include "chrome/browser/chromeos/settings/device_oauth2_token_service_factory.h"
@@ -20,6 +23,18 @@
 ScreenshotDelegate::~ScreenshotDelegate() {
 }
 
+bool ScreenshotDelegate::IsScreenshotAllowed() {
+  BrowserPolicyConnectorChromeOS* connector =
+      g_browser_process->platform_part()->browser_policy_connector_chromeos();
+  DeviceCloudPolicyManagerChromeOS* manager =
+      connector->GetDeviceCloudPolicyManager();
+  // DeviceCloudPolicyManagerChromeOS and StatusUploader can be null during
+  // shutdown (and unit tests) - don't allow screenshots unless we have a
+  // StatusUploader that can confirm that screenshots are allowed.
+  return manager && manager->GetStatusUploader() &&
+         manager->GetStatusUploader()->IsSessionDataUploadAllowed();
+}
+
 void ScreenshotDelegate::TakeSnapshot(
     gfx::NativeWindow window,
     const gfx::Rect& source_rect,
diff --git a/chrome/browser/chromeos/policy/remote_commands/screenshot_delegate.h b/chrome/browser/chromeos/policy/remote_commands/screenshot_delegate.h
index d809b91..fd15c7e7f 100644
--- a/chrome/browser/chromeos/policy/remote_commands/screenshot_delegate.h
+++ b/chrome/browser/chromeos/policy/remote_commands/screenshot_delegate.h
@@ -28,6 +28,7 @@
   ~ScreenshotDelegate() override;
 
   // DeviceCommandScreenshotJob::Delegate:
+  bool IsScreenshotAllowed() override;
   void TakeSnapshot(
       gfx::NativeWindow window,
       const gfx::Rect& source_rect,
diff --git a/chrome/browser/chromeos/policy/status_uploader.cc b/chrome/browser/chromeos/policy/status_uploader.cc
index 5bf4202..fd95fca 100644
--- a/chrome/browser/chromeos/policy/status_uploader.cc
+++ b/chrome/browser/chromeos/policy/status_uploader.cc
@@ -10,11 +10,13 @@
 #include "base/bind_helpers.h"
 #include "base/location.h"
 #include "base/sequenced_task_runner.h"
+#include "chrome/browser/chromeos/policy/device_local_account.h"
 #include "chrome/browser/chromeos/policy/device_status_collector.h"
 #include "chromeos/settings/cros_settings_names.h"
 #include "chromeos/settings/cros_settings_provider.h"
 #include "components/policy/core/common/cloud/cloud_policy_client.h"
 #include "components/policy/core/common/cloud/device_management_service.h"
+#include "ui/base/user_activity/user_activity_detector.h"
 
 namespace {
 const int kMinUploadDelayMs = 60 * 1000;  // 60 seconds
@@ -103,6 +105,22 @@
     ScheduleNextStatusUpload();
 }
 
+bool StatusUploader::IsSessionDataUploadAllowed() {
+  // Check if we're in an auto-launched kiosk session.
+  scoped_ptr<DeviceLocalAccount> account =
+      collector_->GetAutoLaunchedKioskSessionInfo();
+  if (!account)
+    return false;
+
+  // Check if there has been any user input.
+  if (!ui::UserActivityDetector::Get()->last_activity_time().is_null())
+    return false;
+
+  // TODO(atwilson): Check if we've captured any audio/video data
+  // (http://crbug.com/487261).
+  return true;
+}
+
 void StatusUploader::UploadStatus() {
   enterprise_management::DeviceStatusReportRequest device_status;
   bool have_device_status = collector_->GetDeviceStatus(&device_status);
diff --git a/chrome/browser/chromeos/policy/status_uploader.h b/chrome/browser/chromeos/policy/status_uploader.h
index 2eead18..6fa48203 100644
--- a/chrome/browser/chromeos/policy/status_uploader.h
+++ b/chrome/browser/chromeos/policy/status_uploader.h
@@ -44,6 +44,11 @@
   // has ever happened.
   base::Time last_upload() const { return last_upload_; }
 
+  // Returns true if session data upload (screenshots, logs, etc) is allowed.
+  // This checks to ensure that the current session is a kiosk session, and
+  // that no user input (keyboard, mouse, touch, audio/video) has been received.
+  bool IsSessionDataUploadAllowed();
+
  private:
   // Callback invoked periodically to upload the device status from the
   // DeviceStatusCollector.
diff --git a/chrome/browser/chromeos/proxy_config_service_impl_unittest.cc b/chrome/browser/chromeos/proxy_config_service_impl_unittest.cc
index 785c48a..121ef02e 100644
--- a/chrome/browser/chromeos/proxy_config_service_impl_unittest.cc
+++ b/chrome/browser/chromeos/proxy_config_service_impl_unittest.cc
@@ -333,7 +333,7 @@
   void SetUserConfigInShill(base::DictionaryValue* pref_proxy_config_dict) {
     std::string proxy_config;
     if (pref_proxy_config_dict)
-      base::JSONWriter::Write(pref_proxy_config_dict, &proxy_config);
+      base::JSONWriter::Write(*pref_proxy_config_dict, &proxy_config);
 
     NetworkStateHandler* network_state_handler =
         NetworkHandler::Get()->network_state_handler();
diff --git a/chrome/browser/component_updater/supervised_user_whitelist_installer_unittest.cc b/chrome/browser/component_updater/supervised_user_whitelist_installer_unittest.cc
index c6266a2..c5e897f0 100644
--- a/chrome/browser/component_updater/supervised_user_whitelist_installer_unittest.cc
+++ b/chrome/browser/component_updater/supervised_user_whitelist_installer_unittest.cc
@@ -51,7 +51,7 @@
   return GetCrxComponentID(component);
 }
 
-std::string JsonToString(const base::DictionaryValue* dict) {
+std::string JsonToString(const base::DictionaryValue& dict) {
   std::string json;
   base::JSONWriter::Write(dict, &json);
   return json;
@@ -310,8 +310,8 @@
   ASSERT_TRUE(base::ReadFileToString(whitelist_path_, &whitelist_contents));
   EXPECT_EQ(kWhitelistContents, whitelist_contents);
 
-  EXPECT_EQ(JsonToString(&pref_),
-            JsonToString(local_state_.GetDictionary(
+  EXPECT_EQ(JsonToString(pref_),
+            JsonToString(*local_state_.GetDictionary(
                 prefs::kRegisteredSupervisedUserWhitelists)));
 }
 
diff --git a/chrome/browser/content_settings/host_content_settings_map_unittest.cc b/chrome/browser/content_settings/host_content_settings_map_unittest.cc
index 6247af2..0cf740f 100644
--- a/chrome/browser/content_settings/host_content_settings_map_unittest.cc
+++ b/chrome/browser/content_settings/host_content_settings_map_unittest.cc
@@ -720,8 +720,8 @@
   // Initialize the content map.
   profile.GetHostContentSettingsMap();
 
-  const base::DictionaryValue* content_setting_prefs =
-      profile.GetPrefs()->GetDictionary(
+  const base::DictionaryValue& content_setting_prefs =
+      *profile.GetPrefs()->GetDictionary(
           prefs::kContentSettingsImagesPatternPairs);
   std::string prefs_as_json;
   base::JSONWriter::Write(content_setting_prefs, &prefs_as_json);
diff --git a/chrome/browser/content_settings/permission_context_base.cc b/chrome/browser/content_settings/permission_context_base.cc
index 60b7438e..9cd5d126 100644
--- a/chrome/browser/content_settings/permission_context_base.cc
+++ b/chrome/browser/content_settings/permission_context_base.cc
@@ -181,7 +181,7 @@
     if (persist) {
       DCHECK(content_setting == CONTENT_SETTING_ALLOW ||
              content_setting == CONTENT_SETTING_BLOCK);
-      if (CONTENT_SETTING_ALLOW)
+      if (content_setting == CONTENT_SETTING_ALLOW)
         PermissionContextUmaUtil::PermissionGranted(permission_type_,
                                                     requesting_origin);
       else
diff --git a/chrome/browser/devtools/device/webrtc/send_command_request.cc b/chrome/browser/devtools/device/webrtc/send_command_request.cc
index d09be25..7bfe5f4 100644
--- a/chrome/browser/devtools/device/webrtc/send_command_request.cc
+++ b/chrome/browser/devtools/device/webrtc/send_command_request.cc
@@ -22,7 +22,7 @@
 SendCommandRequest::SendCommandRequest(const base::DictionaryValue* request,
                                        Delegate* delegate)
     : delegate_(delegate) {
-  base::JSONWriter::Write(request, &upload_data_);
+  base::JSONWriter::Write(*request, &upload_data_);
   DCHECK(delegate_);
 }
 
diff --git a/chrome/browser/devtools/devtools_protocol.cc b/chrome/browser/devtools/devtools_protocol.cc
index 8df0557..5687220 100644
--- a/chrome/browser/devtools/devtools_protocol.cc
+++ b/chrome/browser/devtools/devtools_protocol.cc
@@ -37,7 +37,7 @@
     command.Set(kParamsParam, params.release());
 
   std::string json_command;
-  base::JSONWriter::Write(&command, &json_command);
+  base::JSONWriter::Write(command, &json_command);
   return json_command;
 }
 
diff --git a/chrome/browser/devtools/devtools_ui_bindings.cc b/chrome/browser/devtools/devtools_ui_bindings.cc
index 3a5d3ca..69ab19f 100644
--- a/chrome/browser/devtools/devtools_ui_bindings.cc
+++ b/chrome/browser/devtools/devtools_ui_bindings.cc
@@ -1016,13 +1016,13 @@
   std::string javascript = function_name + "(";
   if (arg1) {
     std::string json;
-    base::JSONWriter::Write(arg1, &json);
+    base::JSONWriter::Write(*arg1, &json);
     javascript.append(json);
     if (arg2) {
-      base::JSONWriter::Write(arg2, &json);
+      base::JSONWriter::Write(*arg2, &json);
       javascript.append(", ").append(json);
       if (arg3) {
-        base::JSONWriter::Write(arg3, &json);
+        base::JSONWriter::Write(*arg3, &json);
         javascript.append(", ").append(json);
       }
     }
diff --git a/chrome/browser/extensions/BUILD.gn b/chrome/browser/extensions/BUILD.gn
index ab3ce940..8a541b1 100644
--- a/chrome/browser/extensions/BUILD.gn
+++ b/chrome/browser/extensions/BUILD.gn
@@ -202,7 +202,4 @@
   if (!use_ozone) {
     sources -= [ "global_shortcut_listener_ozone.cc" ]
   }
-  if (enable_media_router) {
-    defines += [ "ENABLE_MEDIA_ROUTER=1" ]
-  }
 }
diff --git a/chrome/browser/extensions/api/automation/automation_apitest.cc b/chrome/browser/extensions/api/automation/automation_apitest.cc
index 4310f03..e94ad6cc 100644
--- a/chrome/browser/extensions/api/automation/automation_apitest.cc
+++ b/chrome/browser/extensions/api/automation/automation_apitest.cc
@@ -206,7 +206,7 @@
 #else
 #define MAYBE_Mixins Mixins
 #endif
-IN_PROC_BROWSER_TEST_F(AutomationApiTest, Mixins) {
+IN_PROC_BROWSER_TEST_F(AutomationApiTest, MAYBE_Mixins) {
   StartEmbeddedTestServer();
   ASSERT_TRUE(RunExtensionSubtest("automation/tests/tabs", "mixins.html"))
       << message_;
diff --git a/chrome/browser/extensions/api/debugger/debugger_api.cc b/chrome/browser/extensions/api/debugger/debugger_api.cc
index 14638efb..27623d9 100644
--- a/chrome/browser/extensions/api/debugger/debugger_api.cc
+++ b/chrome/browser/extensions/api/debugger/debugger_api.cc
@@ -385,7 +385,7 @@
   }
 
   std::string json_args;
-  base::JSONWriter::Write(&protocol_request, &json_args);
+  base::JSONWriter::Write(protocol_request, &json_args);
   agent_host_->DispatchProtocolMessage(json_args);
 }
 
@@ -666,7 +666,7 @@
     base::DictionaryValue* response) {
   base::Value* error_body;
   if (response->Get("error", &error_body)) {
-    base::JSONWriter::Write(error_body, &error_);
+    base::JSONWriter::Write(*error_body, &error_);
     SendResponse(false);
     return;
   }
diff --git a/chrome/browser/extensions/api/developer_private/extension_info_generator_unittest.cc b/chrome/browser/extensions/api/developer_private/extension_info_generator_unittest.cc
index 3b7d50d9..65e3aec6 100644
--- a/chrome/browser/extensions/api/developer_private/extension_info_generator_unittest.cc
+++ b/chrome/browser/extensions/api/developer_private/extension_info_generator_unittest.cc
@@ -146,15 +146,15 @@
     std::string actual_string;
     for (base::DictionaryValue::Iterator field(*expected_output_data);
          !field.IsAtEnd(); field.Advance()) {
-      const base::Value* expected_value = &field.value();
+      const base::Value& expected_value = field.value();
       base::Value* actual_value = nullptr;
       EXPECT_TRUE(actual_output_data->Get(field.key(), &actual_value)) <<
           field.key() + " is missing" + paths_details;
       if (!actual_value)
         continue;
-      if (!actual_value->Equals(expected_value)) {
+      if (!actual_value->Equals(&expected_value)) {
         base::JSONWriter::Write(expected_value, &expected_string);
-        base::JSONWriter::Write(actual_value, &actual_string);
+        base::JSONWriter::Write(*actual_value, &actual_string);
         EXPECT_EQ(expected_string, actual_string) <<
             field.key() << paths_details;
       }
diff --git a/chrome/browser/extensions/api/downloads/downloads_api.cc b/chrome/browser/extensions/api/downloads/downloads_api.cc
index 268043e..0d614aa 100644
--- a/chrome/browser/extensions/api/downloads/downloads_api.cc
+++ b/chrome/browser/extensions/api/downloads/downloads_api.cc
@@ -1860,7 +1860,7 @@
   scoped_ptr<base::ListValue> args(new base::ListValue());
   args->Append(arg);
   std::string json_args;
-  base::JSONWriter::Write(args.get(), &json_args);
+  base::JSONWriter::Write(*args, &json_args);
   scoped_ptr<Event> event(new Event(event_name, args.Pass()));
   // The downloads system wants to share on-record events with off-record
   // extension renderers even in incognito_split_mode because that's how
diff --git a/chrome/browser/extensions/api/file_system/file_system_api.cc b/chrome/browser/extensions/api/file_system/file_system_api.cc
index fbf6a83..fce5277 100644
--- a/chrome/browser/extensions/api/file_system/file_system_api.cc
+++ b/chrome/browser/extensions/api/file_system/file_system_api.cc
@@ -318,8 +318,8 @@
   if (!registry)  // Possible on shutdown.
     return;
 
-  ConsentProvider consent_provider(
-      new ConsentProviderDelegate(profile, nullptr));
+  ConsentProviderDelegate consent_provider_delegate(profile, nullptr);
+  ConsentProvider consent_provider(&consent_provider_delegate);
   extensions::api::file_system::VolumeListChangedEvent event_args;
   FillVolumeList(profile, &event_args.volumes);
   for (const auto& extension : registry->enabled_extensions()) {
diff --git a/chrome/browser/extensions/api/instance_id/instance_id_apitest.cc b/chrome/browser/extensions/api/instance_id/instance_id_apitest.cc
index a8c00fb..54f07576 100644
--- a/chrome/browser/extensions/api/instance_id/instance_id_apitest.cc
+++ b/chrome/browser/extensions/api/instance_id/instance_id_apitest.cc
@@ -10,7 +10,7 @@
 #include "chrome/browser/services/gcm/fake_gcm_profile_service.h"
 #include "chrome/browser/services/gcm/gcm_profile_service_factory.h"
 #include "chrome/browser/services/gcm/instance_id/instance_id_profile_service_factory.h"
-#include "chrome/common/chrome_switches.h"
+#include "chrome/common/extensions/features/feature_channel.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "components/gcm_driver/instance_id/fake_gcm_driver_for_instance_id.h"
 #include "extensions/test/result_catcher.h"
@@ -36,7 +36,6 @@
 
  protected:
   void SetUpOnMainThread() override;
-  void SetUpCommandLine(base::CommandLine* command_line) override;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(InstanceIDApiTest);
@@ -49,35 +48,40 @@
   ExtensionApiTest::SetUpOnMainThread();
 }
 
-void InstanceIDApiTest::SetUpCommandLine(base::CommandLine* command_line) {
-  ExtensionApiTest::SetUpCommandLine(command_line);
-
-  // Makes sure InstanceID is enabled for testing.
-  command_line->AppendSwitchASCII(
-      switches::kForceFieldTrials, "InstanceID/Enabled/");
-}
-
 IN_PROC_BROWSER_TEST_F(InstanceIDApiTest, GetID) {
+  extensions::ScopedCurrentChannel current_channel(
+      chrome::VersionInfo::CHANNEL_DEV);
   ASSERT_TRUE(RunExtensionTest("instance_id/get_id"));
 }
 
 IN_PROC_BROWSER_TEST_F(InstanceIDApiTest, GetCreationTime) {
+  extensions::ScopedCurrentChannel current_channel(
+      chrome::VersionInfo::CHANNEL_DEV);
   ASSERT_TRUE(RunExtensionTest("instance_id/get_creation_time"));
 }
 
 IN_PROC_BROWSER_TEST_F(InstanceIDApiTest, DeleteID) {
+  extensions::ScopedCurrentChannel current_channel(
+      chrome::VersionInfo::CHANNEL_DEV);
   ASSERT_TRUE(RunExtensionTest("instance_id/delete_id"));
 }
 
 IN_PROC_BROWSER_TEST_F(InstanceIDApiTest, GetToken) {
+  extensions::ScopedCurrentChannel current_channel(
+      chrome::VersionInfo::CHANNEL_DEV);
   ASSERT_TRUE(RunExtensionTest("instance_id/get_token"));
 }
 
 IN_PROC_BROWSER_TEST_F(InstanceIDApiTest, DeleteToken) {
+  extensions::ScopedCurrentChannel current_channel(
+      chrome::VersionInfo::CHANNEL_DEV);
   ASSERT_TRUE(RunExtensionTest("instance_id/delete_token"));
 }
 
 IN_PROC_BROWSER_TEST_F(InstanceIDApiTest, Incognito) {
+  extensions::ScopedCurrentChannel current_channel(
+      chrome::VersionInfo::CHANNEL_DEV);
+
   ResultCatcher catcher;
   catcher.RestrictToBrowserContext(profile());
   ResultCatcher incognito_catcher;
@@ -90,4 +94,16 @@
   EXPECT_TRUE(incognito_catcher.GetNextResult()) << incognito_catcher.message();
 }
 
+IN_PROC_BROWSER_TEST_F(InstanceIDApiTest, BetaChannel) {
+  extensions::ScopedCurrentChannel current_channel(
+      chrome::VersionInfo::CHANNEL_BETA);
+  ASSERT_TRUE(RunExtensionTest("instance_id/channel"));
+}
+
+IN_PROC_BROWSER_TEST_F(InstanceIDApiTest, StableChannel) {
+  extensions::ScopedCurrentChannel current_channel(
+      chrome::VersionInfo::CHANNEL_STABLE);
+  ASSERT_TRUE(RunExtensionTest("instance_id/channel"));
+}
+
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/launcher_page/launcher_page_api.cc b/chrome/browser/extensions/api/launcher_page/launcher_page_api.cc
index ae0669d7..07bb351 100644
--- a/chrome/browser/extensions/api/launcher_page/launcher_page_api.cc
+++ b/chrome/browser/extensions/api/launcher_page/launcher_page_api.cc
@@ -65,6 +65,19 @@
   return RespondNow(NoArguments());
 }
 
+LauncherPageHideFunction::LauncherPageHideFunction() {
+}
+
+ExtensionFunction::ResponseAction LauncherPageHideFunction::Run() {
+  chrome::HostDesktopType host_desktop =
+      chrome::GetHostDesktopTypeForNativeWindow(
+          GetAssociatedWebContents()->GetTopLevelNativeWindow());
+
+  AppListService::Get(host_desktop)->HideCustomLauncherPage();
+
+  return RespondNow(NoArguments());
+}
+
 LauncherPageSetEnabledFunction::LauncherPageSetEnabledFunction() {
 }
 
diff --git a/chrome/browser/extensions/api/launcher_page/launcher_page_api.h b/chrome/browser/extensions/api/launcher_page/launcher_page_api.h
index 8f3b915b..bd39314 100644
--- a/chrome/browser/extensions/api/launcher_page/launcher_page_api.h
+++ b/chrome/browser/extensions/api/launcher_page/launcher_page_api.h
@@ -65,6 +65,21 @@
   DISALLOW_COPY_AND_ASSIGN(LauncherPageShowFunction);
 };
 
+class LauncherPageHideFunction : public UIThreadExtensionFunction {
+ public:
+  DECLARE_EXTENSION_FUNCTION("launcherPage.hide", LAUNCHERPAGE_HIDE);
+
+  LauncherPageHideFunction();
+
+ protected:
+  ~LauncherPageHideFunction() override {}
+
+  ResponseAction Run() override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(LauncherPageHideFunction);
+};
+
 class LauncherPageSetEnabledFunction : public UIThreadExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("launcherPage.setEnabled",
diff --git a/chrome/browser/extensions/api/media_galleries/media_galleries_apitest.cc b/chrome/browser/extensions/api/media_galleries/media_galleries_apitest.cc
index 1cffad6..67740e1 100644
--- a/chrome/browser/extensions/api/media_galleries/media_galleries_apitest.cc
+++ b/chrome/browser/extensions/api/media_galleries/media_galleries_apitest.cc
@@ -164,7 +164,7 @@
     const char* custom_arg = NULL;
     std::string json_string;
     if (!custom_arg_value.empty()) {
-      base::JSONWriter::Write(&custom_arg_value, &json_string);
+      base::JSONWriter::Write(custom_arg_value, &json_string);
       custom_arg = json_string.c_str();
     }
 
diff --git a/chrome/browser/extensions/api/messaging/message_property_provider.cc b/chrome/browser/extensions/api/messaging/message_property_provider.cc
index cee56d7..a1eb7acf 100644
--- a/chrome/browser/extensions/api/messaging/message_property_provider.cc
+++ b/chrome/browser/extensions/api/messaging/message_property_provider.cc
@@ -100,7 +100,7 @@
     return;
   }
   std::string jwk_str;
-  base::JSONWriter::Write(&jwk_value, &jwk_str);
+  base::JSONWriter::Write(jwk_value, &jwk_str);
   original_task_runner->PostTask(FROM_HERE, base::Bind(reply, jwk_str));
 }
 
diff --git a/chrome/browser/extensions/api/messaging/native_message_host_chromeos.cc b/chrome/browser/extensions/api/messaging/native_message_host_chromeos.cc
index 4977908..0fbc770 100644
--- a/chrome/browser/extensions/api/messaging/native_message_host_chromeos.cc
+++ b/chrome/browser/extensions/api/messaging/native_message_host_chromeos.cc
@@ -70,12 +70,12 @@
 
  private:
   void ProcessEcho(const base::DictionaryValue& request) {
-    scoped_ptr<base::DictionaryValue> response(new base::DictionaryValue());
-    response->SetInteger("id", ++message_number_);
-    response->Set("echo", request.DeepCopy());
-    response->SetString("caller_url", kEchoHostOrigins[0]);
+    base::DictionaryValue response;
+    response.SetInteger("id", ++message_number_);
+    response.Set("echo", request.CreateDeepCopy());
+    response.SetString("caller_url", kEchoHostOrigins[0]);
     std::string response_string;
-    base::JSONWriter::Write(response.get(), &response_string);
+    base::JSONWriter::Write(response, &response_string);
     client_->PostMessageFromNativeHost(response_string);
   }
 
diff --git a/chrome/browser/extensions/api/permissions/permissions_api_helpers.cc b/chrome/browser/extensions/api/permissions/permissions_api_helpers.cc
index 19aa3e14..13ce9b1 100644
--- a/chrome/browser/extensions/api/permissions/permissions_api_helpers.cc
+++ b/chrome/browser/extensions/api/permissions/permissions_api_helpers.cc
@@ -51,7 +51,7 @@
     } else {
       std::string name(i->name());
       std::string json;
-      base::JSONWriter::Write(value.get(), &json);
+      base::JSONWriter::Write(*value, &json);
       permissions->permissions->push_back(name + kDelimiter + json);
     }
   }
diff --git a/chrome/browser/extensions/api/socket/tls_socket_unittest.cc b/chrome/browser/extensions/api/socket/tls_socket_unittest.cc
index 49edd64..858d06d 100644
--- a/chrome/browser/extensions/api/socket/tls_socket_unittest.cc
+++ b/chrome/browser/extensions/api/socket/tls_socket_unittest.cc
@@ -69,6 +69,7 @@
   MOCK_CONST_METHOD0(GetUnverifiedServerCertificateChain,
                      scoped_refptr<net::X509Certificate>());
   MOCK_CONST_METHOD0(GetChannelIDService, net::ChannelIDService*());
+  MOCK_CONST_METHOD0(GetSSLFailureState, net::SSLFailureState());
   bool IsConnected() const override { return true; }
 
  private:
diff --git a/chrome/browser/extensions/api/storage/settings_apitest.cc b/chrome/browser/extensions/api/storage/settings_apitest.cc
index eaa5ea1..50f0383 100644
--- a/chrome/browser/extensions/api/storage/settings_apitest.cc
+++ b/chrome/browser/extensions/api/storage/settings_apitest.cc
@@ -174,12 +174,12 @@
       Namespace settings_namespace,
       const std::string& action,
       bool is_final_action) {
-    scoped_ptr<base::DictionaryValue> message(new base::DictionaryValue());
-    message->SetString("namespace", ToString(settings_namespace));
-    message->SetString("action", action);
-    message->SetBoolean("isFinalAction", is_final_action);
+    base::DictionaryValue message;
+    message.SetString("namespace", ToString(settings_namespace));
+    message.SetString("action", action);
+    message.SetBoolean("isFinalAction", is_final_action);
     std::string message_json;
-    base::JSONWriter::Write(message.get(), &message_json);
+    base::JSONWriter::Write(message, &message_json);
     return message_json;
   }
 
diff --git a/chrome/browser/extensions/api/storage/settings_sync_unittest.cc b/chrome/browser/extensions/api/storage/settings_sync_unittest.cc
index 9ed1922f..ab4f521a 100644
--- a/chrome/browser/extensions/api/storage/settings_sync_unittest.cc
+++ b/chrome/browser/extensions/api/storage/settings_sync_unittest.cc
@@ -45,9 +45,8 @@
 // Gets the pretty-printed JSON for a value.
 static std::string GetJson(const base::Value& value) {
   std::string json;
-  base::JSONWriter::WriteWithOptions(&value,
-                                     base::JSONWriter::OPTIONS_PRETTY_PRINT,
-                                     &json);
+  base::JSONWriter::WriteWithOptions(
+      value, base::JSONWriter::OPTIONS_PRETTY_PRINT, &json);
   return json;
 }
 
diff --git a/chrome/browser/extensions/api/storage/settings_sync_util.cc b/chrome/browser/extensions/api/storage/settings_sync_util.cc
index c187c52d..ccd9a44 100644
--- a/chrome/browser/extensions/api/storage/settings_sync_util.cc
+++ b/chrome/browser/extensions/api/storage/settings_sync_util.cc
@@ -30,7 +30,7 @@
   specifics->set_key(key);
   {
     std::string value_as_json;
-    base::JSONWriter::Write(&value, &value_as_json);
+    base::JSONWriter::Write(value, &value_as_json);
     specifics->set_value(value_as_json);
   }
 }
diff --git a/chrome/browser/extensions/api/web_navigation/frame_navigation_state.cc b/chrome/browser/extensions/api/web_navigation/frame_navigation_state.cc
index 37764cb..635653748 100644
--- a/chrome/browser/extensions/api/web_navigation/frame_navigation_state.cc
+++ b/chrome/browser/extensions/api/web_navigation/frame_navigation_state.cc
@@ -37,17 +37,8 @@
 
 FrameNavigationState::~FrameNavigationState() {}
 
-bool FrameNavigationState::CanSendEvents(
-    content::RenderFrameHost* frame_host) const {
-  FrameHostToStateMap::const_iterator it =
-      frame_host_state_map_.find(frame_host);
-  if (it == frame_host_state_map_.end() || it->second.error_occurred) {
-    return false;
-  }
-  return IsValidUrl(it->second.url);
-}
-
-bool FrameNavigationState::IsValidUrl(const GURL& url) const {
+// static
+bool FrameNavigationState::IsValidUrl(const GURL& url) {
   for (unsigned i = 0; i < arraysize(kValidSchemes); ++i) {
     if (url.scheme() == kValidSchemes[i])
       return true;
@@ -60,6 +51,16 @@
   return allow_extension_scheme_ && url.scheme() == kExtensionScheme;
 }
 
+bool FrameNavigationState::CanSendEvents(
+    content::RenderFrameHost* frame_host) const {
+  FrameHostToStateMap::const_iterator it =
+      frame_host_state_map_.find(frame_host);
+  if (it == frame_host_state_map_.end() || it->second.error_occurred) {
+    return false;
+  }
+  return IsValidUrl(it->second.url);
+}
+
 void FrameNavigationState::StartTrackingNavigation(
     content::RenderFrameHost* frame_host,
     const GURL& url,
diff --git a/chrome/browser/extensions/api/web_navigation/frame_navigation_state.h b/chrome/browser/extensions/api/web_navigation/frame_navigation_state.h
index 2e4a300..3751870 100644
--- a/chrome/browser/extensions/api/web_navigation/frame_navigation_state.h
+++ b/chrome/browser/extensions/api/web_navigation/frame_navigation_state.h
@@ -28,6 +28,9 @@
   FrameNavigationState();
   ~FrameNavigationState();
 
+  // True if in general webNavigation events may be sent for the given URL.
+  static bool IsValidUrl(const GURL& url);
+
   // Use these to iterate over all frame hosts known by this object.
   const_iterator begin() const { return frame_hosts_.begin(); }
   const_iterator end() const { return frame_hosts_.end(); }
@@ -35,10 +38,6 @@
   // True if navigation events for the given frame can be sent.
   bool CanSendEvents(content::RenderFrameHost* frame_host) const;
 
-  // TODO(dcheng): This should be static.
-  // True if in general webNavigation events may be sent for the given URL.
-  bool IsValidUrl(const GURL& url) const;
-
   // Starts to track a navigation in |frame_host| to |url|.
   void StartTrackingNavigation(content::RenderFrameHost* frame_host,
                                const GURL& url,
diff --git a/chrome/browser/extensions/api/web_navigation/web_navigation_api.cc b/chrome/browser/extensions/api/web_navigation/web_navigation_api.cc
index aa6c568..d5a9dda 100644
--- a/chrome/browser/extensions/api/web_navigation/web_navigation_api.cc
+++ b/chrome/browser/extensions/api/web_navigation/web_navigation_api.cc
@@ -122,11 +122,8 @@
     DCHECK(GetViewType(old_contents) != VIEW_TYPE_TAB_CONTENTS);
     return;
   }
-  const FrameNavigationState& frame_navigation_state =
-      tab_observer->frame_navigation_state();
-
-  if (!frame_navigation_state.IsValidUrl(old_contents->GetURL()) ||
-      !frame_navigation_state.IsValidUrl(new_contents->GetURL()))
+  if (!FrameNavigationState::IsValidUrl(old_contents->GetURL()) ||
+      !FrameNavigationState::IsValidUrl(new_contents->GetURL()))
     return;
 
   helpers::DispatchOnTabReplaced(old_contents, profile_, new_contents);
@@ -322,31 +319,21 @@
   if (!navigation_state_.CanSendEvents(render_frame_host))
     return;
 
+  std::string event_name;
   if (is_reference_fragment_navigation) {
-    helpers::DispatchOnCommitted(
-        web_navigation::OnReferenceFragmentUpdated::kEventName,
-        web_contents(),
-        render_frame_host,
-        navigation_state_.GetUrl(render_frame_host),
-        transition_type);
+    event_name = web_navigation::OnReferenceFragmentUpdated::kEventName;
   } else if (is_history_state_modification) {
-    helpers::DispatchOnCommitted(
-        web_navigation::OnHistoryStateUpdated::kEventName,
-        web_contents(),
-        render_frame_host,
-        navigation_state_.GetUrl(render_frame_host),
-        transition_type);
+    event_name = web_navigation::OnHistoryStateUpdated::kEventName;
   } else {
     if (navigation_state_.GetIsServerRedirected(render_frame_host)) {
       transition_type = ui::PageTransitionFromInt(
           transition_type | ui::PAGE_TRANSITION_SERVER_REDIRECT);
     }
-    helpers::DispatchOnCommitted(web_navigation::OnCommitted::kEventName,
-                                 web_contents(),
-                                 render_frame_host,
-                                 navigation_state_.GetUrl(render_frame_host),
-                                 transition_type);
+    event_name = web_navigation::OnCommitted::kEventName;
   }
+  helpers::DispatchOnCommitted(event_name, web_contents(), render_frame_host,
+                               navigation_state_.GetUrl(render_frame_host),
+                               transition_type);
 }
 
 void WebNavigationTabObserver::DidFailProvisionalLoad(
diff --git a/chrome/browser/extensions/api/webrtc_audio_private/webrtc_audio_private_browsertest.cc b/chrome/browser/extensions/api/webrtc_audio_private/webrtc_audio_private_browsertest.cc
index 95bcf2e..289aeec 100644
--- a/chrome/browser/extensions/api/webrtc_audio_private/webrtc_audio_private_browsertest.cc
+++ b/chrome/browser/extensions/api/webrtc_audio_private/webrtc_audio_private_browsertest.cc
@@ -94,7 +94,7 @@
     base::ListValue parameters;
     AppendTabIdToRequestInfo(&parameters, tab_id);
     std::string parameter_string;
-    JSONWriter::Write(&parameters, &parameter_string);
+    JSONWriter::Write(parameters, &parameter_string);
 
     scoped_refptr<WebrtcAudioPrivateGetActiveSinkFunction> function =
         new WebrtcAudioPrivateGetActiveSinkFunction();
@@ -180,7 +180,7 @@
   scoped_ptr<base::Value> result = InvokeGetSinks(&sink_list);
 
   std::string result_string;
-  JSONWriter::Write(result.get(), &result_string);
+  JSONWriter::Write(*result, &result_string);
   VLOG(2) << result_string;
 
   EXPECT_EQ(devices.size(), sink_list->GetSize());
@@ -229,7 +229,7 @@
   base::ListValue parameters;
   AppendTabIdToRequestInfo(&parameters, tab_id);
   std::string parameter_string;
-  JSONWriter::Write(&parameters, &parameter_string);
+  JSONWriter::Write(parameters, &parameter_string);
 
   scoped_refptr<WebrtcAudioPrivateGetActiveSinkFunction> function =
       new WebrtcAudioPrivateGetActiveSinkFunction();
@@ -240,7 +240,7 @@
                                        browser()));
 
   std::string result_string;
-  JSONWriter::Write(result.get(), &result_string);
+  JSONWriter::Write(*result, &result_string);
   EXPECT_EQ("\"\"", result_string);
 }
 
@@ -253,7 +253,7 @@
   AppendTabIdToRequestInfo(&parameters, tab_id);
   parameters.AppendString("no such id");
   std::string parameter_string;
-  JSONWriter::Write(&parameters, &parameter_string);
+  JSONWriter::Write(parameters, &parameter_string);
 
   scoped_refptr<WebrtcAudioPrivateSetActiveSinkFunction> function =
       new WebrtcAudioPrivateSetActiveSinkFunction();
@@ -299,7 +299,7 @@
     AppendTabIdToRequestInfo(&parameters, tab_id);
     parameters.AppendString(target_device);
     std::string parameter_string;
-    JSONWriter::Write(&parameters, &parameter_string);
+    JSONWriter::Write(parameters, &parameter_string);
 
     scoped_refptr<WebrtcAudioPrivateSetActiveSinkFunction> function =
       new WebrtcAudioPrivateSetActiveSinkFunction();
@@ -345,14 +345,14 @@
     parameters.AppendString(origin.spec());
     parameters.AppendString(source_id_in_origin);
     std::string parameter_string;
-    JSONWriter::Write(&parameters, &parameter_string);
+    JSONWriter::Write(parameters, &parameter_string);
 
     scoped_ptr<base::Value> result(
         RunFunctionAndReturnSingleResult(function.get(),
                                          parameter_string,
                                          browser()));
     std::string result_string;
-    JSONWriter::Write(result.get(), &result_string);
+    JSONWriter::Write(*result, &result_string);
     VLOG(2) << "Results: " << result_string;
   }
 }
diff --git a/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_apitest.cc b/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_apitest.cc
index fc80b08..cb5ab5e9 100644
--- a/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_apitest.cc
+++ b/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_apitest.cc
@@ -35,7 +35,7 @@
 
 std::string ParamsToString(const base::ListValue& parameters) {
   std::string parameter_string;
-  EXPECT_TRUE(base::JSONWriter::Write(&parameters, &parameter_string));
+  EXPECT_TRUE(base::JSONWriter::Write(parameters, &parameter_string));
   return parameter_string;
 }
 
diff --git a/chrome/browser/extensions/dev_mode_bubble_controller.cc b/chrome/browser/extensions/dev_mode_bubble_controller.cc
index e02ffc9..7f4a3e7 100644
--- a/chrome/browser/extensions/dev_mode_bubble_controller.cc
+++ b/chrome/browser/extensions/dev_mode_bubble_controller.cc
@@ -41,7 +41,8 @@
       ExtensionMessageBubbleController::BubbleAction user_action) override;
   void PerformAction(const ExtensionIdList& list) override;
   base::string16 GetTitle() const override;
-  base::string16 GetMessageBody(bool anchored_to_browser_action) const override;
+  base::string16 GetMessageBody(bool anchored_to_browser_action,
+                                int extension_count) const override;
   base::string16 GetOverflowText(
       const base::string16& overflow_count) const override;
   GURL GetLearnMoreUrl() const override;
@@ -92,7 +93,8 @@
 }
 
 base::string16 DevModeBubbleDelegate::GetMessageBody(
-    bool anchored_to_browser_action) const {
+    bool anchored_to_browser_action,
+    int extension_count) const {
   return l10n_util::GetStringUTF16(IDS_EXTENSIONS_DISABLE_DEVELOPER_MODE_BODY);
 }
 
diff --git a/chrome/browser/extensions/extension_fullscreen_apitest.cc b/chrome/browser/extensions/extension_fullscreen_apitest.cc
index 9abe3c3..198fd71f 100644
--- a/chrome/browser/extensions/extension_fullscreen_apitest.cc
+++ b/chrome/browser/extensions/extension_fullscreen_apitest.cc
@@ -7,13 +7,19 @@
 
 IN_PROC_BROWSER_TEST_F(ExtensionApiTest,
                        ExtensionFullscreenAccessFail) {
-  // Test that fullscreen can be accessed from an extension without permission.
+  // Test that fullscreen cannot be accessed from an extension without
+  // permission.
   ASSERT_TRUE(RunPlatformAppTest("fullscreen/no_permission")) << message_;
 }
 
-// Disabled, a user gesture is required for fullscreen. http://crbug.com/174178
-IN_PROC_BROWSER_TEST_F(ExtensionApiTest,
-                       DISABLED_ExtensionFullscreenAccessPass) {
+#if defined(OS_MACOSX)
+// Fails on MAC: http://crbug.com/480370
+#define MAYBE_ExtensionFullscreenAccessPass \
+    DISABLED_ExtensionFullscreenAccessPass
+#else
+#define MAYBE_ExtensionFullscreenAccessPass ExtensionFullscreenAccessPass
+#endif  // defined(OS_MACOSX)
+IN_PROC_BROWSER_TEST_F(ExtensionApiTest, MAYBE_ExtensionFullscreenAccessPass) {
   // Test that fullscreen can be accessed from an extension with permission.
   ASSERT_TRUE(RunPlatformAppTest("fullscreen/has_permission")) << message_;
 }
diff --git a/chrome/browser/extensions/extension_message_bubble_controller.h b/chrome/browser/extensions/extension_message_bubble_controller.h
index 5e3d878..6d6e803f 100644
--- a/chrome/browser/extensions/extension_message_bubble_controller.h
+++ b/chrome/browser/extensions/extension_message_bubble_controller.h
@@ -46,8 +46,10 @@
     // icon, allowing the bubble to show a different message than when it is
     // anchored against something else (e.g. show "This extension has..."
     // instead of "An extension has...").
+    // |extension_count| is the number of extensions being referenced.
     virtual base::string16 GetMessageBody(
-        bool anchored_to_browser_action) const = 0;
+        bool anchored_to_browser_action,
+        int extension_count) const = 0;
     virtual base::string16 GetOverflowText(
         const base::string16& overflow_count) const = 0;
     virtual base::string16 GetLearnMoreLabel() const;
diff --git a/chrome/browser/extensions/extension_messages_apitest.cc b/chrome/browser/extensions/extension_messages_apitest.cc
index 1c4305257..9edda30 100644
--- a/chrome/browser/extensions/extension_messages_apitest.cc
+++ b/chrome/browser/extensions/extension_messages_apitest.cc
@@ -994,7 +994,7 @@
     base::DictionaryValue jwk_value;
     net::JwkSerializer::ConvertSpkiFromDerToJwk(spki, &jwk_value);
     std::string tls_channel_id_value;
-    base::JSONWriter::Write(&jwk_value, &tls_channel_id_value);
+    base::JSONWriter::Write(jwk_value, &tls_channel_id_value);
     return tls_channel_id_value;
   }
 
diff --git a/chrome/browser/extensions/extension_uninstall_dialog.cc b/chrome/browser/extensions/extension_uninstall_dialog.cc
index 1e39567..0f9b728 100644
--- a/chrome/browser/extensions/extension_uninstall_dialog.cc
+++ b/chrome/browser/extensions/extension_uninstall_dialog.cc
@@ -48,8 +48,6 @@
     ExtensionUninstallDialog::Delegate* delegate)
     : profile_(profile),
       delegate_(delegate),
-      extension_(NULL),
-      triggering_extension_(NULL),
       ui_loop_(base::MessageLoop::current()) {
 }
 
@@ -71,7 +69,7 @@
                             ? extension_misc::EXTENSION_ICON_SMALL * 2
                             : extension_misc::EXTENSION_ICON_LARGE;
   ExtensionResource image = IconsInfo::GetIconResource(
-      extension_, icon_size, ExtensionIconSet::MATCH_BIGGER);
+      extension_.get(), icon_size, ExtensionIconSet::MATCH_BIGGER);
 
   // Load the image asynchronously. The response will be sent to OnImageLoaded.
   ImageLoader* loader = ImageLoader::Get(profile_);
@@ -83,7 +81,7 @@
       ImageLoader::ImageRepresentation::NEVER_RESIZE,
       gfx::Size(),
       ui::SCALE_FACTOR_100P));
-  loader->LoadImagesAsync(extension_,
+  loader->LoadImagesAsync(extension_.get(),
                           images_list,
                           base::Bind(&ExtensionUninstallDialog::OnImageLoaded,
                                      AsWeakPtr(),
@@ -130,7 +128,7 @@
 }
 
 bool ExtensionUninstallDialog::ShouldShowReportAbuseCheckbox() const {
-  return ManifestURL::UpdatesFromGallery(extension_);
+  return ManifestURL::UpdatesFromGallery(extension_.get());
 }
 
 void ExtensionUninstallDialog::OnDialogClosed(CloseAction action) {
diff --git a/chrome/browser/extensions/extension_uninstall_dialog.h b/chrome/browser/extensions/extension_uninstall_dialog.h
index 4a3a32f2..3f750281 100644
--- a/chrome/browser/extensions/extension_uninstall_dialog.h
+++ b/chrome/browser/extensions/extension_uninstall_dialog.h
@@ -91,11 +91,11 @@
   Delegate* delegate_;
 
   // The extension we are showing the dialog for.
-  const Extension* extension_;
+  scoped_refptr<const Extension> extension_;
 
   // The extension triggering the dialog if the dialog was shown by
   // chrome.management.uninstall.
-  const Extension* triggering_extension_;
+  scoped_refptr<const Extension> triggering_extension_;
 
   // The extensions icon.
   gfx::ImageSkia icon_;
diff --git a/chrome/browser/extensions/install_signer.cc b/chrome/browser/extensions/install_signer.cc
index 1fca16a..afb88cc 100644
--- a/chrome/browser/extensions/install_signer.cc
+++ b/chrome/browser/extensions/install_signer.cc
@@ -388,7 +388,7 @@
   }
   dictionary.Set(kIdsKey, id_list.release());
   std::string json;
-  base::JSONWriter::Write(&dictionary, &json);
+  base::JSONWriter::Write(dictionary, &json);
   if (json.empty()) {
     ReportErrorViaCallback();
     return;
diff --git a/chrome/browser/extensions/ntp_overridden_bubble_controller.cc b/chrome/browser/extensions/ntp_overridden_bubble_controller.cc
index 317b7bae..86e437d 100644
--- a/chrome/browser/extensions/ntp_overridden_bubble_controller.cc
+++ b/chrome/browser/extensions/ntp_overridden_bubble_controller.cc
@@ -40,7 +40,8 @@
       override;
   void PerformAction(const extensions::ExtensionIdList& list) override;
   base::string16 GetTitle() const override;
-  base::string16 GetMessageBody(bool anchored_to_browser_action) const override;
+  base::string16 GetMessageBody(bool anchored_to_browser_action,
+                                int extension_count) const override;
   base::string16 GetOverflowText(
       const base::string16& overflow_count) const override;
   GURL GetLearnMoreUrl() const override;
@@ -112,7 +113,8 @@
 }
 
 base::string16 NtpOverriddenBubbleDelegate::GetMessageBody(
-    bool anchored_to_browser_action) const {
+    bool anchored_to_browser_action,
+    int extension_count) const {
   base::string16 body =
       l10n_util::GetStringUTF16(IDS_EXTENSIONS_NTP_CONTROLLED_FIRST_LINE);
   body += l10n_util::GetStringUTF16(
diff --git a/chrome/browser/extensions/proxy_overridden_bubble_controller.cc b/chrome/browser/extensions/proxy_overridden_bubble_controller.cc
index 3d81d16b..0a40141 100644
--- a/chrome/browser/extensions/proxy_overridden_bubble_controller.cc
+++ b/chrome/browser/extensions/proxy_overridden_bubble_controller.cc
@@ -44,7 +44,8 @@
       ExtensionMessageBubbleController::BubbleAction user_action) override;
   void PerformAction(const ExtensionIdList& list) override;
   base::string16 GetTitle() const override;
-  base::string16 GetMessageBody(bool anchored_to_browser_action) const override;
+  base::string16 GetMessageBody(bool anchored_to_browser_action,
+                                int extension_count) const override;
   base::string16 GetOverflowText(
       const base::string16& overflow_count) const override;
   GURL GetLearnMoreUrl() const override;
@@ -122,7 +123,8 @@
 }
 
 base::string16 ProxyOverriddenBubbleDelegate::GetMessageBody(
-    bool anchored_to_browser_action) const {
+    bool anchored_to_browser_action,
+    int extension_count) const {
   if (anchored_to_browser_action) {
     return l10n_util::GetStringUTF16(
         IDS_EXTENSIONS_PROXY_CONTROLLED_FIRST_LINE_EXTENSION_SPECIFIC);
diff --git a/chrome/browser/extensions/settings_api_bubble_controller.cc b/chrome/browser/extensions/settings_api_bubble_controller.cc
index c13239f..7a4f65d 100644
--- a/chrome/browser/extensions/settings_api_bubble_controller.cc
+++ b/chrome/browser/extensions/settings_api_bubble_controller.cc
@@ -46,7 +46,8 @@
       ExtensionMessageBubbleController::BubbleAction user_action) override;
   void PerformAction(const ExtensionIdList& list) override;
   base::string16 GetTitle() const override;
-  base::string16 GetMessageBody(bool anchored_to_browser_action) const override;
+  base::string16 GetMessageBody(bool anchored_to_browser_action,
+                                int extension_count) const override;
   base::string16 GetOverflowText(
       const base::string16& overflow_count) const override;
   GURL GetLearnMoreUrl() const override;
@@ -149,7 +150,8 @@
 }
 
 base::string16 SettingsApiBubbleDelegate::GetMessageBody(
-    bool anchored_to_browser_action) const {
+    bool anchored_to_browser_action,
+    int extension_count) const {
   ExtensionRegistry* registry = ExtensionRegistry::Get(profile());
   const Extension* extension =
       registry->GetExtensionById(extension_id_, ExtensionRegistry::ENABLED);
diff --git a/chrome/browser/extensions/suspicious_extension_bubble_controller.cc b/chrome/browser/extensions/suspicious_extension_bubble_controller.cc
index 94d189f..3f045e3d 100644
--- a/chrome/browser/extensions/suspicious_extension_bubble_controller.cc
+++ b/chrome/browser/extensions/suspicious_extension_bubble_controller.cc
@@ -46,7 +46,8 @@
       ExtensionMessageBubbleController::BubbleAction user_action) override;
   void PerformAction(const extensions::ExtensionIdList& list) override;
   base::string16 GetTitle() const override;
-  base::string16 GetMessageBody(bool anchored_to_browser_action) const override;
+  base::string16 GetMessageBody(bool anchored_to_browser_action,
+                                int extension_count) const override;
   base::string16 GetOverflowText(
       const base::string16& overflow_count) const override;
   GURL GetLearnMoreUrl() const override;
@@ -101,9 +102,13 @@
 }
 
 base::string16 SuspiciousExtensionBubbleDelegate::GetMessageBody(
-    bool anchored_to_browser_action) const {
-  return l10n_util::GetStringFUTF16(IDS_EXTENSIONS_UNSUPPORTED_DISABLED_BODY,
-      l10n_util::GetStringUTF16(IDS_EXTENSION_WEB_STORE_TITLE));
+    bool anchored_to_browser_action,
+    int extension_count) const {
+  int message_id = extension_count == 1 ?
+      IDS_EXTENSIONS_SINGLE_UNSUPPORTED_DISABLED_BODY :
+      IDS_EXTENSIONS_MULTIPLE_UNSUPPORTED_DISABLED_BODY;
+  return l10n_util::GetStringFUTF16(
+      message_id, l10n_util::GetStringUTF16(IDS_EXTENSION_WEB_STORE_TITLE));
 }
 
 base::string16 SuspiciousExtensionBubbleDelegate::GetOverflowText(
diff --git a/chrome/browser/extensions/test_extension_environment.cc b/chrome/browser/extensions/test_extension_environment.cc
index f8478fcb..6914ab0 100644
--- a/chrome/browser/extensions/test_extension_environment.cc
+++ b/chrome/browser/extensions/test_extension_environment.cc
@@ -41,7 +41,7 @@
     manifest->MergeDictionary(manifest_extra_dict);
   } else {
     std::string manifest_json;
-    base::JSONWriter::Write(&manifest_extra, &manifest_json);
+    base::JSONWriter::Write(manifest_extra, &manifest_json);
     ADD_FAILURE() << "Expected dictionary; got \"" << manifest_json << "\"";
   }
   return manifest;
diff --git a/chrome/browser/file_select_helper.cc b/chrome/browser/file_select_helper.cc
index 22a8fb4a..92f3b967 100644
--- a/chrome/browser/file_select_helper.cc
+++ b/chrome/browser/file_select_helper.cc
@@ -292,6 +292,16 @@
   temporary_files_.clear();
 }
 
+void FileSelectHelper::CleanUpOnRenderViewHostChange() {
+  if (!temporary_files_.empty()) {
+    DeleteTemporaryFiles();
+
+    // Now that the temporary files have been scheduled for deletion, there
+    // is no longer any reason to keep this instance around.
+    Release();
+  }
+}
+
 scoped_ptr<ui::SelectFileDialog::FileTypeInfo>
 FileSelectHelper::GetFileTypesFromAcceptType(
     const std::vector<base::string16>& accept_types) {
@@ -390,16 +400,11 @@
   render_view_host_ = render_view_host;
   web_contents_ = web_contents;
   notification_registrar_.RemoveAll();
-  notification_registrar_.Add(this,
-                              content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED,
-                              content::Source<WebContents>(web_contents_));
+  content::WebContentsObserver::Observe(web_contents_);
   notification_registrar_.Add(
       this,
       content::NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED,
       content::Source<RenderWidgetHost>(render_view_host_));
-  notification_registrar_.Add(
-      this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
-      content::Source<WebContents>(web_contents_));
 
   BrowserThread::PostTask(
       BrowserThread::FILE, FROM_HERE,
@@ -534,29 +539,21 @@
       render_view_host_ = NULL;
       break;
     }
-
-    case content::NOTIFICATION_WEB_CONTENTS_DESTROYED: {
-      DCHECK(content::Source<WebContents>(source).ptr() == web_contents_);
-      web_contents_ = NULL;
-    }
-
-    // Intentional fall through.
-    case content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED:
-      if (!temporary_files_.empty()) {
-        DeleteTemporaryFiles();
-
-        // Now that the temporary files have been scheduled for deletion, there
-        // is no longer any reason to keep this instance around.
-        Release();
-      }
-
-      break;
-
     default:
       NOTREACHED();
   }
 }
 
+void FileSelectHelper::RenderViewHostChanged(RenderViewHost* old_host,
+                                             RenderViewHost* new_host) {
+  CleanUpOnRenderViewHostChange();
+}
+
+void FileSelectHelper::WebContentsDestroyed() {
+  web_contents_ = nullptr;
+  CleanUpOnRenderViewHostChange();
+}
+
 // static
 bool FileSelectHelper::IsAcceptTypeValid(const std::string& accept_type) {
   // TODO(raymes): This only does some basic checks, extend to test more cases.
diff --git a/chrome/browser/file_select_helper.h b/chrome/browser/file_select_helper.h
index 06672ba8..0067b8a 100644
--- a/chrome/browser/file_select_helper.h
+++ b/chrome/browser/file_select_helper.h
@@ -12,6 +12,7 @@
 #include "base/gtest_prod_util.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
+#include "content/public/browser/web_contents_observer.h"
 #include "content/public/common/file_chooser_params.h"
 #include "net/base/directory_lister.h"
 #include "ui/shell_dialogs/select_file_dialog.h"
@@ -31,10 +32,10 @@
 // This class handles file-selection requests coming from WebUI elements
 // (via the extensions::ExtensionHost class). It implements both the
 // initialisation and listener functions for file-selection dialogs.
-class FileSelectHelper
-    : public base::RefCountedThreadSafe<FileSelectHelper>,
-      public ui::SelectFileDialog::Listener,
-      public content::NotificationObserver {
+class FileSelectHelper : public base::RefCountedThreadSafe<FileSelectHelper>,
+                         public ui::SelectFileDialog::Listener,
+                         public content::WebContentsObserver,
+                         public content::NotificationObserver {
  public:
 
   // Show the file chooser dialog.
@@ -105,6 +106,11 @@
                const content::NotificationSource& source,
                const content::NotificationDetails& details) override;
 
+  // content::WebContentsObserver overrides.
+  void RenderViewHostChanged(content::RenderViewHost* old_host,
+                             content::RenderViewHost* new_host) override;
+  void WebContentsDestroyed() override;
+
   void EnumerateDirectory(int request_id,
                           content::RenderViewHost* render_view_host,
                           const base::FilePath& path);
@@ -155,6 +161,9 @@
   // vector.
   void DeleteTemporaryFiles();
 
+  // Cleans up when the RenderViewHost of our WebContents changes.
+  void CleanUpOnRenderViewHostChange();
+
   // Helper method to get allowed extensions for select file dialog from
   // the specified accept types as defined in the spec:
   //   http://whatwg.org/html/number-state.html#attr-input-accept
diff --git a/chrome/browser/guest_view/web_view/chrome_web_view_guest_delegate.cc b/chrome/browser/guest_view/web_view/chrome_web_view_guest_delegate.cc
index 170a561..d2570020 100644
--- a/chrome/browser/guest_view/web_view/chrome_web_view_guest_delegate.cc
+++ b/chrome/browser/guest_view/web_view/chrome_web_view_guest_delegate.cc
@@ -35,7 +35,6 @@
 ChromeWebViewGuestDelegate::ChromeWebViewGuestDelegate(
     WebViewGuest* web_view_guest)
     : pending_context_menu_request_id_(0),
-      chromevox_injected_(false),
       web_view_guest_(web_view_guest),
       weak_ptr_factory_(this) {
 }
@@ -83,29 +82,6 @@
           new ChromePDFWebContentsHelperClient()));
 }
 
-void ChromeWebViewGuestDelegate::OnDidCommitProvisionalLoadForFrame(
-    bool is_main_frame) {
-  if (is_main_frame)
-    chromevox_injected_ = false;
-}
-
-void ChromeWebViewGuestDelegate::OnDidInitialize() {
-#if defined(OS_CHROMEOS)
-  chromeos::AccessibilityManager* accessibility_manager =
-      chromeos::AccessibilityManager::Get();
-  CHECK(accessibility_manager);
-  accessibility_subscription_ = accessibility_manager->RegisterCallback(
-      base::Bind(&ChromeWebViewGuestDelegate::OnAccessibilityStatusChanged,
-                 weak_ptr_factory_.GetWeakPtr()));
-#endif
-}
-
-void ChromeWebViewGuestDelegate::OnDocumentLoadedInFrame(
-    content::RenderFrameHost* render_frame_host) {
-  if (!render_frame_host->GetParent())
-    InjectChromeVoxIfNeeded(render_frame_host->GetRenderViewHost());
-}
-
 void ChromeWebViewGuestDelegate::OnGuestDestroyed() {
   // Clean up custom context menu items for this guest.
   MenuManager* menu_manager = MenuManager::Get(
@@ -149,33 +125,4 @@
   menu_delegate->ShowMenu(pending_menu_.Pass());
 }
 
-void ChromeWebViewGuestDelegate::InjectChromeVoxIfNeeded(
-    content::RenderViewHost* render_view_host) {
-#if defined(OS_CHROMEOS)
-  if (!chromevox_injected_) {
-    chromeos::AccessibilityManager* manager =
-        chromeos::AccessibilityManager::Get();
-    if (manager && manager->IsSpokenFeedbackEnabled()) {
-      manager->InjectChromeVox(render_view_host);
-      chromevox_injected_ = true;
-    }
-  }
-#endif
-}
-
-#if defined(OS_CHROMEOS)
-void ChromeWebViewGuestDelegate::OnAccessibilityStatusChanged(
-    const chromeos::AccessibilityStatusEventDetails& details) {
-  if (details.notification_type == chromeos::ACCESSIBILITY_MANAGER_SHUTDOWN) {
-    accessibility_subscription_.reset();
-  } else if (details.notification_type ==
-      chromeos::ACCESSIBILITY_TOGGLE_SPOKEN_FEEDBACK) {
-    if (details.enabled)
-      InjectChromeVoxIfNeeded(guest_web_contents()->GetRenderViewHost());
-    else
-      chromevox_injected_ = false;
-  }
-}
-#endif
-
 }  // namespace extensions
diff --git a/chrome/browser/guest_view/web_view/chrome_web_view_guest_delegate.h b/chrome/browser/guest_view/web_view/chrome_web_view_guest_delegate.h
index aae364a..d21d8a47 100644
--- a/chrome/browser/guest_view/web_view/chrome_web_view_guest_delegate.h
+++ b/chrome/browser/guest_view/web_view/chrome_web_view_guest_delegate.h
@@ -29,10 +29,6 @@
   // WebViewGuestDelegate implementation.
   bool HandleContextMenu(const content::ContextMenuParams& params) override;
   void OnAttachWebViewHelpers(content::WebContents* contents) override;
-  void OnDidCommitProvisionalLoadForFrame(bool is_main_frame) override;
-  void OnDidInitialize() override;
-  void OnDocumentLoadedInFrame(
-      content::RenderFrameHost* render_frame_host) override;
   void OnGuestDestroyed() override;
   void OnShowContextMenu(int request_id, const MenuItemVector* items) override;
 
@@ -47,31 +43,14 @@
   static scoped_ptr<base::ListValue> MenuModelToValue(
       const ui::SimpleMenuModel& menu_model);
 
-  void InjectChromeVoxIfNeeded(content::RenderViewHost* render_view_host);
-
-#if defined(OS_CHROMEOS)
-  // Notification of a change in the state of an accessibility setting.
-  void OnAccessibilityStatusChanged(
-      const chromeos::AccessibilityStatusEventDetails& details);
-#endif
-
   // A counter to generate a unique request id for a context menu request.
   // We only need the ids to be unique for a given WebViewGuest.
   int pending_context_menu_request_id_;
 
-  // Set to |true| if ChromeVox was already injected in main frame.
-  bool chromevox_injected_;
-
   // Holds the RenderViewContextMenuBase that has been built but yet to be
   // shown. This is .reset() after ShowContextMenu().
   scoped_ptr<RenderViewContextMenuBase> pending_menu_;
 
-#if defined(OS_CHROMEOS)
-  // Subscription to receive notifications on changes to a11y settings.
-  scoped_ptr<chromeos::AccessibilityStatusSubscription>
-      accessibility_subscription_;
-#endif
-
   WebViewGuest* const web_view_guest_;
 
   // This is used to ensure pending tasks will not fire after this object is
@@ -84,4 +63,3 @@
 }  // namespace extensions
 
 #endif  // CHROME_BROWSER_GUEST_VIEW_WEB_VIEW_CHROME_WEB_VIEW_GUEST_DELEGATE_H_
-
diff --git a/chrome/browser/io_thread.cc b/chrome/browser/io_thread.cc
index 55767a7..46d0e3e8 100644
--- a/chrome/browser/io_thread.cc
+++ b/chrome/browser/io_thread.cc
@@ -1342,9 +1342,6 @@
         ShouldEnableQuicPortSelection(command_line));
     globals->quic_connection_options =
         GetQuicConnectionOptions(command_line, quic_trial_params);
-    if (ShouldEnableQuicPacing(command_line, quic_trial_params)) {
-      globals->quic_connection_options.push_back(net::kPACE);
-    }
   }
 
   size_t max_packet_length = GetQuicMaxPacketLength(command_line,
@@ -1439,20 +1436,6 @@
   return false;  // Default to disabling port selection on all channels.
 }
 
-bool IOThread::ShouldEnableQuicPacing(
-    const base::CommandLine& command_line,
-    const VariationParameters& quic_trial_params) {
-  if (command_line.HasSwitch(switches::kEnableQuicPacing))
-    return true;
-
-  if (command_line.HasSwitch(switches::kDisableQuicPacing))
-    return false;
-
-  return LowerCaseEqualsASCII(
-      GetVariationParam(quic_trial_params, "enable_pacing"),
-      "true");
-}
-
 net::QuicTagVector IOThread::GetQuicConnectionOptions(
     const base::CommandLine& command_line,
     const VariationParameters& quic_trial_params) {
diff --git a/chrome/browser/io_thread.h b/chrome/browser/io_thread.h
index ca55e19c..0b94438 100644
--- a/chrome/browser/io_thread.h
+++ b/chrome/browser/io_thread.h
@@ -346,12 +346,6 @@
   static bool ShouldEnableQuicPortSelection(
       const base::CommandLine& command_line);
 
-  // Returns true if QUIC packet pacing should be negotiated during the
-  // QUIC handshake.
-  static bool ShouldEnableQuicPacing(
-      const base::CommandLine& command_line,
-      const VariationParameters& quic_trial_params);
-
   // Returns true if QUIC should always require handshake confirmation during
   // the QUIC handshake.
   static bool ShouldQuicAlwaysRequireHandshakeConfirmation(
diff --git a/chrome/browser/io_thread_unittest.cc b/chrome/browser/io_thread_unittest.cc
index 13b21fc6..03e3dc4 100644
--- a/chrome/browser/io_thread_unittest.cc
+++ b/chrome/browser/io_thread_unittest.cc
@@ -80,7 +80,6 @@
 };
 
 TEST_F(IOThreadTest, InitializeNetworkSessionParamsFromGlobals) {
-  globals_.quic_connection_options.push_back(net::kPACE);
   globals_.quic_connection_options.push_back(net::kTBBR);
   globals_.quic_connection_options.push_back(net::kTIME);
 
@@ -220,17 +219,6 @@
   EXPECT_FALSE(IOThread::ShouldEnableQuicForDataReductionProxy());
 }
 
-TEST_F(IOThreadTest, EnablePacingFromCommandLine) {
-  command_line_.AppendSwitch("enable-quic");
-  command_line_.AppendSwitch("enable-quic-pacing");
-
-  ConfigureQuicGlobals();
-  net::HttpNetworkSession::Params params;
-  InitializeNetworkSessionParams(&params);
-  net::QuicTagVector options;
-  options.push_back(net::kPACE);
-  EXPECT_EQ(options, params.quic_connection_options);
-}
 TEST_F(IOThreadTest, DisableInsecureQuicFromFieldTrialParams) {
   field_trial_group_ = "Enabled";
   field_trial_params_["disable_insecure_quic"] = "true";
@@ -241,18 +229,6 @@
   EXPECT_TRUE(params.disable_insecure_quic);
 }
 
-TEST_F(IOThreadTest, EnablePacingFromFieldTrialParams) {
-  field_trial_group_ = "Enabled";
-  field_trial_params_["enable_pacing"] = "true";
-
-  ConfigureQuicGlobals();
-  net::HttpNetworkSession::Params params;
-  InitializeNetworkSessionParams(&params);
-  net::QuicTagVector options;
-  options.push_back(net::kPACE);
-  EXPECT_EQ(options, params.quic_connection_options);
-}
-
 TEST_F(IOThreadTest, PacketLengthFromCommandLine) {
   command_line_.AppendSwitch("enable-quic");
   command_line_.AppendSwitchASCII("quic-max-packet-length", "1450");
@@ -303,14 +279,13 @@
 TEST_F(IOThreadTest, QuicConnectionOptionsFromCommandLine) {
   command_line_.AppendSwitch("enable-quic");
   command_line_.AppendSwitchASCII("quic-connection-options",
-                                  "PACE,TIME,TBBR,REJ");
+                                  "TIME,TBBR,REJ");
 
   ConfigureQuicGlobals();
   net::HttpNetworkSession::Params params;
   InitializeNetworkSessionParams(&params);
 
   net::QuicTagVector options;
-  options.push_back(net::kPACE);
   options.push_back(net::kTIME);
   options.push_back(net::kTBBR);
   options.push_back(net::kREJ);
@@ -319,14 +294,13 @@
 
 TEST_F(IOThreadTest, QuicConnectionOptionsFromFieldTrialParams) {
   field_trial_group_ = "Enabled";
-  field_trial_params_["connection_options"] = "PACE,TIME,TBBR,REJ";
+  field_trial_params_["connection_options"] = "TIME,TBBR,REJ";
 
   ConfigureQuicGlobals();
   net::HttpNetworkSession::Params params;
   InitializeNetworkSessionParams(&params);
 
   net::QuicTagVector options;
-  options.push_back(net::kPACE);
   options.push_back(net::kTIME);
   options.push_back(net::kTBBR);
   options.push_back(net::kREJ);
diff --git a/chrome/browser/lifetime/application_lifetime.cc b/chrome/browser/lifetime/application_lifetime.cc
index 0d80bd11..261e00e0 100644
--- a/chrome/browser/lifetime/application_lifetime.cc
+++ b/chrome/browser/lifetime/application_lifetime.cc
@@ -33,7 +33,6 @@
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
-#include "content/public/browser/browser_shutdown.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/navigation_details.h"
 #include "content/public/browser/notification_service.h"
diff --git a/chrome/browser/local_discovery/privet_http_unittest.cc b/chrome/browser/local_discovery/privet_http_unittest.cc
index f8d5dbe..9fe8500d 100644
--- a/chrome/browser/local_discovery/privet_http_unittest.cc
+++ b/chrome/browser/local_discovery/privet_http_unittest.cc
@@ -222,7 +222,7 @@
   std::string result = json;
   scoped_ptr<base::Value> value(base::JSONReader::Read(result));
   DCHECK(value);
-  base::JSONWriter::Write(value.get(), &result);
+  base::JSONWriter::Write(*value, &result);
   return result;
 }
 
diff --git a/chrome/browser/local_discovery/privetv3_session.cc b/chrome/browser/local_discovery/privetv3_session.cc
index 85a9a42..b278279 100644
--- a/chrome/browser/local_discovery/privetv3_session.cc
+++ b/chrome/browser/local_discovery/privetv3_session.cc
@@ -410,7 +410,7 @@
     on_post_data_.Run(input);
   std::string json;
   base::JSONWriter::WriteWithOptions(
-      &input, base::JSONWriter::OPTIONS_PRETTY_PRINT, &json);
+      input, base::JSONWriter::OPTIONS_PRETTY_PRINT, &json);
   PrivetURLFetcher* fetcher =
       CreateFetcher(api, net::URLFetcher::RequestType::POST, callback);
   fetcher->SetUploadData(cloud_print::kContentTypeJSON, json);
diff --git a/chrome/browser/media/router/BUILD.gn b/chrome/browser/media/router/BUILD.gn
index 6ee9a6f..62caec6 100644
--- a/chrome/browser/media/router/BUILD.gn
+++ b/chrome/browser/media/router/BUILD.gn
@@ -5,85 +5,25 @@
 import("//testing/test.gni")
 import("//third_party/mojo/src/mojo/public/tools/bindings/mojom.gni")
 
-source_set("router") {
-  deps = [
-    ":router_core",
-  ]
-}
+gypi_values = exec_script("//build/gypi_to_gn.py",
+                          [ rebase_path("media_router.gypi") ],
+                          "scope",
+                          [ "media_router.gypi" ])
 
-source_set("router_core") {
+# TODO(mfoltz): Fix problem that requires explicitly listing //skia
+source_set("router") {
   deps = [
     ":mojo_bindings",
     "//base",
+    "//extensions/browser",
     "//components/keyed_service/core",
     "//third_party/mojo/src/mojo/public/cpp/bindings",
+    "//skia",
     "//url",
   ]
-  sources = [
-    "create_session_request.cc",
-    "create_session_request.h",
-    "issue.cc",
-    "issue.h",
-    "issue_manager.cc",
-    "issue_manager.h",
-    "issues_observer.h",
-    "media_route.cc",
-    "media_route.h",
-    "media_route_id.h",
-    "media_router.h",
-    "media_router_type_converters.cc",
-    "media_router_type_converters.h",
-    "media_routes_observer.cc",
-    "media_routes_observer.h",
-    "media_sink.cc",
-    "media_sink.h",
-    "media_sinks_observer.cc",
-    "media_sinks_observer.h",
-    "media_source.cc",
-    "media_source.h",
-    "media_source_helper.cc",
-    "media_source_helper.h",
-    "presentation_media_sinks_observer.cc",
-    "presentation_media_sinks_observer.h",
-    "route_id_manager.cc",
-    "route_id_manager.h",
-  ]
-}
-
-source_set("unit_tests") {
-  testonly = true
-  deps = [
-    ":router_core",
-    ":unit_tests_support",
-    "//base/test:test_support",
-    "//chrome/test:test_support",
-    "//testing/gmock",
-    "//testing/gtest",
-    "//third_party/cld_2:cld2_static",
-    "//third_party/mojo/src/mojo/public/cpp/bindings",
-  ]
-  sources = [
-    "media_route_unittest.cc",
-    "media_router_type_converters_unittest.cc",
-    "media_sink_unittest.cc",
-    "media_source_unittest.cc",
-    "presentation_media_sinks_observer_unittest.cc",
-    "route_id_manager_unittest.cc",
-  ]
-}
-
-source_set("unit_tests_support") {
-  testonly = true
-  deps = [
-    ":router_core",
-    "//testing/gmock",
-  ]
-  sources = [
-    "mock_media_router.cc",
-    "mock_media_router.h",
-    "mock_screen_availability_listener.cc",
-    "mock_screen_availability_listener.h",
-  ]
+  sources = rebase_path(gypi_values.media_router_sources,
+                        ".",
+                        "//chrome/browser/media/router")
 }
 
 mojom("mojo_bindings") {
@@ -92,13 +32,15 @@
   ]
 }
 
-# Optional standalone test binary, for faster isolated builds.
-test("unit_tests_main") {
+source_set("test_support") {
+  testonly = true
   deps = [
-    ":unit_tests",
-    "//testing/gmock:gmock_main",
+    ":mojo_bindings",
+    ":router",
+    "//chrome/test:test_support",
+    "//testing/gmock",
   ]
-  sources = [
-    ":unittest_files",
-  ]
+  sources = rebase_path(gypi_values.media_router_test_support_sources,
+                        ".",
+                        "//chrome/browser/media/router")
 }
diff --git a/chrome/browser/media/router/media_router.gyp b/chrome/browser/media/router/media_router.gyp
index 33e8bc8..7f83664 100644
--- a/chrome/browser/media/router/media_router.gyp
+++ b/chrome/browser/media/router/media_router.gyp
@@ -3,8 +3,12 @@
 # found in the LICENSE file.
 
 {
+  'includes': [
+    'media_router.gypi',
+  ],
   'targets': [
     {
+      # GN version: //chrome/browser/media/router:router
       'target_name': 'media_router',
       'type': 'static_library',
       'include_dirs': [
@@ -13,43 +17,20 @@
       ],
       'dependencies': [
         # media_router_type_converters.h needs the generated file.
-        ':media_router_mojo_gen',
-        ':media_router_mojo',
+        'media_router_mojo_gen',
+        'media_router_mojo',
         '<(DEPTH)/base/base.gyp:base',
+        '<(DEPTH)/components/components.gyp:keyed_service_core',
+        '<(DEPTH)/extensions/extensions.gyp:extensions_browser',
+        '<(DEPTH)/skia/skia.gyp:skia',
         '<(DEPTH)/url/url.gyp:url_lib',
       ],
       'sources': [
-        'create_session_request.cc',
-        'create_session_request.h',
-        'issue.cc',
-        'issue.h',
-        'issue_manager.cc',
-        'issue_manager.h',
-        'issue_observer.h',
-        'media_route.cc',
-        'media_route.h',
-        'media_route_id.h',
-        'media_router.h',
-        'media_router_type_converters.cc',
-        'media_router_type_converters.h',
-        'media_routes_observer.cc',
-        'media_routes_observer.h',
-        'media_sink.cc',
-        'media_sink.h',
-        'media_sinks_observer.cc',
-        'media_sinks_observer.h',
-        'media_source.cc',
-        'media_source.h',
-        'media_source_helper.cc',
-        'media_source_helper.h',
-        'presentation_media_sinks_observer.cc',
-        'presentation_media_sinks_observer.h',
-        'route_id_manager.cc',
-        'route_id_manager.h',
+        '<@(media_router_sources)',
       ],
     },
     {
-      # Mojo bindings for the Media Router internal API.
+      # Mojo compiler for the Media Router internal API.
       'target_name': 'media_router_mojo_gen',
       'type': 'none',
       'sources': [
@@ -67,9 +48,6 @@
       ],
       'dependencies': [
         'media_router_mojo_gen',
-        '<(DEPTH)/mojo/mojo_base.gyp:mojo_common_lib',
-        '<(DEPTH)/mojo/mojo_base.gyp:mojo_environment_chromium',
-        '<(DEPTH)/third_party/mojo/mojo_public.gyp:mojo_cpp_bindings',
       ],
       'sources': [
         '<(SHARED_INTERMEDIATE_DIR)/chrome/browser/media/router/media_router.mojom.cc',
@@ -77,23 +55,21 @@
       ],
     },
     {
+      # GN version: //chrome/browser/media/router:test_support
       'target_name': 'media_router_test_support',
       'type': 'static_library',
       'include_dirs': [
         '<(DEPTH)',
       ],
       'dependencies': [
-        ':media_router',
+        'media_router',
+        'media_router_mojo',
         '<(DEPTH)/base/base.gyp:base',
         '<(DEPTH)/testing/gmock.gyp:gmock',
       ],
       'sources': [
-        'mock_media_router.cc',
-        'mock_media_router.h',
-        'mock_screen_availability_listener.cc',
-        'mock_screen_availability_listener.h',
+        '<@(media_router_test_support_sources)',
       ],
     },
-
   ],
 }
diff --git a/chrome/browser/media/router/media_router.gypi b/chrome/browser/media/router/media_router.gypi
new file mode 100644
index 0000000..702b04a
--- /dev/null
+++ b/chrome/browser/media/router/media_router.gypi
@@ -0,0 +1,42 @@
+# Copyright (c) 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.
+
+{
+  'variables': {
+    # File lists shared with GN build.
+    'media_router_sources': [
+      'create_session_request.cc',
+      'create_session_request.h',
+      'issue.cc',
+      'issue.h',
+      'issue_manager.cc',
+      'issue_manager.h',
+      'issues_observer.h',
+      'media_route.cc',
+      'media_route.h',
+      'media_route_id.h',
+      'media_router.h',
+      'media_router_type_converters.cc',
+      'media_router_type_converters.h',
+      'media_routes_observer.cc',
+      'media_routes_observer.h',
+      'media_sink.cc',
+      'media_sink.h',
+      'media_sinks_observer.cc',
+      'media_sinks_observer.h',
+      'media_source.cc',
+      'media_source.h',
+      'media_source_helper.cc',
+      'media_source_helper.h',
+      'presentation_media_sinks_observer.cc',
+      'presentation_media_sinks_observer.h',
+    ],
+    'media_router_test_support_sources': [
+      'mock_media_router.cc',
+      'mock_media_router.h',
+      'mock_screen_availability_listener.cc',
+      'mock_screen_availability_listener.h',
+    ],
+  },
+}
diff --git a/chrome/browser/media/router/media_router_tests.gypi b/chrome/browser/media/router/media_router_tests.gypi
deleted file mode 100644
index 3ef86c75..0000000
--- a/chrome/browser/media/router/media_router_tests.gypi
+++ /dev/null
@@ -1,24 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-{
-  'sources': [
-    '../../ui/webui/media_router/media_cast_mode_unittest.cc',
-    '../../ui/webui/media_router/media_router_test.cc',
-    '../../ui/webui/media_router/media_router_test.h',
-    '../../ui/webui/media_router/media_router_dialog_controller_unittest.cc',
-    'issue_manager_unittest.cc',
-    'issue_unittest.cc',
-    'media_route_unittest.cc',
-    'media_router_type_converters_unittest.cc',
-    'media_sink_unittest.cc',
-    'media_source_helper_unittest.cc',
-    'media_source_unittest.cc',
-    "presentation_media_sinks_observer_unittest.cc",
-    'route_id_manager_unittest.cc',
-  ],
-  'dependencies': [
-    'browser/media/router/media_router.gyp:media_router_test_support',
-  ],
-}
diff --git a/chrome/browser/media/router/route_id_manager.cc b/chrome/browser/media/router/route_id_manager.cc
deleted file mode 100644
index 9735257..0000000
--- a/chrome/browser/media/router/route_id_manager.cc
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/media/router/route_id_manager.h"
-
-#include "base/memory/singleton.h"
-#include "base/strings/string_number_conversions.h"
-#include "chrome/browser/media/router/media_route.h"
-
-namespace media_router {
-
-const char kLocalRoutePrefix[] = "route-local-";
-
-RouteIDManager::RouteIDManager() : next_local_id_(0) {}
-
-std::string RouteIDManager::ForLocalRoute() {
-  DCHECK(CalledOnValidThread());
-  return kLocalRoutePrefix + base::Uint64ToString(next_local_id_++);
-}
-
-// static
-RouteIDManager* RouteIDManager::GetInstance() {
-  return Singleton<RouteIDManager>::get();
-}
-
-}  // namespace media_router
diff --git a/chrome/browser/media/router/route_id_manager.h b/chrome/browser/media/router/route_id_manager.h
deleted file mode 100644
index 8497bd1..0000000
--- a/chrome/browser/media/router/route_id_manager.h
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_MEDIA_ROUTER_ROUTE_ID_MANAGER_H_
-#define CHROME_BROWSER_MEDIA_ROUTER_ROUTE_ID_MANAGER_H_
-
-#include <string>
-
-#include "base/basictypes.h"
-#include "base/gtest_prod_util.h"
-#include "base/memory/singleton.h"
-#include "base/threading/non_thread_safe.h"
-
-namespace media_router {
-
-class MediaRoute;
-
-// Shared singleton which coordinates the assignment of unique IDs to
-// MediaRoute objects.
-// Class is not threadsafe; IDs should be created on the same thread.
-class RouteIDManager : public base::NonThreadSafe {
- public:
-  static RouteIDManager* GetInstance();
-
-  std::string ForLocalRoute();
-
- private:
-  FRIEND_TEST_ALL_PREFIXES(RouteIDManagerTest, ForLocalRoute);
-  friend struct DefaultSingletonTraits<RouteIDManager>;
-
-  RouteIDManager();
-
-  // Monotonically increasing ID number.
-  uint64 next_local_id_;
-
-  DISALLOW_COPY_AND_ASSIGN(RouteIDManager);
-};
-
-}  // namespace media_router
-
-#endif  // CHROME_BROWSER_MEDIA_ROUTER_ROUTE_ID_MANAGER_H_
diff --git a/chrome/browser/media/router/route_id_manager_unittest.cc b/chrome/browser/media/router/route_id_manager_unittest.cc
deleted file mode 100644
index 46da03e..0000000
--- a/chrome/browser/media/router/route_id_manager_unittest.cc
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/media/router/route_id_manager.h"
-#include "testing/gmock/include/gmock/gmock.h"
-
-namespace media_router {
-
-TEST(RouteIDManagerTest, ForLocalRoute) {
-  // Singleton instance is left unused for better test isolation.
-  RouteIDManager manager1;
-  EXPECT_EQ("route-local-0", manager1.ForLocalRoute());
-  EXPECT_EQ("route-local-1", manager1.ForLocalRoute());
-
-  RouteIDManager manager2;
-  EXPECT_EQ("route-local-0", manager2.ForLocalRoute());
-}
-
-}  // namespace media_router
diff --git a/chrome/browser/net/pref_proxy_config_tracker_impl.cc b/chrome/browser/net/pref_proxy_config_tracker_impl.cc
index 49161ba..f839949 100644
--- a/chrome/browser/net/pref_proxy_config_tracker_impl.cc
+++ b/chrome/browser/net/pref_proxy_config_tracker_impl.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/net/pref_proxy_config_tracker_impl.h"
 
 #include "base/bind.h"
+#include "base/metrics/histogram_macros.h"
 #include "base/prefs/pref_registry_simple.h"
 #include "base/prefs/pref_service.h"
 #include "base/strings/string_util.h"
@@ -30,10 +31,8 @@
 }
 
 // Removes any Data Reduction Proxies like *.googlezip.net from |proxy_list|.
-void RemoveGooglezipDataReductionProxiesFromList(net::ProxyList* proxy_list) {
-  if (proxy_list->IsEmpty())
-    return;
-
+// Returns the number of proxies that were removed from |proxy_list|.
+size_t RemoveGooglezipDataReductionProxiesFromList(net::ProxyList* proxy_list) {
   bool found_googlezip_proxy = false;
   for (const net::ProxyServer& proxy : proxy_list->GetAll()) {
     if (IsGooglezipDataReductionProxy(proxy)) {
@@ -42,17 +41,21 @@
     }
   }
   if (!found_googlezip_proxy)
-    return;
+    return 0;
 
+  size_t num_removed_proxies = 0;
   net::ProxyList replacement_list;
   for (const net::ProxyServer& proxy : proxy_list->GetAll()) {
     if (!IsGooglezipDataReductionProxy(proxy))
       replacement_list.AddProxyServer(proxy);
+    else
+      ++num_removed_proxies;
   }
 
   if (replacement_list.IsEmpty())
     replacement_list.AddProxyServer(net::ProxyServer::Direct());
   *proxy_list = replacement_list;
+  return num_removed_proxies;
 }
 
 // Remove any Data Reduction Proxies like *.googlezip.net from |proxy_rules|.
@@ -61,17 +64,23 @@
 // the Data Reduction Proxy without adding any of the necessary authentication
 // headers or applying the Data Reduction Proxy bypass logic. See
 // http://crbug.com/476610.
-// TODO(sclittle): Add UMA to record how often this method is called, and how
-// often it actually removes a *.googlezip.net proxy. This method should be
-// removed once it stops actually finding and removing *.googlezip.net proxies
-// from the proxy rules.
+// TODO(sclittle): This method should be removed once the UMA indicates that
+// *.googlezip.net proxies are no longer present in the |proxy_rules|.
 void RemoveGooglezipDataReductionProxies(
     net::ProxyConfig::ProxyRules* proxy_rules) {
-  RemoveGooglezipDataReductionProxiesFromList(&proxy_rules->fallback_proxies);
-  RemoveGooglezipDataReductionProxiesFromList(&proxy_rules->proxies_for_ftp);
-  RemoveGooglezipDataReductionProxiesFromList(&proxy_rules->proxies_for_http);
-  RemoveGooglezipDataReductionProxiesFromList(&proxy_rules->proxies_for_https);
-  RemoveGooglezipDataReductionProxiesFromList(&proxy_rules->single_proxies);
+  size_t num_removed_proxies =
+      RemoveGooglezipDataReductionProxiesFromList(
+          &proxy_rules->fallback_proxies) +
+      RemoveGooglezipDataReductionProxiesFromList(
+          &proxy_rules->proxies_for_ftp) +
+      RemoveGooglezipDataReductionProxiesFromList(
+          &proxy_rules->proxies_for_http) +
+      RemoveGooglezipDataReductionProxiesFromList(
+          &proxy_rules->proxies_for_https) +
+      RemoveGooglezipDataReductionProxiesFromList(&proxy_rules->single_proxies);
+
+  UMA_HISTOGRAM_COUNTS_100("Net.PrefProxyConfig.GooglezipProxyRemovalCount",
+                           num_removed_proxies);
 }
 
 }  // namespace
diff --git a/chrome/browser/net/pref_proxy_config_tracker_impl_unittest.cc b/chrome/browser/net/pref_proxy_config_tracker_impl_unittest.cc
index 44a3c005b..793e9e7c 100644
--- a/chrome/browser/net/pref_proxy_config_tracker_impl_unittest.cc
+++ b/chrome/browser/net/pref_proxy_config_tracker_impl_unittest.cc
@@ -11,6 +11,7 @@
 #include "base/message_loop/message_loop.h"
 #include "base/prefs/pref_registry_simple.h"
 #include "base/prefs/testing_pref_service.h"
+#include "base/test/histogram_tester.h"
 #include "chrome/browser/prefs/pref_service_mock_factory.h"
 #include "chrome/browser/prefs/proxy_config_dictionary.h"
 #include "chrome/common/chrome_switches.h"
@@ -310,39 +311,58 @@
       "https://proxy.googlezip.net:443,compress.googlezip.net,"
       "https://proxy-dev.googlezip.net:443,proxy-dev.googlezip.net,"
       "quic://proxy.googlezip.net";
+  const int kNumDataReductionProxies = 5;
 
   struct {
     std::string initial_proxy_rules;
     const char* http_proxy_info;
     const char* https_proxy_info;
     const char* ftp_proxy_info;
+    int expected_num_removed_proxies;
   } test_cases[] = {
       {"http=foopyhttp," + kDataReductionProxies +
            ",direct://;https=foopyhttps," + kDataReductionProxies +
            ",direct://;ftp=foopyftp," + kDataReductionProxies + ",direct://",
        "foopyhttp;direct://",
        "foopyhttps;direct://",
-       "foopyftp;direct://"},
+       "foopyftp;direct://",
+       kNumDataReductionProxies * 3},
 
       {"foopy," + kDataReductionProxies + ",direct://",
        "foopy;direct://",
        "foopy;direct://",
-       "foopy;direct://"},
+       "foopy;direct://",
+       kNumDataReductionProxies},
 
       {"http=" + kDataReductionProxies + ";https=" + kDataReductionProxies +
            ";ftp=" + kDataReductionProxies,
        "direct://",
        "direct://",
-       "direct://"},
+       "direct://",
+       kNumDataReductionProxies * 3},
 
       {"http=" + kDataReductionProxies + ",foopy,direct://",
        "foopy;direct://",
        "direct://",
-       "direct://"},
+       "direct://",
+       kNumDataReductionProxies},
+
+      {"foopy,direct://",
+       "foopy;direct://",
+       "foopy;direct://",
+       "foopy;direct://",
+       0},
+
+      {"direct://",
+       "direct://",
+       "direct://",
+       "direct://",
+       0},
   };
 
   // Test setting the proxy from a user pref.
   for (const auto& test : test_cases) {
+    base::HistogramTester histogram_tester;
     pref_service_->SetUserPref(prefs::kProxy,
                                ProxyConfigDictionary::CreateFixedServers(
                                    test.initial_proxy_rules, std::string()));
@@ -351,6 +371,9 @@
     net::ProxyConfig config;
     EXPECT_EQ(net::ProxyConfigService::CONFIG_VALID,
               proxy_config_service_->GetLatestProxyConfig(&config));
+    histogram_tester.ExpectUniqueSample(
+        "Net.PrefProxyConfig.GooglezipProxyRemovalCount",
+        test.expected_num_removed_proxies, 1);
 
     CheckResolvedProxyMatches(&config, GURL("http://google.com"),
                               test.http_proxy_info);
diff --git a/chrome/browser/net/proxy_service_factory.cc b/chrome/browser/net/proxy_service_factory.cc
index 96293f8a..7ec1ac3 100644
--- a/chrome/browser/net/proxy_service_factory.cc
+++ b/chrome/browser/net/proxy_service_factory.cc
@@ -7,6 +7,7 @@
 #include <string>
 
 #include "base/command_line.h"
+#include "base/metrics/field_trial.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/threading/thread.h"
 #include "chrome/browser/browser_process.h"
@@ -38,6 +39,23 @@
 
 using content::BrowserThread;
 
+namespace {
+
+#if !defined(OS_ANDROID)
+bool EnableOutOfProcessV8Pac(const base::CommandLine& command_line) {
+  const std::string group_name =
+      base::FieldTrialList::FindFullName("OutOfProcessPac");
+
+  if (command_line.HasSwitch(switches::kDisableOutOfProcessPac))
+    return false;
+  if (command_line.HasSwitch(switches::kV8PacMojoOutOfProcess))
+    return true;
+  return group_name == "Enabled";
+}
+#endif  // !defined(OS_ANDROID)
+
+}  // namespace
+
 // static
 net::ProxyConfigService* ProxyServiceFactory::CreateProxyConfigService(
     PrefProxyConfigTracker* tracker) {
@@ -144,14 +162,16 @@
 #endif
 
 #if !defined(OS_ANDROID)
-    if (command_line.HasSwitch(switches::kV8PacMojoOutOfProcess)) {
-      proxy_service = net::CreateProxyServiceUsingMojoFactory(
-          UtilityProcessMojoProxyResolverFactory::GetInstance(),
+    // In-process Mojo PAC can only be set on the command line, so its presence
+    // should override other options.
+    if (command_line.HasSwitch(switches::kV8PacMojoInProcess)) {
+      proxy_service = net::CreateProxyServiceUsingMojoInProcess(
           proxy_config_service, new net::ProxyScriptFetcherImpl(context),
           dhcp_proxy_script_fetcher, context->host_resolver(), net_log,
           network_delegate);
-    } else if (command_line.HasSwitch(switches::kV8PacMojoInProcess)) {
-      proxy_service = net::CreateProxyServiceUsingMojoInProcess(
+    } else if (EnableOutOfProcessV8Pac(command_line)) {
+      proxy_service = net::CreateProxyServiceUsingMojoFactory(
+          UtilityProcessMojoProxyResolverFactory::GetInstance(),
           proxy_config_service, new net::ProxyScriptFetcherImpl(context),
           dhcp_proxy_script_fetcher, context->host_resolver(), net_log,
           network_delegate);
diff --git a/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_io_data.cc b/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_io_data.cc
index c70e581..08a6344 100644
--- a/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_io_data.cc
+++ b/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_io_data.cc
@@ -7,6 +7,8 @@
 #include "base/prefs/pref_service.h"
 #include "chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings.h"
 #include "chrome/common/chrome_content_client.h"
+#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config_retrieval_params.h"
+#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_experiments_stats.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h"
@@ -61,6 +63,9 @@
               DataReductionProxyChromeSettings::GetClient(), flags, net_log,
               io_task_runner, ui_task_runner, enabled, enable_quic,
               GetUserAgent()));
+  data_reduction_proxy_io_data->experiments_stats()->InitializeOnUIThread(
+      data_reduction_proxy::DataReductionProxyConfigRetrievalParams::Create(
+          prefs));
 
 #if defined(ENABLE_DATA_REDUCTION_PROXY_DEBUGGING)
   scoped_ptr<data_reduction_proxy::ContentDataReductionProxyDebugUIService>
diff --git a/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings.cc b/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings.cc
index 43188184..db900de 100644
--- a/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings.cc
+++ b/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings.cc
@@ -138,7 +138,7 @@
               profile_prefs, ui_task_runner, commit_delay));
   scoped_ptr<data_reduction_proxy::DataReductionProxyService> service =
       make_scoped_ptr(new data_reduction_proxy::DataReductionProxyService(
-          compression_stats.Pass(), this, request_context_getter,
+          compression_stats.Pass(), this, profile_prefs, request_context_getter,
           io_data->io_task_runner()));
   data_reduction_proxy::DataReductionProxySettings::
       InitDataReductionProxySettings(profile_prefs, io_data, service.Pass());
diff --git a/chrome/browser/net/utility_process_mojo_proxy_resolver_factory.cc b/chrome/browser/net/utility_process_mojo_proxy_resolver_factory.cc
index 0be9eef..73ffff9 100644
--- a/chrome/browser/net/utility_process_mojo_proxy_resolver_factory.cc
+++ b/chrome/browser/net/utility_process_mojo_proxy_resolver_factory.cc
@@ -64,6 +64,7 @@
     const mojo::String& pac_script,
     mojo::InterfaceRequest<net::interfaces::ProxyResolver> req,
     net::interfaces::HostResolverPtr host_resolver,
+    net::interfaces::ProxyResolverErrorObserverPtr error_observer,
     net::interfaces::ProxyResolverFactoryRequestClientPtr client) {
   DCHECK(thread_checker_.CalledOnValidThread());
   if (!resolver_factory_)
@@ -78,7 +79,8 @@
   idle_timer_.Stop();
   num_proxy_resolvers_++;
   resolver_factory_->CreateResolver(pac_script, req.Pass(),
-                                    host_resolver.Pass(), client.Pass());
+                                    host_resolver.Pass(), error_observer.Pass(),
+                                    client.Pass());
   return make_scoped_ptr(new base::ScopedClosureRunner(
       base::Bind(&UtilityProcessMojoProxyResolverFactory::OnResolverDestroyed,
                  base::Unretained(this))));
diff --git a/chrome/browser/net/utility_process_mojo_proxy_resolver_factory.h b/chrome/browser/net/utility_process_mojo_proxy_resolver_factory.h
index 2b796a2c..f6e9e21 100644
--- a/chrome/browser/net/utility_process_mojo_proxy_resolver_factory.h
+++ b/chrome/browser/net/utility_process_mojo_proxy_resolver_factory.h
@@ -33,6 +33,7 @@
       const mojo::String& pac_script,
       mojo::InterfaceRequest<net::interfaces::ProxyResolver> req,
       net::interfaces::HostResolverPtr host_resolver,
+      net::interfaces::ProxyResolverErrorObserverPtr error_observer,
       net::interfaces::ProxyResolverFactoryRequestClientPtr client) override;
 
  private:
diff --git a/chrome/browser/password_manager/generated_password_saved_infobar_delegate_android.cc b/chrome/browser/password_manager/generated_password_saved_infobar_delegate_android.cc
index f6dd43c..59df849 100644
--- a/chrome/browser/password_manager/generated_password_saved_infobar_delegate_android.cc
+++ b/chrome/browser/password_manager/generated_password_saved_infobar_delegate_android.cc
@@ -22,7 +22,7 @@
     GeneratedPasswordSavedInfoBarDelegateAndroid()
     : button_label_(l10n_util::GetStringUTF16(IDS_OK)) {
   base::string16 link = l10n_util::GetStringUTF16(
-      IDS_MANAGE_PASSWORDS_CONFIRM_GENERATED_LINK);
+      IDS_MANAGE_PASSWORDS_LINK);
   size_t offset;
   message_text_ = l10n_util::GetStringFUTF16(
       IDS_MANAGE_PASSWORDS_CONFIRM_GENERATED_TEXT_INFOBAR, link, &offset);
diff --git a/chrome/browser/password_manager/password_store_factory.cc b/chrome/browser/password_manager/password_store_factory.cc
index 8e640816..13d0e74d 100644
--- a/chrome/browser/password_manager/password_store_factory.cc
+++ b/chrome/browser/password_manager/password_store_factory.cc
@@ -193,6 +193,21 @@
   }
 }
 
+// static
+void PasswordStoreFactory::TrimOrDeleteAffiliationCache(Profile* profile) {
+  scoped_refptr<PasswordStore> password_store =
+      GetForProfile(profile, ServiceAccessType::EXPLICIT_ACCESS);
+  if (password_store && password_store->HasAffiliatedMatchHelper()) {
+    password_store->TrimAffiliationCache();
+  } else {
+    scoped_refptr<base::SingleThreadTaskRunner> db_thread_runner(
+        content::BrowserThread::GetMessageLoopProxyForThread(
+            content::BrowserThread::DB));
+    password_manager::AffiliationService::DeleteCache(
+        GetAffiliationDatabasePath(profile), db_thread_runner.get());
+  }
+}
+
 PasswordStoreFactory::PasswordStoreFactory()
     : BrowserContextKeyedServiceFactory(
         "PasswordStore",
diff --git a/chrome/browser/password_manager/password_store_factory.h b/chrome/browser/password_manager/password_store_factory.h
index 25bd747..5fab46e 100644
--- a/chrome/browser/password_manager/password_store_factory.h
+++ b/chrome/browser/password_manager/password_store_factory.h
@@ -62,6 +62,10 @@
   // that syncing passwords has just started or ended for |profile|.
   static void OnPasswordsSyncedStatePotentiallyChanged(Profile* profile);
 
+  // Trims the affiliation cache for |profile| if affiliation-based matching is
+  // enabled, and completely deletes it otherwise.
+  static void TrimOrDeleteAffiliationCache(Profile* profile);
+
  private:
   friend struct DefaultSingletonTraits<PasswordStoreFactory>;
 
diff --git a/chrome/browser/password_manager/save_password_infobar_delegate.cc b/chrome/browser/password_manager/save_password_infobar_delegate.cc
index 7e2f2d8..299b246 100644
--- a/chrome/browser/password_manager/save_password_infobar_delegate.cc
+++ b/chrome/browser/password_manager/save_password_infobar_delegate.cc
@@ -44,7 +44,7 @@
   SavePasswordInfoBarDelegate* infobar_delegate =
       new SavePasswordInfoBarDelegate(
           form_to_save.Pass(), uma_histogram_suffix, source_type,
-          password_bubble_experiment::IsEnabledSmartLockBranding(profile));
+          password_bubble_experiment::IsSmartLockBrandingEnabled(profile));
 #if defined(OS_ANDROID)
   // For Android in case of smart lock we need different appearance of infobar.
   scoped_ptr<infobars::InfoBar> infobar =
diff --git a/chrome/browser/policy/cloud/DEPS b/chrome/browser/policy/cloud/DEPS
index 422fa2a..07ecd7c9 100644
--- a/chrome/browser/policy/cloud/DEPS
+++ b/chrome/browser/policy/cloud/DEPS
@@ -38,7 +38,9 @@
     "+content/public/test",
   ],
 
-  r"cloud_policy_invalidator_unittest\.cc": [
+  r"(cloud_policy_invalidator_unittest|"
+  r"remote_commands_invalidator_unittest)"
+  r"\.cc": [
     "+chrome/browser/invalidation/fake_invalidation_service.h",
   ],
 }
diff --git a/chrome/browser/policy/cloud/remote_commands_invalidator.cc b/chrome/browser/policy/cloud/remote_commands_invalidator.cc
new file mode 100644
index 0000000..f0af3cc
--- /dev/null
+++ b/chrome/browser/policy/cloud/remote_commands_invalidator.cc
@@ -0,0 +1,158 @@
+// 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/policy/cloud/remote_commands_invalidator.h"
+
+#include <string>
+
+#include "base/logging.h"
+#include "components/invalidation/invalidation.h"
+#include "components/invalidation/invalidation_service.h"
+#include "components/invalidation/invalidation_util.h"
+#include "components/invalidation/invalidator_state.h"
+#include "components/invalidation/object_id_invalidation_map.h"
+#include "components/invalidation/single_object_invalidation_set.h"
+
+namespace policy {
+
+RemoteCommandsInvalidator::RemoteCommandsInvalidator() {
+}
+
+RemoteCommandsInvalidator::~RemoteCommandsInvalidator() {
+  DCHECK_EQ(SHUT_DOWN, state_);
+}
+
+void RemoteCommandsInvalidator::Initialize(
+    invalidation::InvalidationService* invalidation_service) {
+  DCHECK_EQ(SHUT_DOWN, state_);
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  DCHECK(invalidation_service);
+  invalidation_service_ = invalidation_service;
+
+  state_ = STOPPED;
+  OnInitialize();
+}
+
+void RemoteCommandsInvalidator::Shutdown() {
+  DCHECK_NE(SHUT_DOWN, state_);
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  Stop();
+
+  state_ = SHUT_DOWN;
+  OnShutdown();
+}
+
+void RemoteCommandsInvalidator::Start() {
+  DCHECK_EQ(STOPPED, state_);
+  DCHECK(thread_checker_.CalledOnValidThread());
+  state_ = STARTED;
+
+  OnStart();
+}
+
+void RemoteCommandsInvalidator::Stop() {
+  DCHECK_NE(SHUT_DOWN, state_);
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  if (state_ == STARTED) {
+    Unregister();
+    state_ = STOPPED;
+
+    OnStop();
+  }
+}
+
+void RemoteCommandsInvalidator::OnInvalidatorStateChange(
+    syncer::InvalidatorState state) {
+  DCHECK_EQ(STARTED, state_);
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  invalidation_service_enabled_ = state == syncer::INVALIDATIONS_ENABLED;
+  UpdateInvalidationsEnabled();
+}
+
+void RemoteCommandsInvalidator::OnIncomingInvalidation(
+    const syncer::ObjectIdInvalidationMap& invalidation_map) {
+  DCHECK_EQ(STARTED, state_);
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  if (!invalidation_service_enabled_)
+    LOG(WARNING) << "Unexpected invalidation received.";
+
+  const syncer::SingleObjectInvalidationSet& list =
+      invalidation_map.ForObject(object_id_);
+  if (list.IsEmpty()) {
+    NOTREACHED();
+    return;
+  }
+
+  // Acknowledge all invalidations.
+  for (const auto& it : list)
+    it.Acknowledge();
+
+  DoRemoteCommandsFetch();
+}
+
+std::string RemoteCommandsInvalidator::GetOwnerName() const {
+  return "RemoteCommands";
+}
+
+void RemoteCommandsInvalidator::ReloadPolicyData(
+    const enterprise_management::PolicyData* policy) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  if (state_ != STARTED)
+    return;
+
+  // Create the ObjectId based on the policy data.
+  // If the policy does not specify an the ObjectId, then unregister.
+  if (!policy || !policy->has_command_invalidation_source() ||
+      !policy->has_command_invalidation_name()) {
+    Unregister();
+    return;
+  }
+  const invalidation::ObjectId object_id(policy->command_invalidation_source(),
+                                         policy->command_invalidation_name());
+
+  // If the policy object id in the policy data is different from the currently
+  // registered object id, update the object registration.
+  if (!is_registered_ || !(object_id == object_id_))
+    Register(object_id);
+}
+
+void RemoteCommandsInvalidator::Register(
+    const invalidation::ObjectId& object_id) {
+  // Register this handler with the invalidation service if needed.
+  if (!is_registered_) {
+    OnInvalidatorStateChange(invalidation_service_->GetInvalidatorState());
+    invalidation_service_->RegisterInvalidationHandler(this);
+    is_registered_ = true;
+  }
+
+  object_id_ = object_id;
+  UpdateInvalidationsEnabled();
+
+  // Update registration with the invalidation service.
+  syncer::ObjectIdSet ids;
+  ids.insert(object_id);
+  invalidation_service_->UpdateRegisteredInvalidationIds(this, ids);
+}
+
+void RemoteCommandsInvalidator::Unregister() {
+  if (is_registered_) {
+    invalidation_service_->UpdateRegisteredInvalidationIds(
+        this, syncer::ObjectIdSet());
+    invalidation_service_->UnregisterInvalidationHandler(this);
+    is_registered_ = false;
+    UpdateInvalidationsEnabled();
+  }
+}
+
+void RemoteCommandsInvalidator::UpdateInvalidationsEnabled() {
+  invalidations_enabled_ = invalidation_service_enabled_ && is_registered_;
+}
+
+}  // namespace policy
diff --git a/chrome/browser/policy/cloud/remote_commands_invalidator.h b/chrome/browser/policy/cloud/remote_commands_invalidator.h
new file mode 100644
index 0000000..07d0194a
--- /dev/null
+++ b/chrome/browser/policy/cloud/remote_commands_invalidator.h
@@ -0,0 +1,115 @@
+// 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_POLICY_CLOUD_REMOTE_COMMANDS_INVALIDATOR_H_
+#define CHROME_BROWSER_POLICY_CLOUD_REMOTE_COMMANDS_INVALIDATOR_H_
+
+#include "base/macros.h"
+#include "base/threading/thread_checker.h"
+#include "components/invalidation/invalidation_handler.h"
+#include "google/cacheinvalidation/include/types.h"
+#include "policy/proto/device_management_backend.pb.h"
+
+namespace invalidation {
+class InvalidationService;
+}  // namespace invalidation
+
+namespace policy {
+
+// This class provides basic intefaces for an invalidator for remote commands
+// services. It's not interacting with CloudPolicyClient/CloudPolicyCore
+// directly, instead, it handles the interacting with invalidation service
+// only and leaves interfaces to integrate with subclasses.
+class RemoteCommandsInvalidator : public syncer::InvalidationHandler {
+ public:
+  RemoteCommandsInvalidator();
+  ~RemoteCommandsInvalidator() override;
+
+  // Initialize this invalidator to pair with |invalidation_service|. Must be
+  // called before Start().
+  void Initialize(invalidation::InvalidationService* invalidation_service);
+
+  // Shutdown this invalidator. Will stop the invalidator first, and after
+  // shutting down, the invalidator can't be started anymore unless it's
+  // initialized again.
+  void Shutdown();
+
+  // Starts to process invalidations.
+  void Start();
+
+  // Stops to process invalidation. May only be called after Start() has been
+  // called.
+  void Stop();
+
+  // Helpful accessors.
+  invalidation::InvalidationService* invalidation_service() {
+    return invalidation_service_;
+  }
+  bool invalidations_enabled() { return invalidations_enabled_; }
+
+  // syncer::InvalidationHandler:
+  void OnInvalidatorStateChange(syncer::InvalidatorState state) override;
+  void OnIncomingInvalidation(
+      const syncer::ObjectIdInvalidationMap& invalidation_map) override;
+  std::string GetOwnerName() const override;
+
+ protected:
+  virtual void OnInitialize() = 0;
+  virtual void OnShutdown() = 0;
+  virtual void OnStart() = 0;
+  virtual void OnStop() = 0;
+
+  // Subclasses must override this method to implement the actual remote
+  // commands fetch.
+  virtual void DoRemoteCommandsFetch() = 0;
+
+  // Subclasses must call this function to set the object id for remote command
+  // invalidations.
+  void ReloadPolicyData(const enterprise_management::PolicyData* policy);
+
+ private:
+  // Registers the given object with the invalidation service.
+  void Register(const invalidation::ObjectId& object_id);
+
+  // Unregisters the current object with the invalidation service.
+  void Unregister();
+
+  // Updates invalidations_enabled_.
+  void UpdateInvalidationsEnabled();
+
+  // The state of the object.
+  enum State {
+    SHUT_DOWN,
+    STOPPED,
+    STARTED,
+  };
+  State state_ = SHUT_DOWN;
+
+  // The invalidation service.
+  invalidation::InvalidationService* invalidation_service_ = nullptr;
+
+  // Whether the invalidator currently has the ability to receive invalidations.
+  // This is true if the invalidation service is enabled and the invalidator
+  // has registered for a remote commands object.
+  bool invalidations_enabled_ = false;
+
+  // Whether the invalidation service is currently enabled.
+  bool invalidation_service_enabled_ = false;
+
+  // Whether this object has registered for remote commands invalidations.
+  bool is_registered_ = false;
+
+  // The object id representing the remote commands in the invalidation service.
+  invalidation::ObjectId object_id_;
+
+  // A thread checker to make sure that callbacks are invoked on the correct
+  // thread.
+  base::ThreadChecker thread_checker_;
+
+  DISALLOW_COPY_AND_ASSIGN(RemoteCommandsInvalidator);
+};
+
+}  // namespace policy
+
+#endif  // CHROME_BROWSER_POLICY_CLOUD_REMOTE_COMMANDS_INVALIDATOR_H_
diff --git a/chrome/browser/policy/cloud/remote_commands_invalidator_impl.cc b/chrome/browser/policy/cloud/remote_commands_invalidator_impl.cc
new file mode 100644
index 0000000..51fbc5c
--- /dev/null
+++ b/chrome/browser/policy/cloud/remote_commands_invalidator_impl.cc
@@ -0,0 +1,65 @@
+// 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/policy/cloud/remote_commands_invalidator_impl.h"
+
+#include "base/logging.h"
+#include "components/policy/core/common/remote_commands/remote_commands_service.h"
+
+namespace policy {
+
+RemoteCommandsInvalidatorImpl::RemoteCommandsInvalidatorImpl(
+    CloudPolicyCore* core)
+    : core_(core) {
+  DCHECK(core_);
+}
+
+void RemoteCommandsInvalidatorImpl::OnInitialize() {
+  core_->AddObserver(this);
+  if (core_->remote_commands_service())
+    OnRemoteCommandsServiceStarted(core_);
+}
+
+void RemoteCommandsInvalidatorImpl::OnShutdown() {
+  core_->RemoveObserver(this);
+}
+
+void RemoteCommandsInvalidatorImpl::OnStart() {
+  core_->store()->AddObserver(this);
+  OnStoreLoaded(core_->store());
+}
+
+void RemoteCommandsInvalidatorImpl::OnStop() {
+  core_->store()->RemoveObserver(this);
+}
+
+void RemoteCommandsInvalidatorImpl::DoRemoteCommandsFetch() {
+  DCHECK(core_->remote_commands_service());
+  core_->remote_commands_service()->FetchRemoteCommands();
+}
+
+void RemoteCommandsInvalidatorImpl::OnCoreConnected(CloudPolicyCore* core) {
+}
+
+void RemoteCommandsInvalidatorImpl::OnRefreshSchedulerStarted(
+    CloudPolicyCore* core) {
+}
+
+void RemoteCommandsInvalidatorImpl::OnCoreDisconnecting(CloudPolicyCore* core) {
+  Stop();
+}
+
+void RemoteCommandsInvalidatorImpl::OnRemoteCommandsServiceStarted(
+    CloudPolicyCore* core) {
+  Start();
+}
+
+void RemoteCommandsInvalidatorImpl::OnStoreLoaded(CloudPolicyStore* core) {
+  ReloadPolicyData(core_->store()->policy());
+}
+
+void RemoteCommandsInvalidatorImpl::OnStoreError(CloudPolicyStore* core) {
+}
+
+}  // namespace policy
diff --git a/chrome/browser/policy/cloud/remote_commands_invalidator_impl.h b/chrome/browser/policy/cloud/remote_commands_invalidator_impl.h
new file mode 100644
index 0000000..aca0aef
--- /dev/null
+++ b/chrome/browser/policy/cloud/remote_commands_invalidator_impl.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_POLICY_CLOUD_REMOTE_COMMANDS_INVALIDATOR_IMPL_H_
+#define CHROME_BROWSER_POLICY_CLOUD_REMOTE_COMMANDS_INVALIDATOR_IMPL_H_
+
+#include "base/macros.h"
+#include "chrome/browser/policy/cloud/remote_commands_invalidator.h"
+#include "components/policy/core/common/cloud/cloud_policy_core.h"
+#include "components/policy/core/common/cloud/cloud_policy_store.h"
+
+namespace policy {
+
+// Implementation of invalidator for remote commands services. This class
+// listens to events from CloudPolicyCore and CloudPolicyStore and builds
+// with RemoteCommandsInvalidator to complete the tasks.
+class RemoteCommandsInvalidatorImpl : public RemoteCommandsInvalidator,
+                                      public CloudPolicyCore::Observer,
+                                      public CloudPolicyStore::Observer {
+ public:
+  explicit RemoteCommandsInvalidatorImpl(CloudPolicyCore* core);
+
+  // RemoteCommandsInvalidator:
+  void OnInitialize() override;
+  void OnShutdown() override;
+  void OnStart() override;
+  void OnStop() override;
+  void DoRemoteCommandsFetch() override;
+
+  // CloudPolicyCore::Observer:
+  void OnCoreConnected(CloudPolicyCore* core) override;
+  void OnRefreshSchedulerStarted(CloudPolicyCore* core) override;
+  void OnCoreDisconnecting(CloudPolicyCore* core) override;
+  void OnRemoteCommandsServiceStarted(CloudPolicyCore* core) override;
+
+  // CloudPolicyStore::Observer:
+  void OnStoreLoaded(CloudPolicyStore* store) override;
+  void OnStoreError(CloudPolicyStore* store) override;
+
+ private:
+  CloudPolicyCore* const core_;
+
+  DISALLOW_COPY_AND_ASSIGN(RemoteCommandsInvalidatorImpl);
+};
+
+}  // namespace policy
+
+#endif  // CHROME_BROWSER_POLICY_CLOUD_REMOTE_COMMANDS_INVALIDATOR_IMPL_H_
diff --git a/chrome/browser/policy/cloud/remote_commands_invalidator_unittest.cc b/chrome/browser/policy/cloud/remote_commands_invalidator_unittest.cc
new file mode 100644
index 0000000..d33a919c
--- /dev/null
+++ b/chrome/browser/policy/cloud/remote_commands_invalidator_unittest.cc
@@ -0,0 +1,293 @@
+// 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/policy/cloud/remote_commands_invalidator.h"
+
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "chrome/browser/invalidation/fake_invalidation_service.h"
+#include "components/invalidation/invalidation.h"
+#include "components/invalidation/invalidation_util.h"
+#include "components/invalidation/invalidator_registrar.h"
+#include "components/invalidation/invalidator_state.h"
+#include "components/invalidation/mock_ack_handler.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace em = enterprise_management;
+
+using ::testing::Mock;
+using ::testing::StrictMock;
+
+namespace policy {
+
+class MockRemoteCommandInvalidator : public RemoteCommandsInvalidator {
+ public:
+  MockRemoteCommandInvalidator() {}
+
+  MOCK_METHOD0(OnInitialize, void());
+  MOCK_METHOD0(OnShutdown, void());
+  MOCK_METHOD0(OnStart, void());
+  MOCK_METHOD0(OnStop, void());
+  MOCK_METHOD0(DoRemoteCommandsFetch, void());
+
+  void SetInvalidationObjectID(const invalidation::ObjectId& object_id) {
+    em::PolicyData policy_data;
+    policy_data.set_command_invalidation_source(object_id.source());
+    policy_data.set_command_invalidation_name(object_id.name());
+    ReloadPolicyData(&policy_data);
+  }
+
+  void ClearInvalidationObjectID() {
+    const em::PolicyData policy_data;
+    ReloadPolicyData(&policy_data);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MockRemoteCommandInvalidator);
+};
+
+class RemoteCommandsInvalidatorTest : public testing::Test {
+ public:
+  RemoteCommandsInvalidatorTest()
+      : kTestingObjectId1(123456, "abcdef"),
+        kTestingObjectId2(654321, "defabc") {
+  }
+
+  void EnableInvalidationService() {
+    invalidation_service_.SetInvalidatorState(syncer::INVALIDATIONS_ENABLED);
+  }
+
+  void DisableInvalidationService() {
+    invalidation_service_.SetInvalidatorState(
+        syncer::TRANSIENT_INVALIDATION_ERROR);
+  }
+
+  syncer::Invalidation FireInvalidation(
+      const invalidation::ObjectId& object_id) {
+    const syncer::Invalidation invalidation =
+        syncer::Invalidation::InitUnknownVersion(object_id);
+    invalidation_service_.EmitInvalidationForTest(invalidation);
+    return invalidation;
+  }
+
+  bool IsInvalidationSent(const syncer::Invalidation& invalidation) {
+    return !invalidation_service_.GetMockAckHandler()->IsUnsent(invalidation);
+  }
+
+  bool IsInvalidationAcknowledged(const syncer::Invalidation& invalidation) {
+    return invalidation_service_.GetMockAckHandler()->IsAcknowledged(
+        invalidation);
+  }
+
+  bool IsInvalidatorRegistered() {
+    return !invalidation_service_.invalidator_registrar()
+                .GetRegisteredIds(&invalidator_)
+                .empty();
+  }
+
+  void VerifyExpectations() {
+    Mock::VerifyAndClearExpectations(&invalidator_);
+  }
+
+ protected:
+  // Initialize and start the invalidator.
+  void InitializeAndStart() {
+    EXPECT_CALL(invalidator_, OnInitialize()).Times(1);
+    invalidator_.Initialize(&invalidation_service_);
+    VerifyExpectations();
+
+    EXPECT_CALL(invalidator_, OnStart()).Times(1);
+    invalidator_.Start();
+
+    VerifyExpectations();
+  }
+
+  // Stop and shutdown the invalidator.
+  void StopAndShutdown() {
+    EXPECT_CALL(invalidator_, OnStop()).Times(1);
+    EXPECT_CALL(invalidator_, OnShutdown()).Times(1);
+    invalidator_.Shutdown();
+
+    VerifyExpectations();
+  }
+
+  // Fire an invalidation to verify that invalidation is not working.
+  void VerifyInvalidationDisabled(const invalidation::ObjectId& object_id) {
+    const syncer::Invalidation invalidation = FireInvalidation(object_id);
+
+    base::RunLoop().RunUntilIdle();
+    EXPECT_FALSE(IsInvalidationSent(invalidation));
+  }
+
+  // Fire an invalidation to verify that invalidation works.
+  void VerifyInvalidationEnabled(const invalidation::ObjectId& object_id) {
+    EXPECT_TRUE(invalidator_.invalidations_enabled());
+
+    EXPECT_CALL(invalidator_, DoRemoteCommandsFetch()).Times(1);
+    const syncer::Invalidation invalidation = FireInvalidation(object_id);
+
+    base::RunLoop().RunUntilIdle();
+    EXPECT_TRUE(IsInvalidationSent(invalidation));
+    EXPECT_TRUE(IsInvalidationAcknowledged(invalidation));
+    VerifyExpectations();
+  }
+
+  const invalidation::ObjectId kTestingObjectId1;
+  const invalidation::ObjectId kTestingObjectId2;
+
+  base::MessageLoop loop_;
+
+  invalidation::FakeInvalidationService invalidation_service_;
+  StrictMock<MockRemoteCommandInvalidator> invalidator_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(RemoteCommandsInvalidatorTest);
+};
+
+// Verifies that only the fired invalidations will be received.
+TEST_F(RemoteCommandsInvalidatorTest, FiredInvalidation) {
+  InitializeAndStart();
+
+  // Invalidator won't work at this point.
+  EXPECT_FALSE(invalidator_.invalidations_enabled());
+
+  // Load the policy data, it should work now.
+  invalidator_.SetInvalidationObjectID(kTestingObjectId1);
+  EXPECT_TRUE(invalidator_.invalidations_enabled());
+
+  base::RunLoop().RunUntilIdle();
+  // No invalidation will be received if no invalidation is fired.
+  VerifyExpectations();
+
+  // Fire an invalidation with different object id, no invalidation will be
+  // received.
+  const syncer::Invalidation invalidation1 =
+      FireInvalidation(kTestingObjectId2);
+
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(IsInvalidationSent(invalidation1));
+  VerifyExpectations();
+
+  // Fire the invalidation, it should be acknowledged and trigger a remote
+  // commands fetch.
+  EXPECT_CALL(invalidator_, DoRemoteCommandsFetch()).Times(1);
+  const syncer::Invalidation invalidation2 =
+      FireInvalidation(kTestingObjectId1);
+
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(IsInvalidationSent(invalidation2));
+  EXPECT_TRUE(IsInvalidationAcknowledged(invalidation2));
+  VerifyExpectations();
+
+  StopAndShutdown();
+}
+
+// Verifies that no invalidation will be received when invalidator is shutdown.
+TEST_F(RemoteCommandsInvalidatorTest, ShutDown) {
+  EXPECT_FALSE(invalidator_.invalidations_enabled());
+  FireInvalidation(kTestingObjectId1);
+
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(invalidator_.invalidations_enabled());
+}
+
+// Verifies that no invalidation will be received when invalidator is stopped.
+TEST_F(RemoteCommandsInvalidatorTest, Stopped) {
+  EXPECT_CALL(invalidator_, OnInitialize()).Times(1);
+  invalidator_.Initialize(&invalidation_service_);
+  VerifyExpectations();
+
+  EXPECT_FALSE(invalidator_.invalidations_enabled());
+  FireInvalidation(kTestingObjectId2);
+
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(invalidator_.invalidations_enabled());
+
+  EXPECT_CALL(invalidator_, OnShutdown()).Times(1);
+  invalidator_.Shutdown();
+}
+
+// Verifies that stated/stopped state changes work as expected.
+TEST_F(RemoteCommandsInvalidatorTest, StartedStateChange) {
+  InitializeAndStart();
+
+  // Invalidator requires object id to work.
+  VerifyInvalidationDisabled(kTestingObjectId1);
+  EXPECT_FALSE(invalidator_.invalidations_enabled());
+  invalidator_.SetInvalidationObjectID(kTestingObjectId1);
+  VerifyInvalidationEnabled(kTestingObjectId1);
+
+  // Stop and restart invalidator.
+  EXPECT_CALL(invalidator_, OnStop()).Times(1);
+  invalidator_.Stop();
+  VerifyExpectations();
+
+  VerifyInvalidationDisabled(kTestingObjectId1);
+  EXPECT_FALSE(invalidator_.invalidations_enabled());
+
+  EXPECT_CALL(invalidator_, OnStart()).Times(1);
+  invalidator_.Start();
+  VerifyExpectations();
+
+  // Invalidator requires object id to work.
+  invalidator_.SetInvalidationObjectID(kTestingObjectId1);
+  VerifyInvalidationEnabled(kTestingObjectId1);
+
+  StopAndShutdown();
+}
+
+// Verifies that registered state changes work as expected.
+TEST_F(RemoteCommandsInvalidatorTest, RegistedStateChange) {
+  InitializeAndStart();
+
+  invalidator_.SetInvalidationObjectID(kTestingObjectId1);
+  VerifyInvalidationEnabled(kTestingObjectId1);
+
+  invalidator_.SetInvalidationObjectID(kTestingObjectId2);
+  VerifyInvalidationEnabled(kTestingObjectId2);
+  VerifyInvalidationDisabled(kTestingObjectId1);
+
+  invalidator_.SetInvalidationObjectID(kTestingObjectId1);
+  VerifyInvalidationEnabled(kTestingObjectId1);
+  VerifyInvalidationDisabled(kTestingObjectId2);
+
+  invalidator_.ClearInvalidationObjectID();
+  VerifyInvalidationDisabled(kTestingObjectId1);
+  VerifyInvalidationDisabled(kTestingObjectId2);
+  EXPECT_FALSE(invalidator_.invalidations_enabled());
+
+  invalidator_.SetInvalidationObjectID(kTestingObjectId2);
+  VerifyInvalidationEnabled(kTestingObjectId2);
+  VerifyInvalidationDisabled(kTestingObjectId1);
+
+  StopAndShutdown();
+}
+
+// Verifies that invalidation service enabled state changes work as expected.
+TEST_F(RemoteCommandsInvalidatorTest, InvalidationServiceEnabledStateChanged) {
+  InitializeAndStart();
+
+  invalidator_.SetInvalidationObjectID(kTestingObjectId1);
+  VerifyInvalidationEnabled(kTestingObjectId1);
+
+  DisableInvalidationService();
+  EXPECT_FALSE(invalidator_.invalidations_enabled());
+
+  EnableInvalidationService();
+  VerifyInvalidationEnabled(kTestingObjectId1);
+
+  EnableInvalidationService();
+  VerifyInvalidationEnabled(kTestingObjectId1);
+
+  DisableInvalidationService();
+  EXPECT_FALSE(invalidator_.invalidations_enabled());
+
+  DisableInvalidationService();
+  EXPECT_FALSE(invalidator_.invalidations_enabled());
+
+  StopAndShutdown();
+}
+
+}  // namespace policy
diff --git a/chrome/browser/policy/test/local_policy_test_server.cc b/chrome/browser/policy/test/local_policy_test_server.cc
index d4bb6c7..439067f 100644
--- a/chrome/browser/policy/test/local_policy_test_server.cc
+++ b/chrome/browser/policy/test/local_policy_test_server.cc
@@ -240,7 +240,7 @@
 
     if (!clients_.empty()) {
       std::string json;
-      base::JSONWriter::Write(&clients_, &json);
+      base::JSONWriter::Write(clients_, &json);
       base::FilePath client_state_file =
           server_data_dir_.path().Append(kClientStateFileName);
       if (base::WriteFile(client_state_file, json.c_str(), json.size()) !=
diff --git a/chrome/browser/profile_resetter/resettable_settings_snapshot.cc b/chrome/browser/profile_resetter/resettable_settings_snapshot.cc
index d7d00017..da82550 100644
--- a/chrome/browser/profile_resetter/resettable_settings_snapshot.cc
+++ b/chrome/browser/profile_resetter/resettable_settings_snapshot.cc
@@ -215,7 +215,7 @@
                 "new field needs to be serialized here");
 
   std::string json;
-  base::JSONWriter::Write(&dict, &json);
+  base::JSONWriter::Write(dict, &json);
   return json;
 }
 
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu.cc b/chrome/browser/renderer_context_menu/render_view_context_menu.cc
index be5d6ef..3c5e9a0 100644
--- a/chrome/browser/renderer_context_menu/render_view_context_menu.cc
+++ b/chrome/browser/renderer_context_menu/render_view_context_menu.cc
@@ -62,6 +62,7 @@
 #include "chrome/common/spellcheck_messages.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/grit/generated_resources.h"
+#include "components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h"
 #include "components/google/core/browser/google_util.h"
 #include "components/metrics/proto/omnibox_input_type.pb.h"
 #include "components/omnibox/autocomplete_match.h"
@@ -220,8 +221,10 @@
     {63, IDC_WRITING_DIRECTION_DEFAULT},
     {64, IDC_WRITING_DIRECTION_LTR},
     {65, IDC_WRITING_DIRECTION_RTL},
+    {66, IDC_CONTENT_CONTEXT_SHOW_ORIGINAL_IMAGE},
     // Add new items here and use |enum_id| from the next line.
-    {66, 0},  // Must be the last. Increment |enum_id| when new IDC was added.
+    // Also, add new items to RenderViewContextMenuItem enum in histograms.xml.
+    {67, 0},  // Must be the last. Increment |enum_id| when new IDC was added.
 };
 
 // Collapses large ranges of ids before looking for UMA enum.
@@ -741,6 +744,14 @@
                                   IDS_CONTENT_CONTEXT_COPYIMAGELOCATION);
   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYIMAGE,
                                   IDS_CONTENT_CONTEXT_COPYIMAGE);
+  std::map<std::string, std::string>::const_iterator it =
+      params_.properties.find(data_reduction_proxy::chrome_proxy_header());
+  if (it != params_.properties.end() && it->second ==
+      data_reduction_proxy::chrome_proxy_lo_fi_directive()) {
+    menu_model_.AddItemWithStringId(
+        IDC_CONTENT_CONTEXT_SHOW_ORIGINAL_IMAGE,
+        IDS_CONTENT_CONTEXT_SHOW_ORIGINAL_IMAGE);
+  }
   DataReductionProxyChromeSettings* settings =
       DataReductionProxyChromeSettingsFactory::GetForBrowserContext(
           browser_context_);
@@ -1161,6 +1172,7 @@
     // The images shown in the most visited thumbnails can't be opened or
     // searched for conventionally.
     case IDC_CONTENT_CONTEXT_OPEN_ORIGINAL_IMAGE_NEW_TAB:
+    case IDC_CONTENT_CONTEXT_SHOW_ORIGINAL_IMAGE:
     case IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB:
     case IDC_CONTENT_CONTEXT_SEARCHWEBFORIMAGE:
       return params_.src_url.is_valid() &&
@@ -1476,6 +1488,10 @@
           data_reduction_proxy::kDataReductionPassThroughHeader);
       break;
 
+    case IDC_CONTENT_CONTEXT_SHOW_ORIGINAL_IMAGE:
+      ShowOriginalImage();
+      break;
+
     case IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB:
     case IDC_CONTENT_CONTEXT_OPENAVNEWTAB:
       OpenURL(params_.src_url,
@@ -1830,6 +1846,14 @@
   source_web_contents_->GetRenderViewHost()->CopyImageAt(x, y);
 }
 
+void RenderViewContextMenu::ShowOriginalImage() {
+  RenderFrameHost* render_frame_host = GetRenderFrameHost();
+  if (!render_frame_host)
+    return;
+  render_frame_host->Send(new ChromeViewMsg_RequestReloadImageForContextNode(
+      render_frame_host->GetRoutingID()));
+}
+
 void RenderViewContextMenu::GetImageThumbnailForSearch() {
   RenderFrameHost* render_frame_host = GetRenderFrameHost();
   if (!render_frame_host)
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu.h b/chrome/browser/renderer_context_menu/render_view_context_menu.h
index e492994..c033698 100644
--- a/chrome/browser/renderer_context_menu/render_view_context_menu.h
+++ b/chrome/browser/renderer_context_menu/render_view_context_menu.h
@@ -134,6 +134,9 @@
   // Copy to the clipboard an image located at a point in the RenderView
   void CopyImageAt(int x, int y);
 
+  // Show the original image located at a point in the RenderView.
+  void ShowOriginalImage();
+
   // Get an image located at a point in the RenderView for search.
   void GetImageThumbnailForSearch();
 
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu_browsertest.cc b/chrome/browser/renderer_context_menu/render_view_context_menu_browsertest.cc
index 0498a2c..823dbafd 100644
--- a/chrome/browser/renderer_context_menu/render_view_context_menu_browsertest.cc
+++ b/chrome/browser/renderer_context_menu/render_view_context_menu_browsertest.cc
@@ -4,6 +4,7 @@
 
 #include <string>
 
+#include "base/bind.h"
 #include "base/command_line.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
@@ -34,6 +35,10 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/test_utils.h"
+#include "net/base/load_flags.h"
+#include "net/url_request/url_request.h"
+#include "net/url_request/url_request_filter.h"
+#include "net/url_request/url_request_interceptor.h"
 #include "third_party/WebKit/public/web/WebContextMenuData.h"
 #include "third_party/WebKit/public/web/WebInputEvent.h"
 
@@ -525,4 +530,125 @@
   EXPECT_EQ(ThumbnailResponseWatcher::THUMBNAIL_RECEIVED, watcher.Wait());
 }
 
+class ShowImageRequestInterceptor : public net::URLRequestInterceptor {
+ public:
+  ShowImageRequestInterceptor() : num_requests_(0),
+                                  requests_to_wait_for_(-1),
+                                  weak_factory_(this) {
+  }
+
+  ~ShowImageRequestInterceptor() override {}
+
+  // net::URLRequestInterceptor implementation
+  net::URLRequestJob* MaybeInterceptRequest(
+      net::URLRequest* request,
+      net::NetworkDelegate* network_delegate) const override {
+    DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+    EXPECT_TRUE(request->load_flags() & net::LOAD_BYPASS_CACHE);
+    content::BrowserThread::PostTask(
+        content::BrowserThread::UI, FROM_HERE,
+        base::Bind(&ShowImageRequestInterceptor::RequestCreated,
+                   weak_factory_.GetWeakPtr()));
+    return nullptr;
+  }
+
+  void WaitForRequests(int requests_to_wait_for) {
+    DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+    DCHECK_EQ(-1, requests_to_wait_for_);
+    DCHECK(!run_loop_);
+
+    if (num_requests_ >= requests_to_wait_for)
+      return;
+
+    requests_to_wait_for_ = requests_to_wait_for;
+    run_loop_.reset(new base::RunLoop());
+    run_loop_->Run();
+    run_loop_.reset();
+    requests_to_wait_for_ = -1;
+    EXPECT_EQ(num_requests_, requests_to_wait_for);
+  }
+
+  // It is up to the caller to wait until all relevant requests has been
+  // created, either through calling WaitForRequests or some other manner,
+  // before calling this method.
+  int num_requests() const {
+    DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+    return num_requests_;
+  }
+
+ private:
+  void RequestCreated() {
+    DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+    num_requests_++;
+    if (num_requests_ == requests_to_wait_for_)
+      run_loop_->Quit();
+  }
+
+  // These are only used on the UI thread.
+  int num_requests_;
+  int requests_to_wait_for_;
+  scoped_ptr<base::RunLoop> run_loop_;
+
+  // This prevents any risk of flake if any test doesn't wait for a request
+  // it sent.  Mutable so it can be accessed from a const function.
+  mutable base::WeakPtrFactory<ShowImageRequestInterceptor> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(ShowImageRequestInterceptor);
+};
+
+class ShowImageBrowserTest : public InProcessBrowserTest {
+ protected:
+  void SetupAndLoadImagePage(const std::string& image_path) {
+    // Go to a page with an image in it. The test server doesn't serve the image
+    // with the right MIME type, so use a data URL to make a page containing it.
+    GURL image_url(test_server()->GetURL(image_path));
+    GURL page("data:text/html,<img src='" + image_url.spec() + "'>");
+    ui_test_utils::NavigateToURL(browser(), page);
+  }
+
+  void AddShowImageInterceptor(const std::string& image_path) {
+    interceptor_ = new ShowImageRequestInterceptor();
+    scoped_ptr<net::URLRequestInterceptor> owned_interceptor(interceptor_);
+    content::BrowserThread::PostTask(
+        content::BrowserThread::IO, FROM_HERE,
+        base::Bind(&ShowImageBrowserTest::AddInterceptorForURL,
+                   base::Unretained(this),
+                   GURL(test_server()->GetURL(image_path).spec()),
+                   base::Passed(&owned_interceptor)));
+  }
+
+  void AttemptShowImage() {
+    // Right-click where the image should be.
+    // |menu_observer_| will cause the show-image menu item to be clicked.
+    menu_observer_.reset(new ContextMenuNotificationObserver(
+        IDC_CONTENT_CONTEXT_SHOW_ORIGINAL_IMAGE));
+    content::WebContents* tab =
+        browser()->tab_strip_model()->GetActiveWebContents();
+    content::SimulateMouseClickAt(tab, 0, blink::WebMouseEvent::ButtonRight,
+                                  gfx::Point(15, 15));
+  }
+
+  void AddInterceptorForURL(
+      const GURL& url, scoped_ptr<net::URLRequestInterceptor> handler) {
+    DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+    net::URLRequestFilter::GetInstance()->AddUrlInterceptor(
+        url, handler.Pass());
+  }
+
+  ShowImageRequestInterceptor* interceptor_;
+
+ private:
+  scoped_ptr<ContextMenuNotificationObserver> menu_observer_;
+};
+
+IN_PROC_BROWSER_TEST_F(ShowImageBrowserTest, ShowImage) {
+  static const char kValidImage[] = "files/show_image/image.png";
+  SetupAndLoadImagePage(kValidImage);
+  AddShowImageInterceptor(kValidImage);
+  AttemptShowImage();
+  interceptor_->WaitForRequests(1);
+  EXPECT_EQ(1, interceptor_->num_requests());
+}
+
 }  // namespace
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu_unittest.cc b/chrome/browser/renderer_context_menu/render_view_context_menu_unittest.cc
index c55c0ce9..66c8b7c 100644
--- a/chrome/browser/renderer_context_menu/render_view_context_menu_unittest.cc
+++ b/chrome/browser/renderer_context_menu/render_view_context_menu_unittest.cc
@@ -23,6 +23,7 @@
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h"
+#include "components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h"
 #include "content/public/browser/web_contents.h"
@@ -356,6 +357,10 @@
     return menu;
   }
 
+  void AppendImageItems(TestRenderViewContextMenu* menu) {
+    menu->AppendImageItems();
+  }
+
   void SetupDataReductionProxy(bool enable_data_reduction_proxy) {
     drp_test_context_ =
         data_reduction_proxy::DataReductionProxyTestContext::Builder()
@@ -467,3 +472,19 @@
                   std::string::npos &&
               headers.find("Cache-Control: no-cache") == std::string::npos);
 }
+
+// Verify that the Chrome-Proxy Lo-Fi directive causes the context menu to
+// display the "Show Image" menu item.
+TEST_F(RenderViewContextMenuPrefsTest, DataSaverShowImage) {
+  SetupDataReductionProxy(true);
+  content::ContextMenuParams params = CreateParams(MenuItem::IMAGE);
+  params.properties[data_reduction_proxy::chrome_proxy_header()] =
+      data_reduction_proxy::chrome_proxy_lo_fi_directive();
+  params.unfiltered_link_url = params.link_url;
+  content::WebContents* wc = web_contents();
+  scoped_ptr<TestRenderViewContextMenu> menu(
+      new TestRenderViewContextMenu(wc->GetMainFrame(), params));
+  AppendImageItems(menu.get());
+
+  ASSERT_TRUE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_SHOW_ORIGINAL_IMAGE));
+}
diff --git a/chrome/browser/resources/chromeos/chromevox/manifest.json.jinja2 b/chrome/browser/resources/chromeos/chromevox/manifest.json.jinja2
index 68b27ad..88ee980 100644
--- a/chrome/browser/resources/chromeos/chromevox/manifest.json.jinja2
+++ b/chrome/browser/resources/chromeos/chromevox/manifest.json.jinja2
@@ -55,8 +55,8 @@
   "automation": {
     "desktop": true
   },
-{% if is_chromevox_classic == '0' %}
   "commands": {
+{% if is_chromevox_classic == '0' %}
     "nextElement": {
       "description": "__MSG_CHROMEVOX_NEXT_OBJECT__",
       "suggested_key": {
@@ -279,8 +279,8 @@
         "chromeos": "Search+Shift+R"
       }
     }
-  },
 {% endif %}
+  },
   "options_page": "chromevox/background/options.html",
   "default_locale": "en"
 }
diff --git a/chrome/browser/resources/chromeos/login/gaia_password_changed.html b/chrome/browser/resources/chromeos/login/gaia_password_changed.html
index 82d8fd1..be137ac 100644
--- a/chrome/browser/resources/chromeos/login/gaia_password_changed.html
+++ b/chrome/browser/resources/chromeos/login/gaia_password_changed.html
@@ -45,11 +45,12 @@
             <p i18n-content="passwordChangedTitle">
             </p>
           </div>
-          <gaia-input-form class="footer" id="oldPasswordInput"
-              inputtype="password"
-              i18n-values="errorMsg:oldPasswordIncorrect;
-                          inputLabel:oldPasswordHint;
-                          buttonText:nextButtonText">
+          <gaia-input-form class="footer" id="oldPasswordInputForm"
+              i18n-values="buttonText:nextButtonText">
+            <gaia-input id="oldPasswordInput" type="password"
+                i18n-values="error:oldPasswordIncorrect;
+                             label:oldPasswordHint">
+            </gaia-input>
             <gaia-paper-button noink i18n-content="forgotOldPasswordButtonText"
                 class="link-button"
                 on-tap="{{onForgotPasswordClicked}}">
diff --git a/chrome/browser/resources/chromeos/login/gaia_password_changed.js b/chrome/browser/resources/chromeos/login/gaia_password_changed.js
index a004678..9887a4b 100644
--- a/chrome/browser/resources/chromeos/login/gaia_password_changed.js
+++ b/chrome/browser/resources/chromeos/login/gaia_password_changed.js
@@ -5,21 +5,21 @@
 
 Polymer('gaia-password-changed', {
   invalidate: function() {
-    this.$.oldPasswordInput.setValid(false);
+    this.$.oldPasswordInput.isInvalid = true;
   },
 
   reset: function() {
     this.$.animatedPages.selected = 0;
     this.clearPassword();
-    this.$.oldPasswordInput.setValid(true);
+    this.$.oldPasswordInput.isInvalid = false;
     this.disabled = false;
     this.$.closeButton.hidden = false;
     this.$.oldPasswordCard.classList.remove('disabled');
   },
 
   ready: function() {
-    this.$.oldPasswordInput.addEventListener('buttonClick', function() {
-      var inputPassword = this.$.oldPasswordInput.inputValue;
+    this.$.oldPasswordInputForm.addEventListener('submit', function() {
+      var inputPassword = this.$.oldPasswordInput.value;
       if (!inputPassword)
         this.invalidate();
       else {
@@ -36,7 +36,7 @@
   },
 
   set disabled(value) {
-    this.$.oldPasswordInput.disabled = value;
+    this.$.oldPasswordInputForm.disabled = value;
   },
 
   onForgotPasswordClicked: function() {
@@ -45,7 +45,7 @@
   },
 
   onTryAgainClicked: function() {
-    this.$.oldPasswordInput.setValid(true);
+    this.$.oldPasswordInput.isInvalid = false;
     this.$.animatedPages.selected -= 1;
   },
 
@@ -54,7 +54,7 @@
   },
 
   clearPassword: function() {
-    this.$.oldPasswordInput.inputValue = '';
+    this.$.oldPasswordInput.value = '';
   },
 
   onProceedClicked: function() {
diff --git a/chrome/browser/resources/chromeos/login/header_bar.css b/chrome/browser/resources/chromeos/login/header_bar.css
index a1fd095..3e8a1e8 100644
--- a/chrome/browser/resources/chromeos/login/header_bar.css
+++ b/chrome/browser/resources/chromeos/login/header_bar.css
@@ -77,8 +77,10 @@
   color: black !important;
   display: block;
   font-size: 13px;
+  height: auto;
   left: 15px;
   margin: 0 0 -10px -10px;
+  min-height: 34px;
   position: absolute;
   text-align: center;
   width: 180px;
diff --git a/chrome/browser/resources/chromeos/login/header_bar.js b/chrome/browser/resources/chromeos/login/header_bar.js
index 9cf78ad..20c551e 100644
--- a/chrome/browser/resources/chromeos/login/header_bar.js
+++ b/chrome/browser/resources/chromeos/login/header_bar.js
@@ -352,7 +352,8 @@
           accountPickerIsActive ||
           !this.allowCancel_ ||
           wrongHWIDWarningIsActive ||
-          isMultiProfilesUI;
+          isMultiProfilesUI ||
+          supervisedUserCreationDialogIsActive;
       $('guest-user-header-bar-item').hidden =
           (gaiaIsActive && !this.isNewGaiaFlow_) ||
           supervisedUserCreationDialogIsActiveAndNotIntro ||
diff --git a/chrome/browser/resources/chromeos/login/oobe_screen_eula.js b/chrome/browser/resources/chromeos/login/oobe_screen_eula.js
index b43d666..f6c85cc 100644
--- a/chrome/browser/resources/chromeos/login/oobe_screen_eula.js
+++ b/chrome/browser/resources/chromeos/login/oobe_screen_eula.js
@@ -96,6 +96,7 @@
       acceptButton.textContent = loadTimeData.getString('acceptAgreement');
       acceptButton.addEventListener('click', function(e) {
         $('eula').classList.add('loading');  // Mark EULA screen busy.
+        Oobe.clearErrors();
         e.stopPropagation();
       });
       buttons.push(acceptButton);
diff --git a/chrome/browser/resources/chromeos/login/screen_gaia_signin.js b/chrome/browser/resources/chromeos/login/screen_gaia_signin.js
index 0fc43f40..388a8a5 100644
--- a/chrome/browser/resources/chromeos/login/screen_gaia_signin.js
+++ b/chrome/browser/resources/chromeos/login/screen_gaia_signin.js
@@ -33,7 +33,6 @@
       'onFrameError',
       'updateCancelButtonState',
       'showWhitelistCheckFailedError',
-      'updateDeviceId',
     ],
 
     /**
@@ -153,8 +152,6 @@
           'backButton', this.onBackButton_.bind(this));
       this.gaiaAuthHost_.addEventListener(
           'showView', this.onShowView_.bind(this));
-      this.gaiaAuthHost_.addEventListener('attemptLogin',
-                                          this.onAttemptLogin_.bind(this));
       this.gaiaAuthHost_.confirmPasswordCallback =
           this.onAuthConfirmPassword_.bind(this);
       this.gaiaAuthHost_.noPasswordCallback =
@@ -630,16 +627,6 @@
     },
 
     /**
-     * Invoked when the auth host emits 'attemptLogin' event.
-     * @param {Object} Message object with |detail| field keeping email:
-     * like {detail: 'user@gmail.com'} .
-     * @private
-     */
-    onAttemptLogin_: function(e) {
-      chrome.send('attemptLogin', [e.detail]);
-    },
-
-    /**
      * Invoked when the user has successfully authenticated via SAML, the
      * principals API was not used and the auth host needs the user to confirm
      * the scraped password.
@@ -747,8 +734,7 @@
             credentials.email,
             credentials.password,
             credentials.authCode,
-            credentials.usingSAML,
-            credentials.deviceId
+            credentials.usingSAML
           ]);
         }
       } else {
@@ -953,18 +939,6 @@
 
       if (!show)
         Oobe.showSigninUI();
-    },
-
-    /**
-     * Inform Gaia of new deviceId.
-     * @param {data} Object like {'deviceId': 'test-device-id'}
-     */
-    updateDeviceId: function(data) {
-      if (!this.isNewGaiaFlow)
-        return;
-
-      if (data && data.deviceId)
-        this.gaiaAuthHost_.updateDeviceId(data.deviceId);
-    },
+    }
   };
 });
diff --git a/chrome/browser/resources/chromeos/login/screen_supervised_user_creation.css b/chrome/browser/resources/chromeos/login/screen_supervised_user_creation.css
index 0db1542..30416a6 100644
--- a/chrome/browser/resources/chromeos/login/screen_supervised_user_creation.css
+++ b/chrome/browser/resources/chromeos/login/screen_supervised_user_creation.css
@@ -549,3 +549,16 @@
 .camera.live:not(.online) .supervised-user-creation-image-stream-area .spinner {
   display: block;
 }
+
+#supervised-user-creation-close-button-item {
+  color: rgba(0, 0, 0, .54);
+  position: absolute;
+  right: 10px;
+  top: 10px;
+  z-index: 1;
+}
+
+html[dir=rtl] #supervised-user-creation-close-button-item {
+  left: 10px;
+  right: auto;
+}
diff --git a/chrome/browser/resources/chromeos/login/screen_supervised_user_creation.html b/chrome/browser/resources/chromeos/login/screen_supervised_user_creation.html
index 170b473..8be6fc77 100644
--- a/chrome/browser/resources/chromeos/login/screen_supervised_user_creation.html
+++ b/chrome/browser/resources/chromeos/login/screen_supervised_user_creation.html
@@ -1,3 +1,4 @@
+<link rel="import" href="chrome://oobe/custom_elements.html">
 <div class="step hidden" id="supervised-user-creation" hidden>
   <div class="step-contents">
     <div id="supervised-user-creation-intro" class="step-no-logo">
@@ -157,4 +158,7 @@
     <img class="import-pod-image"></img>
     <div class="import-pod-name"></div>
   </div>
+  <button id="supervised-user-creation-close-button-item" is="gaia-icon-button"
+      icon="close" i18n-values="aria-label:closeButton" tabindex="0">
+  </button>
 </div>
diff --git a/chrome/browser/resources/chromeos/login/screen_supervised_user_creation.js b/chrome/browser/resources/chromeos/login/screen_supervised_user_creation.js
index be8f355..c7d44f8 100644
--- a/chrome/browser/resources/chromeos/login/screen_supervised_user_creation.js
+++ b/chrome/browser/resources/chromeos/login/screen_supervised_user_creation.js
@@ -616,6 +616,12 @@
           'webkitTransitionEnd', function(e) {
             previewElement.classList.remove('animation');
           });
+
+      $('supervised-user-creation-close-button-item').addEventListener(
+          'click', function(e) {
+            this.cancel();
+            e.preventDefault();
+          }.bind(this));
     },
 
     buttonIds: [],
@@ -1193,6 +1199,9 @@
             !this.importList_.selectedPod_ ||
             this.importList_.selectedPod_.user.exists;
       }
+      $('supervised-user-creation-close-button-item').hidden =
+          (visiblePage == 'created');
+
       chrome.send('currentSupervisedUserPage', [this.currentPage_]);
     },
 
diff --git a/chrome/browser/resources/gaia_auth_host/authenticator.js b/chrome/browser/resources/gaia_auth_host/authenticator.js
index 020493cd..87580d9 100644
--- a/chrome/browser/resources/gaia_auth_host/authenticator.js
+++ b/chrome/browser/resources/gaia_auth_host/authenticator.js
@@ -29,8 +29,6 @@
   var OAUTH_CODE_COOKIE = 'oauth_code';
   var SERVICE_ID = 'chromeoslogin';
   var EMBEDDED_SETUP_CHROMEOS_ENDPOINT = 'embedded/setup/chromeos';
-  var X_DEVICE_ID_HEADER = 'X-Device-ID';
-  var EPHEMERAL_DEVICE_ID_PREFIX = 't_';
 
   /**
    * The source URL parameter for the constrained signin flow.
@@ -85,8 +83,6 @@
     'enterpriseDomain',    // Domain in which hosting device is (or should be)
                            // enrolled.
     'emailDomain',         // Value used to prefill domain for email.
-    'deviceId',            // User device ID (sync Id).
-    'sessionIsEphemeral',  // User session would be ephemeral.
     'clientVersion',       // Version of the Chrome build.
     'platformVersion',     // Version of the OS build.
     'releaseChannel',      // Installation channel.
@@ -119,9 +115,6 @@
     this.reloadUrl_ = null;
     this.trusted_ = true;
     this.oauth_code_ = null;
-    this.deviceId_ = null;
-    this.sessionIsEphemeral_ = null;
-    this.onBeforeSetHeadersSet_ = false;
 
     this.useEafe_ = false;
     this.clientId_ = null;
@@ -216,14 +209,6 @@
       this.webview_.contextMenus.onShow.addListener(function(e) {
         e.preventDefault();
       });
-      if (!this.onBeforeSetHeadersSet_) {
-        this.onBeforeSetHeadersSet_ = true;
-        var filterPrefix = this.idpOrigin_ + EMBEDDED_SETUP_CHROMEOS_ENDPOINT;
-        this.webview_.request.onBeforeSendHeaders.addListener(
-            this.onBeforeSendHeaders_.bind(this),
-            {urls: [filterPrefix + '?*', filterPrefix + '/*']},
-            ['requestHeaders', 'blocking']);
-      }
     }
 
     this.webview_.src = this.reloadUrl_;
@@ -261,8 +246,6 @@
         url = appendParam(url, 'release_channel', data.releaseChannel);
       if (data.endpointGen)
         url = appendParam(url, 'endpoint_gen', data.endpointGen);
-      this.deviceId_ = data.deviceId;
-      this.sessionIsEphemeral_ = data.sessionIsEphemeral;
     } else {
       url = appendParam(url, 'continue', this.continueUrl_);
       url = appendParam(url, 'service', data.service || SERVICE_ID);
@@ -397,36 +380,6 @@
   };
 
   /**
-   * Handler for webView.request.onBeforeSendHeaders .
-   * @return {!Object} Modified request headers.
-   * @private
-   */
-  Authenticator.prototype.onBeforeSendHeaders_ = function(details) {
-    // deviceId_ is empty when we do not need to send it. For example,
-    // in case of device enrollment.
-    if (this.isNewGaiaFlowChromeOS && this.deviceId_) {
-      var headers = details.requestHeaders;
-      var found = false;
-      var deviceId = this.getGAIADeviceId_();
-
-      for (var i = 0, l = headers.length; i < l; ++i) {
-        if (headers[i].name == X_DEVICE_ID_HEADER) {
-          headers[i].value = deviceId;
-          found = true;
-          break;
-        }
-      }
-      if (!found) {
-        details.requestHeaders.push(
-            {name: X_DEVICE_ID_HEADER, value: deviceId});
-      }
-    }
-    return {
-      requestHeaders: details.requestHeaders
-    };
-  };
-
-  /**
    * Returns true if given HTML5 message is received from the webview element.
    * @param {object} e Payload of the received HTML5 message.
    */
@@ -582,8 +535,7 @@
                             chooseWhatToSync: this.chooseWhatToSync_,
                             skipForNow: this.skipForNow_,
                             sessionIndex: this.sessionIndex_ || '',
-                            trusted: this.trusted_,
-                            deviceId: this.deviceId_ || ''
+                            trusted: this.trusted_
                           }
                         }));
     this.clearCredentials_();
@@ -647,7 +599,6 @@
     if (currentUrl.lastIndexOf(this.idpOrigin_) == 0) {
       var msg = {
         'method': 'handshake',
-        'deviceId': this.getGAIADeviceId_(),
       };
 
       this.webview_.contentWindow.postMessage(msg, currentUrl);
@@ -716,37 +667,6 @@
   };
 
   /**
-   * Format deviceId for GAIA .
-   * @return {string} deviceId.
-   * @private
-   */
-  Authenticator.prototype.getGAIADeviceId_ = function() {
-    // deviceId_ is empty when we do not need to send it. For example,
-    // in case of device enrollment.
-    if (!(this.isNewGaiaFlowChromeOS && this.deviceId_))
-      return;
-
-    if (this.sessionIsEphemeral_)
-      return EPHEMERAL_DEVICE_ID_PREFIX + this.deviceId_;
-    else
-      return this.deviceId_;
-  };
-
-  /**
-   * Informs Gaia of new deviceId to be used.
-   */
-  Authenticator.prototype.updateDeviceId = function(deviceId) {
-    this.deviceId_ = deviceId;
-    var msg = {
-      'method': 'updateDeviceId',
-      'deviceId': this.getGAIADeviceId_(),
-    };
-
-    var currentUrl = this.webview_.src;
-    this.webview_.contentWindow.postMessage(msg, currentUrl);
-  };
-
-  /**
    * The current auth flow of the hosted auth page.
    * @type {AuthFlow}
    */
diff --git a/chrome/browser/resources/google_now/background.js b/chrome/browser/resources/google_now/background.js
index 2db2d1e..aebf1be 100644
--- a/chrome/browser/resources/google_now/background.js
+++ b/chrome/browser/resources/google_now/background.js
@@ -1028,8 +1028,6 @@
  */
 function initialize() {
   recordEvent(GoogleNowEvent.EXTENSION_START);
-  // TODO(skare): Reenable, after signin.
-  unregisterFromGcm();
   onStateChange();
 }
 
@@ -1054,7 +1052,8 @@
 }
 
 /**
- * Starts or stops the optin check.
+ * Starts or stops the optin check and GCM channel to receive optin
+ * notifications.
  * @param {boolean} shouldPollOptInStatus true to start and false to stop
  *     polling the optin status.
  */
@@ -1073,6 +1072,12 @@
           'Action Ignored setShouldPollOptInStatus=' + shouldPollOptInStatus);
     }
   });
+
+  if (shouldPollOptInStatus) {
+    registerForGcm();
+  } else {
+    unregisterFromGcm();
+  }
 }
 
 /**
diff --git a/chrome/browser/resources/local_ntp/most_visited_single.js b/chrome/browser/resources/local_ntp/most_visited_single.js
index ce9fb810..46d2897 100644
--- a/chrome/browser/resources/local_ntp/most_visited_single.js
+++ b/chrome/browser/resources/local_ntp/most_visited_single.js
@@ -338,11 +338,16 @@
 
   tile.href = data.url;
   tile.title = data.title;
-  tile.addEventListener('keypress', function(ev) {
-    if (ev.keyCode == 127) { // DELETE
+  tile.addEventListener('keydown', function(event) {
+    if (event.keyCode == 46 /* DELETE */ ||
+        event.keyCode == 8 /* BACKSPACE */) {
+      event.preventDefault();
+      event.stopPropagation();
       blacklistTile(tile);
-      ev.stopPropagation();
-      return false;
+    } else if (event.keyCode == 13 /* ENTER */ ||
+               event.keyCode == 32 /* SPACE */) {
+      event.preventDefault();
+      tile.click();
     }
   });
   // TODO(fserb): remove this or at least change to mouseenter.
diff --git a/chrome/browser/resources/media_router/media_router_common.css b/chrome/browser/resources/media_router/media_router_common.css
index 47d72ae..4add52ebc 100644
--- a/chrome/browser/resources/media_router/media_router_common.css
+++ b/chrome/browser/resources/media_router/media_router_common.css
@@ -9,6 +9,7 @@
   cursor: pointer;
   font-size: 1em;
   font-weight: bold;
+  margin: 0;
   overflow: hidden;
   text-align: center;
   width: 100%;
diff --git a/chrome/browser/resources/ntp4/compiled_resources.gyp b/chrome/browser/resources/ntp4/compiled_resources.gyp
index 8316d78..ed02952 100644
--- a/chrome/browser/resources/ntp4/compiled_resources.gyp
+++ b/chrome/browser/resources/ntp4/compiled_resources.gyp
@@ -39,7 +39,6 @@
           'page_list_view.js',
           'nav_dot.js',
           'other_sessions.js',
-          'suggestions_page.js',
           'new_tab.js',
         ],
         'externs': ['<(CLOSURE_DIR)/externs/chrome_send_externs.js'],
diff --git a/chrome/browser/resources/ntp4/new_tab.html b/chrome/browser/resources/ntp4/new_tab.html
index 3694ba00..4cac17a1 100644
--- a/chrome/browser/resources/ntp4/new_tab.html
+++ b/chrome/browser/resources/ntp4/new_tab.html
@@ -27,7 +27,6 @@
 <link rel="stylesheet" href="../../../../ui/webui/resources/css/trash.css">
 <link rel="stylesheet" href="../../../../ui/webui/resources/css/widgets.css">
 <link rel="stylesheet" href="apps_page.css">
-<link rel="stylesheet" href="chrome://newtab/suggestions_page.css">
 <link rel="stylesheet" href="most_visited_page.css">
 <link rel="stylesheet" href="nav_dot.css">
 <link rel="stylesheet" href="new_tab.css">
diff --git a/chrome/browser/resources/ntp4/new_tab.js b/chrome/browser/resources/ntp4/new_tab.js
index 007bd039..4c1ac76 100644
--- a/chrome/browser/resources/ntp4/new_tab.js
+++ b/chrome/browser/resources/ntp4/new_tab.js
@@ -137,8 +137,6 @@
             function() { chrome.send('onLearnMore'); });
       }
     }
-    if (loadTimeData.getBoolean('isDiscoveryInNTPEnabled'))
-      sectionsToWaitFor++;
     measureNavDots();
 
     // Load the current theme colors.
@@ -171,21 +169,6 @@
       chrome.send('getMostVisited');
     }
 
-    if (loadTimeData.getBoolean('isDiscoveryInNTPEnabled')) {
-      var suggestionsScript = document.createElement('script');
-      suggestionsScript.src = 'suggestions_page.js';
-      suggestionsScript.onload = function() {
-         newTabView.appendTilePage(new ntp.SuggestionsPage(),
-                                   loadTimeData.getString('suggestions'),
-                                   false,
-                                   (newTabView.appsPages.length > 0) ?
-                                       newTabView.appsPages[0] : null);
-         chrome.send('getSuggestions');
-         cr.dispatchSimpleEvent(document, 'sectionready', true, true);
-      };
-      document.querySelector('head').appendChild(suggestionsScript);
-    }
-
     if (!loadTimeData.getBoolean('showWebStoreIcon')) {
       var webStoreIcon = $('chrome-web-store-link');
       // Not all versions of the NTP have a footer, so this may not exist.
@@ -547,10 +530,6 @@
     cr.dispatchSimpleEvent(document, 'sectionready', true, true);
   }
 
-  function setSuggestionsPages(data, hasBlacklistedUrls) {
-    newTabView.suggestionsPage.data = data;
-  }
-
   /**
    * Set the dominant color for a node. This will be called in response to
    * getFaviconDominantColor. The node represented by |id| better have a setter
@@ -759,7 +738,6 @@
     setBookmarkBarAttached: setBookmarkBarAttached,
     setForeignSessions: setForeignSessions,
     setMostVisitedPages: setMostVisitedPages,
-    setSuggestionsPages: setSuggestionsPages,
     setFaviconDominantColor: setFaviconDominantColor,
     showNotification: showNotification,
     themeChanged: themeChanged,
diff --git a/chrome/browser/resources/ntp4/page_list_view.js b/chrome/browser/resources/ntp4/page_list_view.js
index 14c613b..fa1513b9 100644
--- a/chrome/browser/resources/ntp4/page_list_view.js
+++ b/chrome/browser/resources/ntp4/page_list_view.js
@@ -86,12 +86,6 @@
     appsPages: undefined,
 
     /**
-     * The Suggestions page.
-     * @type {!Element|undefined}
-     */
-    suggestionsPage: undefined,
-
-    /**
      * The Most Visited page.
      * @type {!Element|undefined}
      */
@@ -273,11 +267,6 @@
         this.mostVisitedPage = page;
       }
 
-      if (typeof ntp.SuggestionsPage != 'undefined' &&
-          page instanceof ntp.SuggestionsPage) {
-        this.suggestionsPage = page;
-      }
-
       // If we're appending an AppsPage and it's a temporary page, animate it.
       var animate = page instanceof ntp.AppsPage &&
                     page.classList.contains('temporary');
@@ -536,19 +525,6 @@
                                         this.tilePages.length - 1));
       this.cardSlider.setCards(Array.prototype.slice.call(this.tilePages),
                                pageNo);
-      // The shownPage property was potentially saved from a previous webui that
-      // didn't have the same set of pages as the current one. So we cascade
-      // from suggestions, to most visited and then to apps because we can have
-      // an page with apps only (e.g., chrome://apps) or one with only the most
-      // visited, but not one with only suggestions. And we alwayd default to
-      // most visited first when previously shown page is not availabel anymore.
-      // If most visited isn't there either, we go to apps.
-      if (this.shownPage == loadTimeData.getInteger('suggestions_page_id')) {
-        if (this.suggestionsPage)
-          this.cardSlider.selectCardByValue(this.suggestionsPage);
-        else
-          this.shownPage = loadTimeData.getInteger('most_visited_page_id');
-      }
       if (this.shownPage == loadTimeData.getInteger('most_visited_page_id')) {
         if (this.mostVisitedPage)
           this.cardSlider.selectCardByValue(this.mostVisitedPage);
@@ -692,8 +668,6 @@
         } else if (page.classList.contains('most-visited-page')) {
           this.setShownPage_(
               loadTimeData.getInteger('most_visited_page_id'), 0);
-        } else if (page.classList.contains('suggestions-page')) {
-          this.setShownPage_(loadTimeData.getInteger('suggestions_page_id'), 0);
         } else {
           console.error('unknown page selected');
         }
diff --git a/chrome/browser/resources/ntp4/suggestions_page.css b/chrome/browser/resources/ntp4/suggestions_page.css
deleted file mode 100644
index 8fd1109..0000000
--- a/chrome/browser/resources/ntp4/suggestions_page.css
+++ /dev/null
@@ -1,109 +0,0 @@
-/* Copyright (c) 2012 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. */
-
-.suggestions {
-  position: absolute;
-  z-index: 0;
-}
-
-.suggestions {
-  -webkit-box-orient: vertical;
-  display: -webkit-box;
-  position: absolute;
-  text-decoration: none;
-}
-
-.suggestions:focus {
-  outline: none;
-}
-
-.suggestions .close-button {
-  -webkit-transition: opacity 150ms;
-  opacity: 0;
-  position: absolute;
-  right: 0;
-  top: 0;
-  z-index: 5;
-}
-
-html[dir=rtl] .suggestions .close-button {
-  left: 0;
-  right: auto;
-}
-
-.suggestions:hover .close-button {
-  -webkit-transition-delay: 500ms;
-  opacity: 1;
-}
-
-.suggestions .close-button:hover {
-  -webkit-transition: none;
-}
-
-.suggestions .favicon {
-  -webkit-margin-start: 5px;
-  background: no-repeat left 50%;
-  bottom: 7px;
-  box-sizing: border-box;
-  display: block;
-  height: 16px;
-  position: absolute;
-  width: 16px;
-}
-
-html[dir='rtl'] .suggestions .favicon {
-  background-position-x: right;
-}
-
-.suggestions .color-stripe {
-  border-bottom-left-radius: 3px 3px;
-  border-bottom-right-radius: 3px 3px;
-  /* Matches height of title plus height of score.  */
-  bottom: 36px;
-  height: 3px;
-  position: absolute;
-  width: 100%;
-  z-index: 10;
-}
-
-.suggestions .title {
-  display: block;
-  height: 18px;
-  overflow: hidden;
-  text-align: center;
-  text-overflow: ellipsis;
-  white-space: nowrap;
-}
-
-.suggestions .score {
-  display: block;
-  height: 18px;
-  overflow: hidden;
-  text-align: center;
-}
-
-.suggestions:focus .thumbnail,
-.suggestions:hover .thumbnail {
-  opacity: 0.95;
-}
-
-.suggestions:focus .thumbnail-shield,
-.suggestions:hover .thumbnail-shield,
-.suggestions:active .thumbnail-shield {
-  background: -webkit-linear-gradient(rgba(255, 255, 255, 0),
-                                      rgba(255, 255, 255, 0) 80%,
-                                      rgba(255, 255, 255, 0.9));
-}
-
-/* The thumbnail gets lighter when clicked, but not when the click is on the
- * close button. */
-.suggestions:active .close-button:not(:active) + .thumbnail {
-  opacity: 0.9;
-}
-
-/* The thumbnail gets a shadow when clicked, but not when the click is on the
- * close button. */
-.suggestions:active .close-button:not(:active) + .thumbnail .thumbnail-shield {
-  box-shadow: inset 0 1px 10px rgba(0, 0, 0, 0.2);
-}
diff --git a/chrome/browser/resources/ntp4/suggestions_page.js b/chrome/browser/resources/ntp4/suggestions_page.js
deleted file mode 100644
index 6dc5ecd..0000000
--- a/chrome/browser/resources/ntp4/suggestions_page.js
+++ /dev/null
@@ -1,478 +0,0 @@
-// Copyright (c) 2012 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.
-
-cr.define('ntp', function() {
-  'use strict';
-
-  var TilePage = ntp.TilePage;
-
-  /**
-   * A counter for generating unique tile IDs.
-   */
-  var tileID = 0;
-
-  /**
-   * Creates a new Suggestions page object for tiling.
-   * @constructor
-   * @extends {HTMLAnchorElement}
-   */
-  function Suggestion() {
-    var el = cr.doc.createElement('a');
-    el.__proto__ = Suggestion.prototype;
-    el.initialize();
-
-    return el;
-  }
-
-  Suggestion.prototype = {
-    __proto__: HTMLAnchorElement.prototype,
-
-    initialize: function() {
-      this.reset();
-
-      this.addEventListener('click', this.handleClick_);
-      this.addEventListener('keydown', this.handleKeyDown_);
-    },
-
-    get index() {
-      assert(this.tile);
-      return this.tile.index;
-    },
-
-    get data() {
-      return this.data_;
-    },
-
-    /**
-     * Clears the DOM hierarchy for this node, setting it back to the default
-     * for a blank thumbnail. TODO(georgey) make it a template.
-     */
-    reset: function() {
-      this.className = 'suggestions filler real';
-      this.innerHTML =
-          '<span class="thumbnail-wrapper fills-parent">' +
-            '<div class="close-button"></div>' +
-            '<span class="thumbnail fills-parent">' +
-              // thumbnail-shield provides a gradient fade effect.
-              '<div class="thumbnail-shield fills-parent"></div>' +
-            '</span>' +
-            '<span class="favicon"></span>' +
-          '</span>' +
-          '<div class="color-stripe"></div>' +
-          '<span class="title"></span>' +
-          '<span class="score"></span>';
-
-      this.querySelector('.close-button').title =
-          loadTimeData.getString('removethumbnailtooltip');
-
-      this.tabIndex = -1;
-      this.data_ = null;
-      this.removeAttribute('id');
-      this.title = '';
-    },
-
-    /**
-     * Update the appearance of this tile according to |data|.
-     * @param {{score: number, url: string, title: string, direction: string,
-     *     filler: boolean}} data A dictionary of relevant data for the page.
-     * @see chrome/browser/ui/webui/ntp/suggestions_source_top_sites.cc
-     * @see chrome/browser/ui/webui/ntp/most_visited_handler.cc
-     */
-    updateForData: function(data) {
-      if (this.classList.contains('blacklisted') && data) {
-        // Animate appearance of new tile.
-        this.classList.add('new-tile-contents');
-      }
-      this.classList.remove('blacklisted');
-
-      if (!data || data.filler) {
-        if (this.data_)
-          this.reset();
-        return;
-      }
-
-      var id = tileID++;
-      this.id = 'suggestions-tile-' + id;
-      this.data_ = data;
-      this.classList.add('focusable');
-
-      var faviconDiv = this.querySelector('.favicon');
-      var faviconUrl = 'chrome://favicon/size/16@1x/' + data.url;
-      faviconDiv.style.backgroundImage = url(faviconUrl);
-      chrome.send('getFaviconDominantColor', [faviconUrl, this.id]);
-
-      var title = this.querySelector('.title');
-      title.textContent = data.title;
-      title.dir = data.direction;
-
-      var score = this.querySelector('.score');
-      score.textContent = data.score;
-
-      // Sets the tooltip.
-      this.title = data.title;
-
-      var thumbnailUrl;
-      thumbnailUrl = data.urlImage ? data.urlImage :
-        'chrome://thumb/' + data.url;
-
-      this.querySelector('.thumbnail').style.backgroundImage =
-          url(thumbnailUrl);
-
-      this.href = data.url;
-
-      this.classList.remove('filler');
-    },
-
-    /**
-     * Sets the color of the favicon dominant color bar.
-     * @param {string} color The css-parsable value for the color.
-     */
-    set stripeColor(color) {
-      this.querySelector('.color-stripe').style.backgroundColor = color;
-    },
-
-    /**
-     * Handles a click on the tile.
-     * @param {Event} e The click event.
-     */
-    handleClick_: function(e) {
-      if (e.target.classList.contains('close-button')) {
-        this.blacklist_();
-        e.preventDefault();
-      } else {
-        // Records the index of this tile.
-        chrome.send('metricsHandler:recordInHistogram',
-                    ['NewTabPage.SuggestedSite', this.index, 8]);
-        chrome.send('suggestedSitesAction',
-                    [ntp.NtpFollowAction.CLICKED_TILE]);
-      }
-    },
-
-    /**
-     * Allow blacklisting suggestions site using the keyboard.
-     * @param {Event} e The keydown event.
-     */
-    handleKeyDown_: function(e) {
-      if (!cr.isMac && e.keyCode == 46 || // Del
-          cr.isMac && e.metaKey && e.keyCode == 8) { // Cmd + Backspace
-        this.blacklist_();
-      }
-    },
-
-    /**
-     * Permanently removes a page from Suggestions.
-     */
-    blacklist_: function() {
-      this.showUndoNotification_();
-      chrome.send('blacklistURLFromSuggestions', [this.data_.url]);
-      this.reset();
-      chrome.send('getSuggestions');
-      this.classList.add('blacklisted');
-    },
-
-    /**
-     * Shows notification that you can undo blacklisting.
-     */
-    showUndoNotification_: function() {
-      var data = this.data_;
-      var self = this;
-      var doUndo = function() {
-        chrome.send('removeURLsFromSuggestionsBlacklist', [data.url]);
-        self.updateForData(data);
-      };
-
-      var undo = {
-        action: doUndo,
-        text: loadTimeData.getString('undothumbnailremove'),
-      };
-
-      var undoAll = {
-        action: function() {
-          chrome.send('clearSuggestionsURLsBlacklist');
-        },
-        text: loadTimeData.getString('restoreThumbnailsShort'),
-      };
-
-      ntp.showNotification(
-          loadTimeData.getString('thumbnailremovednotification'),
-          [undo, undoAll]);
-    },
-
-    /**
-     * Set the size and position of the suggestions tile.
-     * @param {number} size The total size of |this|.
-     * @param {number} x The x-position.
-     * @param {number} y The y-position.
-     */
-    setBounds: function(size, x, y) {
-      this.style.width = size + 'px';
-      this.style.height = heightForWidth(size) + 'px';
-
-      this.style.left = x + 'px';
-      this.style.right = x + 'px';
-      this.style.top = y + 'px';
-    },
-
-    /**
-     * Returns whether this element can be 'removed' from chrome (i.e. whether
-     * the user can drag it onto the trash and expect something to happen).
-     * @return {boolean} True, since suggestions pages can always be
-     *     blacklisted.
-     */
-    canBeRemoved: function() {
-      return true;
-    },
-
-    /**
-     * Removes this element from chrome, i.e. blacklists it.
-     */
-    removeFromChrome: function() {
-      this.blacklist_();
-      this.parentNode.classList.add('finishing-drag');
-    },
-
-    /**
-     * Called when a drag of this tile has ended (after all animations have
-     * finished).
-     */
-    finalizeDrag: function() {
-      this.parentNode.classList.remove('finishing-drag');
-    },
-
-    /**
-     * Called when a drag is starting on the tile. Updates dataTransfer with
-     * data for this tile (for dragging outside of the NTP).
-     * @param {DataTransfer} dataTransfer The drag event data store.
-     */
-    setDragData: function(dataTransfer) {
-      dataTransfer.setData('Text', this.data_.title);
-      dataTransfer.setData('URL', this.data_.url);
-    },
-  };
-
-  var suggestionsPageGridValues = {
-    // The fewest tiles we will show in a row.
-    minColCount: 2,
-    // The suggestions we will show in a row.
-    maxColCount: 4,
-
-    // The smallest a tile can be.
-    minTileWidth: 122,
-    // The biggest a tile can be. 212 (max thumbnail width) + 2.
-    maxTileWidth: 214,
-
-    // The padding between tiles, as a fraction of the tile width.
-    tileSpacingFraction: 1 / 8,
-  };
-  TilePage.initGridValues(suggestionsPageGridValues);
-
-  /**
-   * Calculates the height for a Suggestion tile for a given width. The size
-   * is based on the thumbnail, which should have a 212:132 ratio.
-   * @return {number} The height.
-   */
-  function heightForWidth(width) {
-    // The 2s are for borders, the 36 is for the title and score.
-    return (width - 2) * 132 / 212 + 2 + 36;
-  }
-
-  var THUMBNAIL_COUNT = 8;
-
-  /**
-   * Creates a new SuggestionsPage object.
-   * @constructor
-   * @extends {TilePage}
-   */
-  function SuggestionsPage() {
-    var el = new TilePage(suggestionsPageGridValues);
-    el.__proto__ = SuggestionsPage.prototype;
-    el.initialize();
-
-    return el;
-  }
-
-  SuggestionsPage.prototype = {
-    __proto__: TilePage.prototype,
-
-    initialize: function() {
-      this.classList.add('suggestions-page');
-      this.data_ = null;
-      this.suggestionsTiles_ = this.getElementsByClassName('suggestions real');
-
-      this.addEventListener('carddeselected', this.handleCardDeselected_);
-      this.addEventListener('cardselected', this.handleCardSelected_);
-    },
-
-    /**
-     * Create blank (filler) tiles.
-     * @private
-     */
-    createTiles_: function() {
-      for (var i = 0; i < THUMBNAIL_COUNT; i++) {
-        this.appendTile(new Suggestion(), false);
-      }
-    },
-
-    /**
-     * Update the tiles after a change to |this.data_|.
-     */
-    updateTiles_: function() {
-      for (var i = 0; i < THUMBNAIL_COUNT; i++) {
-        var page = this.data_[i];
-        var tile = this.suggestionsTiles_[i];
-
-        if (i >= this.data_.length)
-          tile.reset();
-        else
-          tile.updateForData(page);
-      }
-    },
-
-    /**
-     * Handles the 'card deselected' event (i.e. the user clicked to another
-     * pane).
-     * @param {Event} e The CardChanged event.
-     */
-    handleCardDeselected_: function(e) {
-      if (!document.documentElement.classList.contains('starting-up')) {
-        chrome.send('suggestedSitesAction',
-                    [ntp.NtpFollowAction.CLICKED_OTHER_NTP_PANE]);
-      }
-    },
-
-    /**
-     * Handles the 'card selected' event (i.e. the user clicked to select the
-     * Suggested pane).
-     * @param {Event} e The CardChanged event.
-     */
-    handleCardSelected_: function(e) {
-      if (!document.documentElement.classList.contains('starting-up'))
-        chrome.send('suggestedSitesSelected');
-    },
-
-    /**
-     * Array of suggestions data objects.
-     * @type {Array}
-     */
-    get data() {
-      return this.data_;
-    },
-    set data(data) {
-      var startTime = Date.now();
-
-      // The first time data is set, create the tiles.
-      if (!this.data_) {
-        this.createTiles_();
-        this.data_ = data.slice(0, THUMBNAIL_COUNT);
-      } else {
-        this.data_ = refreshData(this.data_, data);
-      }
-
-      this.updateTiles_();
-      this.updateFocusableElement();
-      logEvent('suggestions.layout: ' + (Date.now() - startTime));
-    },
-
-    /** @override */
-    shouldAcceptDrag: function(e) {
-      return false;
-    },
-
-    /** @override */
-    heightForWidth: heightForWidth,
-  };
-
-  /**
-   * Executed once the NTP has loaded. Checks if the Suggested pane is
-   * shown or not. If it is shown, the 'suggestedSitesSelected' message is sent
-   * to the C++ code, to record the fact that the user has seen this pane.
-   */
-  SuggestionsPage.onLoaded = function() {
-    if (ntp.getCardSlider() &&
-        ntp.getCardSlider().currentCardValue &&
-        ntp.getCardSlider().currentCardValue.classList
-        .contains('suggestions-page')) {
-      chrome.send('suggestedSitesSelected');
-    }
-  };
-
-  /**
-   * We've gotten additional data for Suggestions page. Update our old data with
-   * the new data. The ordering of the new data is not important, except when a
-   * page is pinned. Thus we try to minimize re-ordering.
-   * @param {Array} oldData The current Suggestions page list.
-   * @param {Array} newData The new Suggestions page list.
-   * @return {Array} The merged page list that should replace the current page
-   * list.
-   */
-  function refreshData(oldData, newData) {
-    oldData = oldData.slice(0, THUMBNAIL_COUNT);
-    newData = newData.slice(0, THUMBNAIL_COUNT);
-
-    // Copy over pinned sites directly.
-    for (var i = 0; i < newData.length; i++) {
-      if (newData[i].pinned) {
-        oldData[i] = newData[i];
-        // Mark the entry as 'updated' so we don't try to update again.
-        oldData[i].updated = true;
-        // Mark the newData page as 'used' so we don't try to re-use it.
-        newData[i].used = true;
-      }
-    }
-
-    // Look through old pages; if they exist in the newData list, keep them
-    // where they are.
-    for (var i = 0; i < oldData.length; i++) {
-      if (!oldData[i] || oldData[i].updated)
-        continue;
-
-      for (var j = 0; j < newData.length; j++) {
-        if (newData[j].used)
-          continue;
-
-        if (newData[j].url == oldData[i].url) {
-          // The background image and other data may have changed.
-          oldData[i] = newData[j];
-          oldData[i].updated = true;
-          newData[j].used = true;
-          break;
-        }
-      }
-    }
-
-    // Look through old pages that haven't been updated yet; replace them.
-    for (var i = 0; i < oldData.length; i++) {
-      if (oldData[i] && oldData[i].updated)
-        continue;
-
-      for (var j = 0; j < newData.length; j++) {
-        if (newData[j].used)
-          continue;
-
-        oldData[i] = newData[j];
-        oldData[i].updated = true;
-        newData[j].used = true;
-        break;
-      }
-
-      if (oldData[i] && !oldData[i].updated)
-        oldData[i] = null;
-    }
-
-    // Clear 'updated' flags so this function will work next time it's called.
-    for (var i = 0; i < THUMBNAIL_COUNT; i++) {
-      if (oldData[i])
-        oldData[i].updated = false;
-    }
-
-    return oldData;
-  }
-
-  return {
-    SuggestionsPage: SuggestionsPage,
-    refreshData: refreshData,
-  };
-});
-
-document.addEventListener('ntpLoaded', ntp.SuggestionsPage.onLoaded);
diff --git a/chrome/browser/resources/suggestions_internals/suggestions_internals.css b/chrome/browser/resources/suggestions_internals/suggestions_internals.css
deleted file mode 100644
index 1996edcd..0000000
--- a/chrome/browser/resources/suggestions_internals/suggestions_internals.css
+++ /dev/null
@@ -1,37 +0,0 @@
-/* Copyright (c) 2012 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. */
-
-.suggestions-debug-table {
-  border: 1px solid grey;
-  margin-bottom: 1.5em;
-}
-
-.suggestions-debug-table th {
-  border: 1px solid grey;
-}
-
-.suggestions-debug-table td {
-  border: 1px solid grey;
-}
-
-p {
-  margin: 0;
-}
-
-.input-section {
-  margin-bottom: 1em;
-}
-
-.boolean-property-true {
-  background-color: rgb(146, 205, 0);
-}
-
-.boolean-property-false {
-  background-color: rgb(205, 74, 0);
-}
-
-.boolean-property-true,
-.boolean-property-false {
-  text-align: center;
-}
diff --git a/chrome/browser/resources/suggestions_internals/suggestions_internals.html b/chrome/browser/resources/suggestions_internals/suggestions_internals.html
deleted file mode 100644
index 8ed75ca..0000000
--- a/chrome/browser/resources/suggestions_internals/suggestions_internals.html
+++ /dev/null
@@ -1,26 +0,0 @@
-<!doctype html>
-<html>
-<head>
-  <meta charset="utf-8">
-  <title>Suggestions Internals</title>
-  <link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
-  <link rel="stylesheet" href="suggestions_internals.css">
-  <script src="chrome://resources/js/cr.js"></script>
-  <script src="chrome://resources/js/util.js"></script>
-  <script src="suggestions_internals.js"></script>
-</head>
-<body>
-  <div class="input-section">
-    <form id="suggestions-form" action="">
-      <p>
-        <input id="refresh-data" type="submit" value="Refresh data">
-      </p>
-      <p>
-        <input id="show-discarded" type="checkbox">
-        <label for="show-discarded">Show discarded items</label>
-      </p>
-    </form>
-  </div>
-  <div id="suggestions-debug-text"></div>
-</body>
-</html>
diff --git a/chrome/browser/resources/suggestions_internals/suggestions_internals.js b/chrome/browser/resources/suggestions_internals/suggestions_internals.js
deleted file mode 100644
index 63a9ace..0000000
--- a/chrome/browser/resources/suggestions_internals/suggestions_internals.js
+++ /dev/null
@@ -1,186 +0,0 @@
-// Copyright (c) 2012 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.
-
-/**
- * Javascript for suggestions_internals.html, served from
- * chrome://suggestions-internals/. This is used to debug suggestions ranking.
- * When loaded, the page will show the current set of suggestions, along with a
- * large set of information (e.g. all the signals that were taken into
- * consideration for deciding which pages were selected to be shown to the user)
- * that will aid in debugging and optimizing the algorithms.
- */
-cr.define('suggestionsInternals', function() {
-  'use strict';
-
-  /**
-   * Register our event handlers.
-   */
-  function initialize() {
-    $('suggestions-form').addEventListener('submit', onRefreshClicked);
-    $('show-discarded').addEventListener('change', refresh);
-    refresh();
-  }
-
-  /**
-   * Called when the 'Refresh' button is clicked. Reloads the suggestions data.
-   */
-  function onRefreshClicked(event) {
-    refresh();
-    event.preventDefault();
-  }
-
-  /**
-   * Reloads the suggestions data by sending a 'getSuggestions' message to
-   * Chrome. The C++ code is then expected to call 'setSuggestions' when there
-   * are suggestions ready.
-   */
-  function refresh() {
-    chrome.send('getSuggestions');
-  }
-
-  /**
-   * A list of columns that we do not want to display.
-   * @type {Array<string>}
-   * @const
-   */
-  var IGNORED_COLUMNS = [
-    'direction'
-  ];
-
-  /**
-   * A list specifying the name of the first columns to be displayed. If
-   * present, they will be displayed in this order, followed by the remaining
-   * columns.
-   * @type {Array<string>}
-   * @const
-   */
-  var PREFERRED_COLUMN_ORDER = [
-    'title',
-    'url',
-    'score'
-  ];
-
-  function setBooleanColumn(column, value) {
-    if (value) {
-      column.innerText = 'Y';
-      column.classList.add('boolean-property-true');
-    } else {
-      column.innerText = 'N';
-      column.classList.add('boolean-property-false');
-    }
-  }
-
-  /**
-   * Called by Chrome code, with a ranked list of suggestions. The columns
-   * to be displayed are calculated automatically from the properties of the
-   * elements in the list, such that all properties have a column.
-   */
-  function setSuggestions(list) {
-    // Build a list of all the columns that will be displayed.
-    var columns = [];
-    list.forEach(function(entry) {
-      for (var column in entry) {
-        if (typeof entry[column] == 'object') {
-          // Expand one level deep
-          for (var subColumn in entry[column]) {
-            var path = column + '.' + subColumn;
-            if (columns.indexOf(path) < 0)
-              columns.push(path);
-          }
-        } else if (columns.indexOf(column) < 0) {
-          columns.push(column);
-        }
-      }
-    });
-
-    // Remove columns that we don't want to display.
-    columns = columns.filter(function(column) {
-      return IGNORED_COLUMNS.indexOf(column) < 0;
-    });
-
-    // Move the preferred columns to the start of the column list.
-    for (var i = PREFERRED_COLUMN_ORDER.length - 1; i >= 0; i--) {
-      var index = columns.indexOf(PREFERRED_COLUMN_ORDER[i]);
-      if (index >= 0)
-        columns.unshift(columns.splice(index, 1)[0]);
-    }
-
-    // Special columns.
-    columns.unshift('favicon');
-    columns.unshift('screenshot');
-    columns.unshift('rank');
-
-    // Erase whatever is currently being displayed.
-    var output = $('suggestions-debug-text');
-    output.innerHTML = '';
-
-    // Create the container table and add the header row.
-    var table = document.createElement('table');
-    table.className = 'suggestions-debug-table';
-    var header = document.createElement('tr');
-    columns.forEach(function(entry) {
-      var column = document.createElement('th');
-      column.innerText = entry;
-      header.appendChild(column);
-    });
-    table.appendChild(header);
-
-    // Add all the suggestions to the table.
-    var rank = 1;
-    list.forEach(function(entry) {
-      var row = document.createElement('tr');
-      columns.forEach(function(columnName) {
-        var column = document.createElement('td');
-        // Expand the path and find the data if it's there.
-        var path = columnName.split('.');
-        var data = entry;
-        for (var i = 0; i < path.length; ++i) {
-          if (data && data.hasOwnProperty(path[i]))
-            data = data[path[i]];
-          else
-            data = undefined;
-        }
-        // Only add the column if the current suggestion has this property
-        // (otherwise, leave the cell empty).
-        if (typeof(data) != 'undefined') {
-          if (typeof(data) == 'boolean') {
-            setBooleanColumn(column, data);
-          } else if (/^https?:\/\/.+$/.test(data)) {
-            // If the text is a URL, make it an anchor element.
-            var anchor = document.createElement('a');
-            anchor.href = data;
-            anchor.innerText = data;
-            column.appendChild(anchor);
-          } else {
-            column.innerText = data;
-          }
-        } else if (columnName == 'rank') {
-          column.innerText = rank++;
-        } else if (columnName == 'screenshot') {
-          var thumbnailUrl = 'chrome://thumb/' + entry.url;
-          var img = document.createElement('img');
-          img.onload = function() { setBooleanColumn(column, true); };
-          img.onerror = function() { setBooleanColumn(column, false); };
-          img.src = thumbnailUrl;
-        } else if (columnName == 'favicon') {
-          var faviconUrl = 'chrome://favicon/size/16@1x/' + entry.url;
-          column.style.backgroundImage = url(faviconUrl);
-          column.style.backgroundRepeat = 'no-repeat';
-          column.style.backgroundPosition = 'center center';
-        }
-        row.appendChild(column);
-      });
-      table.appendChild(row);
-    });
-
-    output.appendChild(table);
-  }
-
-  return {
-    initialize: initialize,
-    setSuggestions: setSuggestions
-  };
-});
-
-document.addEventListener('DOMContentLoaded', suggestionsInternals.initialize);
diff --git a/chrome/browser/safe_browsing/incident_reporting/preference_validation_delegate.cc b/chrome/browser/safe_browsing/incident_reporting/preference_validation_delegate.cc
index 6ac435dc..60b460ad 100644
--- a/chrome/browser/safe_browsing/incident_reporting/preference_validation_delegate.cc
+++ b/chrome/browser/safe_browsing/incident_reporting/preference_validation_delegate.cc
@@ -62,7 +62,7 @@
     incident->set_path(pref_path);
     if (!value ||
         (!value->GetAsString(incident->mutable_atomic_value()) &&
-         !base::JSONWriter::Write(value, incident->mutable_atomic_value()))) {
+         !base::JSONWriter::Write(*value, incident->mutable_atomic_value()))) {
       incident->clear_atomic_value();
     }
     incident->set_value_state(proto_value_state);
diff --git a/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc b/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc
index 472dc51..a11bee0d 100644
--- a/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc
@@ -159,7 +159,7 @@
   // This must be done after calculating |interstitial_reason_| above.
   // Use same prefix for UMA as for Rappor.
   set_metrics_helper(new SecurityInterstitialMetricsHelper(
-      web_contents, request_url(), GetMetricPrefix(), GetMetricPrefix(),
+      web_contents, request_url(), GetMetricPrefix(), GetRapporPrefix(),
       SecurityInterstitialMetricsHelper::REPORT_RAPPOR,
       GetSamplingEventName()));
   metrics_helper()->RecordUserDecision(SecurityInterstitialMetricsHelper::SHOW);
@@ -493,6 +493,20 @@
 }
 
 std::string SafeBrowsingBlockingPage::GetMetricPrefix() const {
+  bool primary_subresource = unsafe_resources_[0].is_subresource;
+  switch (interstitial_reason_) {
+    case SB_REASON_MALWARE:
+      return primary_subresource ? "malware_subresource" : "malware";
+    case SB_REASON_HARMFUL:
+      return primary_subresource ? "harmful_subresource" : "harmful";
+    case SB_REASON_PHISHING:
+      return primary_subresource ? "phishing_subresource" : "phishing";
+  }
+  NOTREACHED();
+  return std::string();
+}
+
+std::string SafeBrowsingBlockingPage::GetRapporPrefix() const {
   switch (interstitial_reason_) {
     case SB_REASON_MALWARE:
       return "malware";
diff --git a/chrome/browser/safe_browsing/safe_browsing_blocking_page.h b/chrome/browser/safe_browsing/safe_browsing_blocking_page.h
index a42b022..80e0642 100644
--- a/chrome/browser/safe_browsing/safe_browsing_blocking_page.h
+++ b/chrome/browser/safe_browsing/safe_browsing_blocking_page.h
@@ -186,6 +186,7 @@
   void PopulatePhishingLoadTimeData(base::DictionaryValue* load_time_data);
 
   std::string GetMetricPrefix() const;
+  std::string GetRapporPrefix() const;
   std::string GetSamplingEventName() const;
 
   DISALLOW_COPY_AND_ASSIGN(SafeBrowsingBlockingPage);
diff --git a/chrome/browser/safe_json_parser_browsertest.cc b/chrome/browser/safe_json_parser_browsertest.cc
index 5d7f5a10..f67e513d 100644
--- a/chrome/browser/safe_json_parser_browsertest.cc
+++ b/chrome/browser/safe_json_parser_browsertest.cc
@@ -19,7 +19,7 @@
     return "(null)";
 
   std::string json;
-  if (!base::JSONWriter::Write(value, &json))
+  if (!base::JSONWriter::Write(*value, &json))
     return "(invalid value)";
 
   return json;
diff --git a/chrome/browser/services/gcm/instance_id/instance_id_profile_service.cc b/chrome/browser/services/gcm/instance_id/instance_id_profile_service.cc
index 47a6f3a0..dc80f36 100644
--- a/chrome/browser/services/gcm/instance_id/instance_id_profile_service.cc
+++ b/chrome/browser/services/gcm/instance_id/instance_id_profile_service.cc
@@ -19,10 +19,12 @@
   if (!gcm::GCMProfileService::IsGCMEnabled(profile))
     return false;
 
-  // Enabled for trunk build.
+  // Enabled only for trunk/canary/dev builds.
   chrome::VersionInfo::Channel channel = chrome::VersionInfo::GetChannel();
-  if (channel == chrome::VersionInfo::CHANNEL_UNKNOWN)
-    return true;
+  if (channel == chrome::VersionInfo::CHANNEL_BETA ||
+      channel == chrome::VersionInfo::CHANNEL_STABLE) {
+    return false;
+  }
 
   return InstanceIDDriver::IsInstanceIDEnabled();
 }
diff --git a/chrome/browser/sessions/tab_loader.cc b/chrome/browser/sessions/tab_loader.cc
index bf1b00a..98226b7 100644
--- a/chrome/browser/sessions/tab_loader.cc
+++ b/chrome/browser/sessions/tab_loader.cc
@@ -117,7 +117,7 @@
     delegate_ = TabLoaderDelegate::Create(this);
     // There is already at least one tab loading (the active tab). As such we
     // only have to start the timeout timer here.
-    StartTimer();
+    StartFirstTimer();
   }
 }
 
@@ -152,6 +152,13 @@
     StartTimer();
 }
 
+void TabLoader::StartFirstTimer() {
+  force_load_timer_.Stop();
+  force_load_timer_.Start(FROM_HERE,
+                          delegate_->GetFirstTabLoadingTimeout(),
+                          this, &TabLoader::ForceLoadTimerFired);
+}
+
 void TabLoader::StartTimer() {
   force_load_timer_.Stop();
   force_load_timer_.Start(FROM_HERE,
diff --git a/chrome/browser/sessions/tab_loader.h b/chrome/browser/sessions/tab_loader.h
index 519d024..d40987d5 100644
--- a/chrome/browser/sessions/tab_loader.h
+++ b/chrome/browser/sessions/tab_loader.h
@@ -68,8 +68,14 @@
   // otherwise |force_load_timer_| is restarted.
   void LoadNextTab();
 
-  // Starts a timer to load load the next tab once expired before the current
-  // tab loading is finished.
+  // Starts |force_load_timer_| to load the first non-visible tab if the timer
+  // expires before a visible tab has finished loading. This uses the same
+  // timer but a different timeout value than StartTimer.
+  void StartFirstTimer();
+
+  // Starts |force_load_timer_| to load the next tab if the timer expires
+  // before the current tab loading is finished. This uses the same timer but a
+  // different timeout value than StartFirstTimer.
   void StartTimer();
 
   // Removes the listeners from the specified tab and removes the tab from
diff --git a/chrome/browser/sessions/tab_loader_delegate.cc b/chrome/browser/sessions/tab_loader_delegate.cc
index 640495e..251096c 100644
--- a/chrome/browser/sessions/tab_loader_delegate.cc
+++ b/chrome/browser/sessions/tab_loader_delegate.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/sessions/tab_loader_delegate.h"
 
+#include "base/strings/string_number_conversions.h"
+#include "components/variations/variations_associated_data.h"
 #include "net/base/network_change_notifier.h"
 
 namespace {
@@ -22,8 +24,13 @@
   ~TabLoaderDelegateImpl() override;
 
   // TabLoaderDelegate:
+  base::TimeDelta GetFirstTabLoadingTimeout() const override {
+    return first_timeout_;
+  }
+
+  // TabLoaderDelegate:
   base::TimeDelta GetTimeoutBeforeLoadingNextTab() const override {
-    return base::TimeDelta::FromMilliseconds(kInitialDelayTimerMS);
+    return timeout_;
   }
 
   // net::NetworkChangeNotifier::ConnectionTypeObserver:
@@ -34,6 +41,10 @@
   // The function to call when the connection type changes.
   TabLoaderCallback* callback_;
 
+  // The timeouts to use in tab loading.
+  base::TimeDelta first_timeout_;
+  base::TimeDelta timeout_;
+
   DISALLOW_COPY_AND_ASSIGN(TabLoaderDelegateImpl);
 };
 
@@ -47,6 +58,28 @@
     // distributes network access, we can remove this.
     callback->SetTabLoadingEnabled(false);
   }
+
+  // Initialize the timeouts to use from the session restore field trial.
+  // Default to the usual value if none is specified.
+
+  static const char kIntelligentSessionRestore[] = "IntelligentSessionRestore";
+  std::string timeout = variations::GetVariationParamValue(
+      kIntelligentSessionRestore, "FirstTabLoadTimeoutMs");
+  int timeout_ms = 0;
+  if (timeout.empty() || !base::StringToInt(timeout, &timeout_ms) ||
+      timeout_ms <= 0) {
+    timeout_ms = kInitialDelayTimerMS;
+  }
+  first_timeout_ = base::TimeDelta::FromMilliseconds(timeout_ms);
+
+  timeout = variations::GetVariationParamValue(
+      kIntelligentSessionRestore, "TabLoadTimeoutMs");
+  timeout_ms = 0;
+  if (timeout.empty() || !base::StringToInt(timeout, &timeout_ms) ||
+      timeout_ms <= 0) {
+    timeout_ms = kInitialDelayTimerMS;
+  }
+  timeout_ = base::TimeDelta::FromMilliseconds(timeout_ms);
 }
 
 TabLoaderDelegateImpl::~TabLoaderDelegateImpl() {
diff --git a/chrome/browser/sessions/tab_loader_delegate.h b/chrome/browser/sessions/tab_loader_delegate.h
index f545354..e396ac5 100644
--- a/chrome/browser/sessions/tab_loader_delegate.h
+++ b/chrome/browser/sessions/tab_loader_delegate.h
@@ -27,8 +27,12 @@
   // The callback object is valid as long as this object exists.
   static scoped_ptr<TabLoaderDelegate> Create(TabLoaderCallback* callback);
 
+  // Returns the default timeout time after which the first non-visible tab
+  // gets loaded if the first (visible) tab did not finish loading.
+  virtual base::TimeDelta GetFirstTabLoadingTimeout() const = 0;
+
   // Returns the default timeout time after which the next tab gets loaded if
-  // the previous tab did not finish to load.
+  // the previous tab did not finish loading.
   virtual base::TimeDelta GetTimeoutBeforeLoadingNextTab() const = 0;
 };
 
diff --git a/chrome/browser/signin/chrome_signin_client.cc b/chrome/browser/signin/chrome_signin_client.cc
index a98dd89..cc4aed9 100644
--- a/chrome/browser/signin/chrome_signin_client.cc
+++ b/chrome/browser/signin/chrome_signin_client.cc
@@ -33,6 +33,7 @@
 
 #if defined(OS_CHROMEOS)
 #include "chrome/browser/chromeos/net/delay_network_call.h"
+#include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "components/user_manager/user_manager.h"
 #endif
 
@@ -40,6 +41,10 @@
 #include "chrome/browser/first_run/first_run.h"
 #endif
 
+namespace {
+const char kEphemeralUserDeviceIDPrefix[] = "t_";
+}
+
 ChromeSigninClient::ChromeSigninClient(
     Profile* profile, SigninErrorController* signin_error_controller)
     : profile_(profile),
@@ -47,6 +52,33 @@
   signin_error_controller_->AddObserver(this);
 #if !defined(OS_CHROMEOS)
   net::NetworkChangeNotifier::AddNetworkChangeObserver(this);
+#else
+  // UserManager may not exist in unit_tests.
+  if (!user_manager::UserManager::IsInitialized())
+    return;
+
+  const user_manager::User* user =
+      chromeos::ProfileHelper::Get()->GetUserByProfile(profile_);
+  if (!user)
+    return;
+  auto* user_manager = user_manager::UserManager::Get();
+  const std::string& user_id = user->GetUserID();
+  if (user_manager->GetKnownUserDeviceId(user_id).empty()) {
+    const std::string legacy_device_id =
+        GetPrefs()->GetString(prefs::kGoogleServicesSigninScopedDeviceId);
+    if (!legacy_device_id.empty()) {
+      // Need to move device ID from the old location to the new one, if it has
+      // not been done yet.
+      user_manager->SetKnownUserDeviceId(user_id, legacy_device_id);
+    } else {
+      user_manager->SetKnownUserDeviceId(
+          user_id,
+          GenerateSigninScopedDeviceID(
+              user_manager->IsUserNonCryptohomeDataEphemeral(user_id)));
+    }
+  }
+  GetPrefs()->SetString(prefs::kGoogleServicesSigninScopedDeviceId,
+                        std::string());
 #endif
 }
 
@@ -77,6 +109,13 @@
          cookie_settings->IsSettingCookieAllowed(google_url, google_url);
 }
 
+// static
+std::string ChromeSigninClient::GenerateSigninScopedDeviceID(
+    bool for_ephemeral) {
+  std::string guid = base::GenerateGUID();
+  return for_ephemeral ? kEphemeralUserDeviceIDPrefix + guid : guid;
+}
+
 PrefService* ChromeSigninClient::GetPrefs() { return profile_->GetPrefs(); }
 
 scoped_refptr<TokenWebData> ChromeSigninClient::GetDatabase() {
@@ -113,16 +152,33 @@
     return std::string();
   }
 
+#if !defined(OS_CHROMEOS)
   std::string signin_scoped_device_id =
       GetPrefs()->GetString(prefs::kGoogleServicesSigninScopedDeviceId);
   if (signin_scoped_device_id.empty()) {
     // If device_id doesn't exist then generate new and save in prefs.
-    signin_scoped_device_id = base::GenerateGUID();
+    signin_scoped_device_id = GenerateSigninScopedDeviceID(false);
     DCHECK(!signin_scoped_device_id.empty());
     GetPrefs()->SetString(prefs::kGoogleServicesSigninScopedDeviceId,
                           signin_scoped_device_id);
   }
   return signin_scoped_device_id;
+#else
+  // UserManager may not exist in unit_tests.
+  if (!user_manager::UserManager::IsInitialized())
+    return std::string();
+
+  const user_manager::User* user =
+      chromeos::ProfileHelper::Get()->GetUserByProfile(profile_);
+  if (!user)
+    return std::string();
+
+  const std::string signin_scoped_device_id =
+      user_manager::UserManager::Get()->GetKnownUserDeviceId(user->GetUserID());
+  LOG_IF(ERROR, signin_scoped_device_id.empty())
+      << "Device ID is not set for user.";
+  return signin_scoped_device_id;
+#endif
 }
 
 void ChromeSigninClient::OnSignedOut() {
diff --git a/chrome/browser/signin/chrome_signin_client.h b/chrome/browser/signin/chrome_signin_client.h
index 016bf5b..34003178 100644
--- a/chrome/browser/signin/chrome_signin_client.h
+++ b/chrome/browser/signin/chrome_signin_client.h
@@ -33,6 +33,10 @@
   static bool ProfileAllowsSigninCookies(Profile* profile);
   static bool SettingsAllowSigninCookies(CookieSettings* cookie_settings);
 
+  // If |for_ephemeral| is true, special kind of device ID for ephemeral users
+  // is generated.
+  static std::string GenerateSigninScopedDeviceID(bool for_ephemeral);
+
   // SigninClient implementation.
   PrefService* GetPrefs() override;
   scoped_refptr<TokenWebData> GetDatabase() override;
diff --git a/chrome/browser/signin/fake_account_tracker_service.cc b/chrome/browser/signin/fake_account_tracker_service.cc
index c592b1a..173acd10 100644
--- a/chrome/browser/signin/fake_account_tracker_service.cc
+++ b/chrome/browser/signin/fake_account_tracker_service.cc
@@ -39,7 +39,8 @@
   user_info.SetString("id", gaia);
   user_info.SetString("email", email);
   user_info.SetString("hd", hosted_domain);
-  SetAccountStateFromUserInfo(account_id, &user_info);
+  std::vector<std::string> service_flags;
+  SetAccountStateFromUserInfo(account_id, &user_info, &service_flags);
 }
 
 void FakeAccountTrackerService::SendRefreshTokenAnnotationRequest(
diff --git a/chrome/browser/speech/chrome_speech_recognition_manager_delegate.cc b/chrome/browser/speech/chrome_speech_recognition_manager_delegate.cc
index 47a8707..dc894638 100644
--- a/chrome/browser/speech/chrome_speech_recognition_manager_delegate.cc
+++ b/chrome/browser/speech/chrome_speech_recognition_manager_delegate.cc
@@ -18,9 +18,6 @@
 #include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
 #include "content/public/browser/browser_thread.h"
-#include "content/public/browser/notification_registrar.h"
-#include "content/public/browser/notification_source.h"
-#include "content/public/browser/notification_types.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/resource_context.h"
@@ -28,6 +25,7 @@
 #include "content/public/browser/speech_recognition_session_config.h"
 #include "content/public/browser/speech_recognition_session_context.h"
 #include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_observer.h"
 #include "content/public/common/speech_recognition_error.h"
 #include "content/public/common/speech_recognition_result.h"
 #include "net/url_request/url_request_context_getter.h"
@@ -137,8 +135,7 @@
 // There is no restriction on the constructor, however this class must be
 // destroyed on the UI thread, due to the NotificationRegistrar dependency.
 class ChromeSpeechRecognitionManagerDelegate::TabWatcher
-    : public base::RefCountedThreadSafe<TabWatcher>,
-      public content::NotificationObserver {
+    : public base::RefCountedThreadSafe<TabWatcher> {
  public:
   typedef base::Callback<void(int render_process_id, int render_view_id)>
       TabClosedCallback;
@@ -168,96 +165,91 @@
     if (!web_contents)
       return;
 
-    // Avoid multiple registrations on |registrar_| for the same |web_contents|.
+    // Avoid multiple registrations for the same |web_contents|.
     if (FindWebContents(web_contents) !=  registered_web_contents_.end()) {
       return;
     }
-    registered_web_contents_.push_back(
-        WebContentsInfo(web_contents, render_process_id, render_view_id));
-
-    // Lazy initialize the registrar.
-    if (!registrar_.get())
-      registrar_.reset(new content::NotificationRegistrar());
-
-    registrar_->Add(this,
-                    content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED,
-                    content::Source<WebContents>(web_contents));
-    registrar_->Add(this,
-                    content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED,
-                    content::Source<WebContents>(web_contents));
+    registered_web_contents_.push_back(new WebContentsTracker(
+        web_contents, base::Bind(&TabWatcher::OnTabClosed,
+                                 // |this| outlives WebContentsTracker.
+                                 base::Unretained(this), web_contents),
+        render_process_id, render_view_id));
   }
 
-  // content::NotificationObserver implementation.
-  void Observe(int type,
-               const content::NotificationSource& source,
-               const content::NotificationDetails& details) override {
-    DCHECK_CURRENTLY_ON(BrowserThread::UI);
-    DCHECK(type == content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED ||
-           type == content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED);
-
-    WebContents* web_contents = content::Source<WebContents>(source).ptr();
-    std::vector<WebContentsInfo>::iterator iter = FindWebContents(web_contents);
+  void OnTabClosed(content::WebContents* web_contents) {
+    ScopedVector<WebContentsTracker>::iterator iter =
+        FindWebContents(web_contents);
     DCHECK(iter != registered_web_contents_.end());
-    int render_process_id = iter->render_process_id;
-    int render_view_id = iter->render_view_id;
+    int render_process_id = (*iter)->render_process_id();
+    int render_view_id = (*iter)->render_view_id();
     registered_web_contents_.erase(iter);
 
-    registrar_->Remove(this,
-                       content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED,
-                       content::Source<WebContents>(web_contents));
-    registrar_->Remove(this,
-                       content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED,
-                       content::Source<WebContents>(web_contents));
-
     tab_closed_callback_.Run(render_process_id, render_view_id);
   }
 
  private:
-  struct WebContentsInfo {
-    WebContentsInfo(content::WebContents* web_contents,
-                    int render_process_id,
-                    int render_view_id)
-        : web_contents(web_contents),
-          render_process_id(render_process_id),
-          render_view_id(render_view_id) {}
+  class WebContentsTracker : public content::WebContentsObserver {
+   public:
+    WebContentsTracker(content::WebContents* web_contents,
+                       const base::Closure& finished_callback,
+                       int render_process_id,
+                       int render_view_id)
+        : content::WebContentsObserver(web_contents),
+          finished_callback_(finished_callback),
+          render_process_id_(render_process_id),
+          render_view_id_(render_view_id) {}
 
-    ~WebContentsInfo() {}
+    ~WebContentsTracker() override {}
 
-    content::WebContents* web_contents;
-    int render_process_id;
-    int render_view_id;
+    int render_process_id() const { return render_process_id_; }
+    int render_view_id() const { return render_view_id_; }
+
+   private:
+    // content::WebContentsObserver overrides.
+    void WebContentsDestroyed() override {
+      Observe(nullptr);
+      finished_callback_.Run();
+      // NOTE: We are deleted now.
+    }
+    void RenderViewHostChanged(content::RenderViewHost* old_host,
+                               content::RenderViewHost* new_host) override {
+      Observe(nullptr);
+      finished_callback_.Run();
+      // NOTE: We are deleted now.
+    }
+
+    const base::Closure finished_callback_;
+    const int render_process_id_;
+    const int render_view_id_;
   };
 
   friend class base::RefCountedThreadSafe<TabWatcher>;
 
-  ~TabWatcher() override {
+  ~TabWatcher() {
     // Must be destroyed on the UI thread due to |registrar_| non thread-safety.
+    // TODO(lazyboy): Do we still need this?
     DCHECK_CURRENTLY_ON(BrowserThread::UI);
   }
 
   // Helper function to find the iterator in |registered_web_contents_| which
   // contains |web_contents|.
-  std::vector<WebContentsInfo>::iterator FindWebContents(
+  ScopedVector<WebContentsTracker>::iterator FindWebContents(
       content::WebContents* web_contents) {
-    for (std::vector<WebContentsInfo>::iterator i(
-         registered_web_contents_.begin());
+    for (ScopedVector<WebContentsTracker>::iterator i(
+             registered_web_contents_.begin());
          i != registered_web_contents_.end(); ++i) {
-      if (i->web_contents == web_contents)
+      if ((*i)->web_contents() == web_contents)
         return i;
     }
 
     return registered_web_contents_.end();
   }
 
-  // Lazy-initialized and used on the UI thread to handle web contents
-  // notifications (tab closing).
-  scoped_ptr<content::NotificationRegistrar> registrar_;
-
   // Keeps track of which WebContent(s) have been registered, in order to avoid
-  // double registrations on |registrar_| and to pass the correct render
+  // double registrations on WebContentsObserver and to pass the correct render
   // process id and render view id to |tab_closed_callback_| after the process
   // has gone away.
-  std::vector<WebContentsInfo> registered_web_contents_;
+  ScopedVector<WebContentsTracker> registered_web_contents_;
 
   // Callback used to notify, on the thread specified by |callback_thread_| the
   // closure of a registered tab.
diff --git a/chrome/browser/speech/extension_api/tts_engine_extension_api.cc b/chrome/browser/speech/extension_api/tts_engine_extension_api.cc
index bc050e17..7e4071f 100644
--- a/chrome/browser/speech/extension_api/tts_engine_extension_api.cc
+++ b/chrome/browser/speech/extension_api/tts_engine_extension_api.cc
@@ -191,7 +191,7 @@
   args->AppendInteger(utterance->id());
 
   std::string json;
-  base::JSONWriter::Write(args.get(), &json);
+  base::JSONWriter::Write(*args, &json);
 
   scoped_ptr<extensions::Event> event(new extensions::Event(
       tts_engine_events::kOnSpeak, args.Pass()));
diff --git a/chrome/browser/spellchecker/feedback_sender.cc b/chrome/browser/spellchecker/feedback_sender.cc
index 5ed97bb..bce2b810 100644
--- a/chrome/browser/spellchecker/feedback_sender.cc
+++ b/chrome/browser/spellchecker/feedback_sender.cc
@@ -403,7 +403,7 @@
                   country_),
       api_version_));
   std::string feedback;
-  base::JSONWriter::Write(feedback_value.get(), &feedback);
+  base::JSONWriter::Write(*feedback_value, &feedback);
 
   // The tests use this identifier to mock the URL fetcher.
   static const int kUrlFetcherId = 0;
diff --git a/chrome/browser/supervised_user/child_accounts/family_info_fetcher_unittest.cc b/chrome/browser/supervised_user/child_accounts/family_info_fetcher_unittest.cc
index 47f7af4..b855b7d5 100644
--- a/chrome/browser/supervised_user/child_accounts/family_info_fetcher_unittest.cc
+++ b/chrome/browser/supervised_user/child_accounts/family_info_fetcher_unittest.cc
@@ -49,7 +49,7 @@
   family_dict->SetWithoutPathExpansion("profile", profile_dict);
   dict.SetWithoutPathExpansion("family", family_dict);
   std::string result;
-  base::JSONWriter::Write(&dict, &result);
+  base::JSONWriter::Write(dict, &result);
   return result;
 }
 
@@ -58,7 +58,7 @@
   base::DictionaryValue* family_dict = new base::DictionaryValue;
   dict.SetWithoutPathExpansion("family", family_dict);
   std::string result;
-  base::JSONWriter::Write(&dict, &result);
+  base::JSONWriter::Write(dict, &result);
   return result;
 }
 
@@ -97,7 +97,7 @@
   }
   dict.SetWithoutPathExpansion("members", list);
   std::string result;
-  base::JSONWriter::Write(&dict, &result);
+  base::JSONWriter::Write(dict, &result);
   return result;
 }
 
diff --git a/chrome/browser/supervised_user/child_accounts/permission_request_creator_apiary.cc b/chrome/browser/supervised_user/child_accounts/permission_request_creator_apiary.cc
index 0f868f453..e14bbff6 100644
--- a/chrome/browser/supervised_user/child_accounts/permission_request_creator_apiary.cc
+++ b/chrome/browser/supervised_user/child_accounts/permission_request_creator_apiary.cc
@@ -190,7 +190,7 @@
   dict.SetStringWithoutPathExpansion(kStateKey, kState);
 
   std::string body;
-  base::JSONWriter::Write(&dict, &body);
+  base::JSONWriter::Write(dict, &body);
   (*it)->url_fetcher->SetUploadData("application/json", body);
 
   (*it)->url_fetcher->Start();
diff --git a/chrome/browser/supervised_user/child_accounts/permission_request_creator_apiary_unittest.cc b/chrome/browser/supervised_user/child_accounts/permission_request_creator_apiary_unittest.cc
index f78e9afa..b0926117 100644
--- a/chrome/browser/supervised_user/child_accounts/permission_request_creator_apiary_unittest.cc
+++ b/chrome/browser/supervised_user/child_accounts/permission_request_creator_apiary_unittest.cc
@@ -24,7 +24,7 @@
   permission_dict->SetStringWithoutPathExpansion("id", "requestid");
   dict.SetWithoutPathExpansion("permissionRequest", permission_dict);
   std::string result;
-  base::JSONWriter::Write(&dict, &result);
+  base::JSONWriter::Write(dict, &result);
   return result;
 }
 
diff --git a/chrome/browser/supervised_user/experimental/supervised_user_async_url_checker_unittest.cc b/chrome/browser/supervised_user/experimental/supervised_user_async_url_checker_unittest.cc
index 0099af6..bc3dfd1 100644
--- a/chrome/browser/supervised_user/experimental/supervised_user_async_url_checker_unittest.cc
+++ b/chrome/browser/supervised_user/experimental/supervised_user_async_url_checker_unittest.cc
@@ -53,7 +53,7 @@
     dict.SetWithoutPathExpansion("items", results_list);
   }
   std::string result;
-  base::JSONWriter::Write(&dict, &result);
+  base::JSONWriter::Write(dict, &result);
   return result;
 }
 
diff --git a/chrome/browser/supervised_user/legacy/supervised_user_shared_settings_service.cc b/chrome/browser/supervised_user/legacy/supervised_user_shared_settings_service.cc
index 94480d8..17fc6758 100644
--- a/chrome/browser/supervised_user/legacy/supervised_user_shared_settings_service.cc
+++ b/chrome/browser/supervised_user/legacy/supervised_user_shared_settings_service.cc
@@ -174,7 +174,7 @@
     const Value& value,
     bool acknowledged) {
   std::string json_value;
-  base::JSONWriter::Write(&value, &json_value);
+  base::JSONWriter::Write(value, &json_value);
   ::sync_pb::EntitySpecifics specifics;
   specifics.mutable_managed_user_shared_setting()->set_mu_id(su_id);
   specifics.mutable_managed_user_shared_setting()->set_key(key);
diff --git a/chrome/browser/supervised_user/legacy/supervised_user_shared_settings_service_unittest.cc b/chrome/browser/supervised_user/legacy/supervised_user_shared_settings_service_unittest.cc
index eed022ae..ffa3940 100644
--- a/chrome/browser/supervised_user/legacy/supervised_user_shared_settings_service_unittest.cc
+++ b/chrome/browser/supervised_user/legacy/supervised_user_shared_settings_service_unittest.cc
@@ -69,7 +69,7 @@
     return std::string();
 
   std::string json_value;
-  base::JSONWriter::Write(value, &json_value);
+  base::JSONWriter::Write(*value, &json_value);
   return json_value;
 }
 
diff --git a/chrome/browser/supervised_user/supervised_user_settings_service.cc b/chrome/browser/supervised_user/supervised_user_settings_service.cc
index 421a2b4..41b4aa2d 100644
--- a/chrome/browser/supervised_user/supervised_user_settings_service.cc
+++ b/chrome/browser/supervised_user/supervised_user_settings_service.cc
@@ -163,7 +163,7 @@
     const std::string& name,
     const base::Value& value) {
   std::string json_value;
-  base::JSONWriter::Write(&value, &json_value);
+  base::JSONWriter::Write(value, &json_value);
   ::sync_pb::EntitySpecifics specifics;
   specifics.mutable_managed_user_setting()->set_name(name);
   specifics.mutable_managed_user_setting()->set_value(json_value);
diff --git a/chrome/browser/sync/profile_sync_service.cc b/chrome/browser/sync/profile_sync_service.cc
index 2ac3dee..5f0bffdf 100644
--- a/chrome/browser/sync/profile_sync_service.cc
+++ b/chrome/browser/sync/profile_sync_service.cc
@@ -365,6 +365,8 @@
   DCHECK(!running_rollback);
 #endif
 
+  memory_pressure_listener_.reset(new base::MemoryPressureListener(base::Bind(
+      &ProfileSyncService::OnMemoryPressure, weak_factory_.GetWeakPtr())));
   startup_controller_->Reset(GetRegisteredDataTypes());
   startup_controller_->TryStart();
 }
@@ -702,6 +704,8 @@
   InitializeBackend(ShouldDeleteSyncFolder());
 
   UpdateFirstSyncTimePref();
+
+  ReportPreviousSessionMemoryWarningCount();
 }
 
 void ProfileSyncService::OnGetTokenSuccess(
@@ -912,6 +916,9 @@
     UpdateAuthErrorState(GoogleServiceAuthError::AuthErrorNone());
 
   NotifyObservers();
+
+  // Mark this as a clean shutdown(without crash).
+  sync_prefs_.SetCleanShutdown(true);
 }
 
 void ProfileSyncService::DisableForUser() {
@@ -2720,3 +2727,31 @@
         access_token_, cache_guid, birthday);
   }
 }
+
+void ProfileSyncService::OnMemoryPressure(
+    base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) {
+  if (memory_pressure_level ==
+      base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL) {
+    sync_prefs_.SetMemoryPressureWarningCount(
+        sync_prefs_.GetMemoryPressureWarningCount() + 1);
+  }
+}
+
+void ProfileSyncService::ReportPreviousSessionMemoryWarningCount() {
+  int warning_received = sync_prefs_.GetMemoryPressureWarningCount();
+
+  if (-1 != warning_received) {
+    // -1 means it is new client.
+    if (!sync_prefs_.DidSyncShutdownCleanly()) {
+      UMA_HISTOGRAM_COUNTS("Sync.MemoryPressureWarningBeforeUncleanShutdown",
+                           warning_received);
+    } else {
+      UMA_HISTOGRAM_COUNTS("Sync.MemoryPressureWarningBeforeCleanShutdown",
+                           warning_received);
+    }
+  }
+  sync_prefs_.SetMemoryPressureWarningCount(0);
+  // Will set to true during a clean shutdown, so crash or something else will
+  // remain this as false.
+  sync_prefs_.SetCleanShutdown(false);
+}
diff --git a/chrome/browser/sync/profile_sync_service.h b/chrome/browser/sync/profile_sync_service.h
index 1ad2cb7..ff2e2b01 100644
--- a/chrome/browser/sync/profile_sync_service.h
+++ b/chrome/browser/sync/profile_sync_service.h
@@ -14,6 +14,7 @@
 #include "base/files/file_path.h"
 #include "base/gtest_prod_util.h"
 #include "base/location.h"
+#include "base/memory/memory_pressure_listener.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/scoped_vector.h"
 #include "base/memory/weak_ptr.h"
@@ -891,6 +892,13 @@
   // Tell the sync server that this client has disabled sync.
   void RemoveClientFromServer() const;
 
+  // Called when the system is under memory pressure.
+  void OnMemoryPressure(
+      base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level);
+
+  // Check if previous shutdown is shutdown cleanly.
+  void ReportPreviousSessionMemoryWarningCount();
+
   // Factory used to create various dependent objects.
   scoped_ptr<ProfileSyncComponentsFactory> factory_;
 
@@ -1070,6 +1078,9 @@
 
   scoped_ptr<browser_sync::SyncStoppedReporter> sync_stopped_reporter_;
 
+  // Listens for the system being under memory pressure.
+  scoped_ptr<base::MemoryPressureListener> memory_pressure_listener_;
+
   base::WeakPtrFactory<ProfileSyncService> weak_factory_;
 
   // We don't use |weak_factory_| for the StartupController because the weak
diff --git a/chrome/browser/sync/profile_sync_service_android.cc b/chrome/browser/sync/profile_sync_service_android.cc
index 59d44f7..d8e536e 100644
--- a/chrome/browser/sync/profile_sync_service_android.cc
+++ b/chrome/browser/sync/profile_sync_service_android.cc
@@ -441,7 +441,7 @@
   scoped_ptr<base::DictionaryValue> about_info =
       sync_ui_util::ConstructAboutInformation(sync_service_);
   std::string about_info_json;
-  base::JSONWriter::Write(about_info.get(), &about_info_json);
+  base::JSONWriter::Write(*about_info, &about_info_json);
 
   return ConvertUTF8ToJavaString(env, about_info_json);
 }
diff --git a/chrome/browser/sync/profile_sync_service_unittest.cc b/chrome/browser/sync/profile_sync_service_unittest.cc
index cba1633..f4cb23a 100644
--- a/chrome/browser/sync/profile_sync_service_unittest.cc
+++ b/chrome/browser/sync/profile_sync_service_unittest.cc
@@ -659,5 +659,50 @@
   EXPECT_TRUE(ProfileSyncService::IsSyncEnabled());
 }
 
+// Test Sync will stop after receive memory pressure
+TEST_F(ProfileSyncServiceTest, MemoryPressureRecording) {
+  CreateService(browser_sync::AUTO_START);
+  IssueTestTokens();
+  ExpectDataTypeManagerCreation(1);
+  ExpectSyncBackendHostCreation(1);
+  InitializeForNthSync();
+
+  EXPECT_TRUE(service()->SyncActive());
+  EXPECT_FALSE(profile()->GetPrefs()->GetBoolean(
+      sync_driver::prefs::kSyncSuppressStart));
+
+  testing::Mock::VerifyAndClearExpectations(components_factory());
+
+  sync_driver::SyncPrefs sync_prefs(service()->profile()->GetPrefs());
+
+  EXPECT_EQ(profile()->GetPrefs()->GetInteger(
+                sync_driver::prefs::kSyncMemoryPressureWarningCount),
+            0);
+  EXPECT_FALSE(sync_prefs.DidSyncShutdownCleanly());
+
+  // Simulate memory pressure notification.
+  base::MemoryPressureListener::NotifyMemoryPressure(
+      base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
+  base::RunLoop().RunUntilIdle();
+
+  // Verify memory pressure recorded.
+  EXPECT_EQ(profile()->GetPrefs()->GetInteger(
+                sync_driver::prefs::kSyncMemoryPressureWarningCount),
+            1);
+  EXPECT_FALSE(sync_prefs.DidSyncShutdownCleanly());
+
+  // Simulate memory pressure notification.
+  base::MemoryPressureListener::NotifyMemoryPressure(
+      base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
+  base::RunLoop().RunUntilIdle();
+  ShutdownAndDeleteService();
+
+  // Verify memory pressure and shutdown recorded.
+  EXPECT_EQ(profile()->GetPrefs()->GetInteger(
+                sync_driver::prefs::kSyncMemoryPressureWarningCount),
+            2);
+  EXPECT_TRUE(sync_prefs.DidSyncShutdownCleanly());
+}
+
 }  // namespace
 }  // namespace browser_sync
diff --git a/chrome/browser/sync/test/integration/extension_settings_helper.cc b/chrome/browser/sync/test/integration/extension_settings_helper.cc
index 73a88533..e9414af1 100644
--- a/chrome/browser/sync/test/integration/extension_settings_helper.cc
+++ b/chrome/browser/sync/test/integration/extension_settings_helper.cc
@@ -31,9 +31,8 @@
 
 std::string ToJson(const base::Value& value) {
   std::string json;
-  base::JSONWriter::WriteWithOptions(&value,
-                                     base::JSONWriter::OPTIONS_PRETTY_PRINT,
-                                     &json);
+  base::JSONWriter::WriteWithOptions(
+      value, base::JSONWriter::OPTIONS_PRETTY_PRINT, &json);
   return json;
 }
 
diff --git a/chrome/browser/sync/test/integration/profile_sync_service_harness.cc b/chrome/browser/sync/test/integration/profile_sync_service_harness.cc
index bb71e353..fca7be5 100644
--- a/chrome/browser/sync/test/integration/profile_sync_service_harness.cc
+++ b/chrome/browser/sync/test/integration/profile_sync_service_harness.cc
@@ -469,8 +469,7 @@
   scoped_ptr<base::DictionaryValue> value(
       sync_ui_util::ConstructAboutInformation(service()));
   std::string service_status;
-  base::JSONWriter::WriteWithOptions(value.get(),
-                                     base::JSONWriter::OPTIONS_PRETTY_PRINT,
-                                     &service_status);
+  base::JSONWriter::WriteWithOptions(
+      *value, base::JSONWriter::OPTIONS_PRETTY_PRINT, &service_status);
   return service_status;
 }
diff --git a/chrome/browser/task_profiler/task_profiler_data_serializer_unittest.cc b/chrome/browser/task_profiler/task_profiler_data_serializer_unittest.cc
index da040b7..5567eec6 100644
--- a/chrome/browser/task_profiler/task_profiler_data_serializer_unittest.cc
+++ b/chrome/browser/task_profiler/task_profiler_data_serializer_unittest.cc
@@ -26,7 +26,7 @@
       process_data_phase, process_id, process_type, &serialized_value);
 
   std::string serialized_json;
-  base::JSONWriter::Write(&serialized_value, &serialized_json);
+  base::JSONWriter::Write(serialized_value, &serialized_json);
 
   EXPECT_EQ(expected_json, serialized_json);
 }
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index ea7487c9..3a16f27 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -427,8 +427,7 @@
     sources += rebase_path(gypi_values.chrome_browser_ui_media_router_sources,
                            ".",
                            "//chrome")
-    deps += [ "//chrome/browser/media/router:router_core" ]
-    defines += [ "ENABLE_MEDIA_ROUTER=1" ]
+    deps += [ "//chrome/browser/media/router" ]
   }
   if (enable_webrtc) {
     sources += rebase_path(gypi_values.chrome_browser_ui_webrtc_sources,
diff --git a/chrome/browser/ui/android/context_menu_helper.cc b/chrome/browser/ui/android/context_menu_helper.cc
index d41f0c8a..37519e1e 100644
--- a/chrome/browser/ui/android/context_menu_helper.cc
+++ b/chrome/browser/ui/android/context_menu_helper.cc
@@ -6,6 +6,7 @@
 
 #include "base/android/jni_android.h"
 #include "base/android/jni_string.h"
+#include "components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h"
 #include "content/public/browser/android/content_view_core.h"
 #include "content/public/browser/android/download_controller_android.h"
 #include "content/public/common/context_menu_params.h"
@@ -75,6 +76,12 @@
   GURL sanitizedReferrer = (params.frame_url.is_empty() ?
       params.page_url : params.frame_url).GetAsReferrer();
 
+  std::map<std::string, std::string>::const_iterator it =
+      params.properties.find(data_reduction_proxy::chrome_proxy_header());
+  bool image_was_fetched_lo_fi =
+      it != params.properties.end() &&
+      it->second == data_reduction_proxy::chrome_proxy_lo_fi_directive();
+
   JNIEnv* env = base::android::AttachCurrentThread();
   base::android::ScopedJavaLocalRef<jobject> jmenu_info =
       ContextMenuParamsAndroid::Java_ContextMenuParams_create(
@@ -86,6 +93,8 @@
           ConvertUTF8ToJavaString(env, params.unfiltered_link_url.spec()).obj(),
           ConvertUTF8ToJavaString(env, params.src_url.spec()).obj(),
           ConvertUTF16ToJavaString(env, params.selection_text).obj(),
+          ConvertUTF16ToJavaString(env, params.title_text).obj(),
+          image_was_fetched_lo_fi,
           params.is_editable,
           ConvertUTF8ToJavaString(env, sanitizedReferrer.spec()).obj(),
           params.referrer_policy);
diff --git a/chrome/browser/ui/app_list/app_list_service.h b/chrome/browser/ui/app_list/app_list_service.h
index b8dafd3..99fbd65 100644
--- a/chrome/browser/ui/app_list/app_list_service.h
+++ b/chrome/browser/ui/app_list/app_list_service.h
@@ -100,6 +100,10 @@
   // Shows the app list, and switches to the custom launcher page.
   virtual void ShowForCustomLauncherPage(Profile* profile) = 0;
 
+  // Hides the custom launcher page if it is currently being shown. Does nothing
+  // otherwise.
+  virtual void HideCustomLauncherPage() = 0;
+
   // Dismiss the app list.
   virtual void DismissAppList() = 0;
 
diff --git a/chrome/browser/ui/app_list/app_list_service_disabled.cc b/chrome/browser/ui/app_list/app_list_service_disabled.cc
index 31a0cbc1..25293ae 100644
--- a/chrome/browser/ui/app_list/app_list_service_disabled.cc
+++ b/chrome/browser/ui/app_list/app_list_service_disabled.cc
@@ -35,6 +35,7 @@
       Profile* profile,
       const scoped_refptr<content::SpeechRecognitionSessionPreamble>& preamble)
       override {}
+  void HideCustomLauncherPage() override {}
   void ShowForAppInstall(Profile* profile,
                          const std::string& extension_id,
                          bool start_discovery_tracking) override {}
diff --git a/chrome/browser/ui/app_list/app_list_service_mac.h b/chrome/browser/ui/app_list/app_list_service_mac.h
index c97e2d3..f8211ca3 100644
--- a/chrome/browser/ui/app_list/app_list_service_mac.h
+++ b/chrome/browser/ui/app_list/app_list_service_mac.h
@@ -51,6 +51,7 @@
   void Init(Profile* initial_profile) override;
   void DismissAppList() override;
   void ShowForCustomLauncherPage(Profile* profile) override;
+  void HideCustomLauncherPage() override;
   bool IsAppListVisible() const override;
   void EnableAppList(Profile* initial_profile,
                      AppListEnableSource enable_source) override;
diff --git a/chrome/browser/ui/app_list/app_list_service_mac.mm b/chrome/browser/ui/app_list/app_list_service_mac.mm
index f337879..35cdec9 100644
--- a/chrome/browser/ui/app_list/app_list_service_mac.mm
+++ b/chrome/browser/ui/app_list/app_list_service_mac.mm
@@ -425,6 +425,10 @@
   NOTIMPLEMENTED();
 }
 
+void AppListServiceMac::HideCustomLauncherPage() {
+  NOTIMPLEMENTED();
+}
+
 bool AppListServiceMac::IsAppListVisible() const {
   return [GetNativeWindow() isVisible] &&
       ![animation_controller_ isClosing];
diff --git a/chrome/browser/ui/app_list/app_list_service_unittest.cc b/chrome/browser/ui/app_list/app_list_service_unittest.cc
index 812d638..c7d3107 100644
--- a/chrome/browser/ui/app_list/app_list_service_unittest.cc
+++ b/chrome/browser/ui/app_list/app_list_service_unittest.cc
@@ -56,6 +56,7 @@
   }
 
   void ShowForCustomLauncherPage(Profile* profile) override {}
+  void HideCustomLauncherPage() override {}
 
   void DismissAppList() override { showing_for_profile_ = NULL; }
 
diff --git a/chrome/browser/ui/app_list/app_list_service_views.cc b/chrome/browser/ui/app_list/app_list_service_views.cc
index 7f1cd4a..6f1a4b8 100644
--- a/chrome/browser/ui/app_list/app_list_service_views.cc
+++ b/chrome/browser/ui/app_list/app_list_service_views.cc
@@ -49,6 +49,19 @@
                          app_list::AppListModel::STATE_CUSTOM_LAUNCHER_PAGE);
 }
 
+void AppListServiceViews::HideCustomLauncherPage() {
+  if (!shower_.IsAppListVisible())
+    return;
+
+  app_list::ContentsView* contents_view =
+      shower_.app_list()->app_list_main_view()->contents_view();
+
+  if (contents_view->IsStateActive(
+          app_list::AppListModel::STATE_CUSTOM_LAUNCHER_PAGE)) {
+    contents_view->SetActiveState(app_list::AppListModel::STATE_START, true);
+  }
+}
+
 void AppListServiceViews::DismissAppList() {
   if (!can_dismiss_)
     return;
diff --git a/chrome/browser/ui/app_list/app_list_service_views.h b/chrome/browser/ui/app_list/app_list_service_views.h
index 60cd10a..7ba7417 100644
--- a/chrome/browser/ui/app_list/app_list_service_views.h
+++ b/chrome/browser/ui/app_list/app_list_service_views.h
@@ -38,6 +38,7 @@
                          const std::string& extension_id,
                          bool start_discovery_tracking) override;
   void ShowForCustomLauncherPage(Profile* profile) override;
+  void HideCustomLauncherPage() override;
   void DismissAppList() override;
   bool IsAppListVisible() const override;
   gfx::NativeWindow GetAppListWindow() override;
diff --git a/chrome/browser/ui/ash/app_list/app_list_controller_ash.cc b/chrome/browser/ui/ash/app_list/app_list_controller_ash.cc
index ce65a13..969f776 100644
--- a/chrome/browser/ui/ash/app_list/app_list_controller_ash.cc
+++ b/chrome/browser/ui/ash/app_list/app_list_controller_ash.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ui/ash/app_list/app_list_controller_ash.h"
 
+#include "ash/metrics/task_switch_metrics_recorder.h"
 #include "ash/shell.h"
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
 #include "chrome/browser/ui/browser_navigator.h"
@@ -101,6 +102,11 @@
     const extensions::Extension* extension,
     AppListSource source,
     int event_flags) {
+  ash::Shell::GetInstance()
+      ->metrics()
+      ->task_switch_metrics_recorder()
+      .OnTaskSwitch(ash::TaskSwitchMetricsRecorder::kAppList);
+
   // Platform apps treat activations as a launch. The app can decide whether to
   // show a new window or focus an existing window as it sees fit.
   if (extension->is_platform_app()) {
diff --git a/chrome/browser/ui/ash/app_list/app_list_service_ash.cc b/chrome/browser/ui/ash/app_list/app_list_service_ash.cc
index 2fb7881d..d46fe3e 100644
--- a/chrome/browser/ui/ash/app_list/app_list_service_ash.cc
+++ b/chrome/browser/ui/ash/app_list/app_list_service_ash.cc
@@ -91,6 +91,20 @@
   ShowAndSwitchToState(app_list::AppListModel::STATE_CUSTOM_LAUNCHER_PAGE);
 }
 
+void AppListServiceAsh::HideCustomLauncherPage() {
+  app_list::AppListView* app_list_view =
+      ash::Shell::GetInstance()->GetAppListView();
+  if (!app_list_view)
+    return;
+
+  app_list::ContentsView* contents_view =
+      app_list_view->app_list_main_view()->contents_view();
+  if (contents_view->IsStateActive(
+          app_list::AppListModel::STATE_CUSTOM_LAUNCHER_PAGE)) {
+    contents_view->SetActiveState(app_list::AppListModel::STATE_START, true);
+  }
+}
+
 bool AppListServiceAsh::IsAppListVisible() const {
   return ash::Shell::GetInstance()->GetAppListTargetVisibility();
 }
diff --git a/chrome/browser/ui/ash/app_list/app_list_service_ash.h b/chrome/browser/ui/ash/app_list/app_list_service_ash.h
index 6dcc302..62e3ae6 100644
--- a/chrome/browser/ui/ash/app_list/app_list_service_ash.h
+++ b/chrome/browser/ui/ash/app_list/app_list_service_ash.h
@@ -44,6 +44,7 @@
                          const std::string& extension_id,
                          bool start_discovery_tracking) override;
   void ShowForCustomLauncherPage(Profile* profile) override;
+  void HideCustomLauncherPage() override;
   bool IsAppListVisible() const override;
   void DismissAppList() override;
   void EnableAppList(Profile* initial_profile,
diff --git a/chrome/browser/ui/ash/ash_keyboard_controller_proxy.cc b/chrome/browser/ui/ash/ash_keyboard_controller_proxy.cc
index d999706b..0b79244 100644
--- a/chrome/browser/ui/ash/ash_keyboard_controller_proxy.cc
+++ b/chrome/browser/ui/ash/ash_keyboard_controller_proxy.cc
@@ -26,6 +26,7 @@
 #include "ui/aura/window_event_dispatcher.h"
 #include "ui/compositor/scoped_layer_animation_settings.h"
 #include "ui/keyboard/keyboard_controller.h"
+#include "ui/keyboard/keyboard_controller_observer.h"
 
 namespace virtual_keyboard_private =
     extensions::core_api::virtual_keyboard_private;
@@ -69,6 +70,43 @@
   return virtual_keyboard_private::ON_TEXT_INPUT_BOX_FOCUSED_TYPE_NONE;
 }
 
+class AshKeyboardControllerObserver
+    : public keyboard::KeyboardControllerObserver {
+ public:
+  explicit AshKeyboardControllerObserver(content::BrowserContext* context)
+      : context_(context) {}
+  ~AshKeyboardControllerObserver() override {}
+
+  // KeyboardControllerObserver overrides:
+  void OnKeyboardBoundsChanging(const gfx::Rect& bounds) override {
+    extensions::EventRouter* router = extensions::EventRouter::Get(context_);
+
+    if (!router->HasEventListener(
+            virtual_keyboard_private::OnBoundsChanged::kEventName)) {
+      return;
+    }
+
+    scoped_ptr<base::ListValue> event_args(new base::ListValue());
+    scoped_ptr<base::DictionaryValue> new_bounds(new base::DictionaryValue());
+    new_bounds->SetInteger("left", bounds.x());
+    new_bounds->SetInteger("top", bounds.y());
+    new_bounds->SetInteger("width", bounds.width());
+    new_bounds->SetInteger("height", bounds.height());
+    event_args->Append(new_bounds.release());
+
+    scoped_ptr<extensions::Event> event(new extensions::Event(
+        virtual_keyboard_private::OnBoundsChanged::kEventName,
+        event_args.Pass()));
+    event->restrict_to_browser_context = context_;
+    router->BroadcastEvent(event.Pass());
+  }
+
+ private:
+  content::BrowserContext* context_;
+
+  DISALLOW_COPY_AND_ASSIGN(AshKeyboardControllerObserver);
+};
+
 }  // namespace
 
 AshKeyboardControllerProxy::AshKeyboardControllerProxy(
@@ -76,7 +114,9 @@
     : keyboard::KeyboardControllerProxy(context) {
 }
 
-AshKeyboardControllerProxy::~AshKeyboardControllerProxy() {}
+AshKeyboardControllerProxy::~AshKeyboardControllerProxy() {
+  DCHECK(!keyboard_controller_);
+}
 
 void AshKeyboardControllerProxy::OnRequest(
     const ExtensionHostMsg_Request_Params& params) {
@@ -123,6 +163,20 @@
   return NULL;
 }
 
+void AshKeyboardControllerProxy::SetController(
+    keyboard::KeyboardController* controller) {
+  // During KeyboardController destruction, controller can be set to null.
+  if (!controller) {
+    DCHECK(keyboard_controller_);
+    keyboard_controller_->RemoveObserver(observer_.get());
+    keyboard_controller_ = nullptr;
+    return;
+  }
+  keyboard_controller_ = controller;
+  observer_.reset(new AshKeyboardControllerObserver(browser_context()));
+  keyboard_controller_->AddObserver(observer_.get());
+}
+
 content::WebContents*
     AshKeyboardControllerProxy::GetAssociatedWebContents() const {
   return web_contents();
diff --git a/chrome/browser/ui/ash/ash_keyboard_controller_proxy.h b/chrome/browser/ui/ash/ash_keyboard_controller_proxy.h
index 40b4777..64c042ce8 100644
--- a/chrome/browser/ui/ash/ash_keyboard_controller_proxy.h
+++ b/chrome/browser/ui/ash/ash_keyboard_controller_proxy.h
@@ -22,6 +22,10 @@
 namespace gfx {
 class Rect;
 }
+namespace keyboard {
+class KeyboardController;
+class KeyboardControllerObserver;
+}
 namespace ui {
 class InputMethod;
 }
@@ -46,6 +50,7 @@
       const content::MediaStreamRequest& request,
       const content::MediaResponseCallback& callback) override;
   void SetupWebContents(content::WebContents* contents) override;
+  void SetController(keyboard::KeyboardController* controller) override;
   void ShowKeyboardContainer(aura::Window* container) override;
 
   // The overridden implementation dispatches
@@ -65,8 +70,11 @@
   bool OnMessageReceived(const IPC::Message& message) override;
   void RenderViewCreated(content::RenderViewHost* render_view_host) override;
 
+  keyboard::KeyboardController* keyboard_controller_;
+
   scoped_ptr<extensions::ExtensionFunctionDispatcher>
       extension_function_dispatcher_;
+  scoped_ptr<keyboard::KeyboardControllerObserver> observer_;
 
   DISALLOW_COPY_AND_ASSIGN(AshKeyboardControllerProxy);
 };
diff --git a/chrome/browser/ui/ash/cast_config_delegate_chromeos.cc b/chrome/browser/ui/ash/cast_config_delegate_chromeos.cc
new file mode 100644
index 0000000..3f0b87b
--- /dev/null
+++ b/chrome/browser/ui/ash/cast_config_delegate_chromeos.cc
@@ -0,0 +1,155 @@
+// 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/ui/ash/cast_config_delegate_chromeos.h"
+
+#include <string>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/extensions/api/tab_capture/tab_capture_api.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/ui/browser_navigator.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/render_view_host.h"
+#include "extensions/browser/extension_host.h"
+#include "extensions/browser/extension_registry.h"
+#include "extensions/browser/process_manager.h"
+#include "extensions/common/extension.h"
+
+namespace chromeos {
+namespace {
+
+using JavaScriptResultCallback =
+    content::RenderFrameHost::JavaScriptResultCallback;
+
+// Returns the cast extension if it exists.
+const extensions::Extension* FindCastExtension() {
+  // TODO(jdufault): Figure out how to correctly handle multiprofile mode.
+  // See crbug.com/488751
+  Profile* profile = ProfileManager::GetActiveUserProfile();
+  const extensions::ExtensionRegistry* extension_registry =
+      extensions::ExtensionRegistry::Get(profile);
+  const extensions::ExtensionSet& enabled_extensions =
+      extension_registry->enabled_extensions();
+
+  for (size_t i = 0; i < arraysize(extensions::kChromecastExtensionIds); ++i) {
+    const std::string extension_id(extensions::kChromecastExtensionIds[i]);
+    if (enabled_extensions.Contains(extension_id)) {
+      return extension_registry->GetExtensionById(
+          extension_id, extensions::ExtensionRegistry::ENABLED);
+    }
+  }
+  return nullptr;
+}
+
+// Utility method that returns the currently active RenderViewHost.
+content::RenderViewHost* GetRenderViewHost() {
+  const extensions::Extension* extension = FindCastExtension();
+  if (!extension)
+    return nullptr;
+  // TODO(jdufault): Figure out how to correctly handle multiprofile mode.
+  // See crbug.com/488751
+  Profile* profile = ProfileManager::GetActiveUserProfile();
+  if (!profile)
+    return nullptr;
+  extensions::ProcessManager* pm = extensions::ProcessManager::Get(profile);
+  return pm->GetBackgroundHostForExtension(extension->id())->render_view_host();
+}
+
+// Executes JavaScript in the context of the cast extension's background page.
+void ExecuteJavaScript(const std::string& javascript) {
+  auto rvh = GetRenderViewHost();
+  if (!rvh)
+    return;
+  rvh->GetMainFrame()->ExecuteJavaScript(base::UTF8ToUTF16(javascript));
+}
+
+// Executes JavaScript in the context of the cast extension's background page.
+// Invokes |callback| with the return value of the invoked javascript.
+void ExecuteJavaScriptWithCallback(const std::string& javascript,
+                                   const JavaScriptResultCallback& callback) {
+  auto rvh = GetRenderViewHost();
+  if (!rvh)
+    return;
+  rvh->GetMainFrame()->ExecuteJavaScript(base::UTF8ToUTF16(javascript),
+                                         callback);
+}
+
+// Handler for GetReceiversAndActivities.
+void GetReceiversAndActivitiesCallback(
+    const ash::CastConfigDelegate::ReceiversAndActivitesCallback& callback,
+    const base::Value* value) {
+  ash::CastConfigDelegate::ReceiversAndActivites receiver_activites;
+  const base::ListValue* ra_list = nullptr;
+  if (value->GetAsList(&ra_list)) {
+    for (auto i = ra_list->begin(); i != ra_list->end(); ++i) {
+      const base::DictionaryValue* ra_dict = nullptr;
+      if ((*i)->GetAsDictionary(&ra_dict)) {
+        const base::DictionaryValue* receiver_dict(nullptr),
+            *activity_dict(nullptr);
+        ash::CastConfigDelegate::ReceiverAndActivity receiver_activity;
+        if (ra_dict->GetDictionary("receiver", &receiver_dict)) {
+          receiver_dict->GetString("name", &receiver_activity.receiver.name);
+          receiver_dict->GetString("id", &receiver_activity.receiver.id);
+        }
+        if (ra_dict->GetDictionary("activity", &activity_dict) &&
+            !activity_dict->empty()) {
+          activity_dict->GetString("id", &receiver_activity.activity.id);
+          activity_dict->GetString("title", &receiver_activity.activity.title);
+          activity_dict->GetString("activityType",
+                                   &receiver_activity.activity.activity_type);
+          activity_dict->GetBoolean("allowStop",
+                                    &receiver_activity.activity.allow_stop);
+          activity_dict->GetInteger("tabId",
+                                    &receiver_activity.activity.tab_id);
+        }
+        receiver_activites[receiver_activity.receiver.id] = receiver_activity;
+      }
+    }
+  }
+  callback.Run(receiver_activites);
+}
+
+}  // namespace
+
+CastConfigDelegateChromeos::CastConfigDelegateChromeos() {
+}
+
+CastConfigDelegateChromeos::~CastConfigDelegateChromeos() {
+}
+
+bool CastConfigDelegateChromeos::HasCastExtension() const {
+  return FindCastExtension() != nullptr;
+}
+
+void CastConfigDelegateChromeos::GetReceiversAndActivities(
+    const ReceiversAndActivitesCallback& callback) {
+  ExecuteJavaScriptWithCallback(
+      "backgroundSetup.getMirrorCapableReceiversAndActivities();",
+      base::Bind(&GetReceiversAndActivitiesCallback, callback));
+}
+
+void CastConfigDelegateChromeos::CastToReceiver(
+    const std::string& receiver_id) {
+  ExecuteJavaScript("backgroundSetup.launchDesktopMirroring('" + receiver_id +
+                    "');");
+}
+
+void CastConfigDelegateChromeos::StopCasting(const std::string& activity_id) {
+  ExecuteJavaScript("backgroundSetup.stopCastMirroring('user-stop');");
+}
+
+void CastConfigDelegateChromeos::LaunchCastOptions() {
+  chrome::NavigateParams params(
+      ProfileManager::GetActiveUserProfile(),
+      FindCastExtension()->GetResourceURL("options.html"),
+      ui::PAGE_TRANSITION_LINK);
+  params.disposition = NEW_FOREGROUND_TAB;
+  params.window_action = chrome::NavigateParams::SHOW_WINDOW;
+  chrome::Navigate(&params);
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/ui/ash/cast_config_delegate_chromeos.h b/chrome/browser/ui/ash/cast_config_delegate_chromeos.h
new file mode 100644
index 0000000..f0c1b58
--- /dev/null
+++ b/chrome/browser/ui/ash/cast_config_delegate_chromeos.h
@@ -0,0 +1,38 @@
+// 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_UI_ASH_CAST_CONFIG_DELEGATE_CHROMEOS_H_
+#define CHROME_BROWSER_UI_ASH_CAST_CONFIG_DELEGATE_CHROMEOS_H_
+
+#include <string>
+
+#include "ash/cast_config_delegate.h"
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/values.h"
+
+namespace chromeos {
+
+// A class which allows the ash tray to communicate with the cast extension.
+class CastConfigDelegateChromeos : public ash::CastConfigDelegate {
+ public:
+  CastConfigDelegateChromeos();
+
+ private:
+  ~CastConfigDelegateChromeos() override;
+
+  // CastConfigDelegate:
+  bool HasCastExtension() const override;
+  void GetReceiversAndActivities(
+      const ReceiversAndActivitesCallback& callback) override;
+  void CastToReceiver(const std::string& receiver_id) override;
+  void StopCasting(const std::string& activity_id) override;
+  void LaunchCastOptions() override;
+
+  DISALLOW_COPY_AND_ASSIGN(CastConfigDelegateChromeos);
+};
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_UI_ASH_CAST_CONFIG_DELEGATE_CHROMEOS_H_
diff --git a/chrome/browser/ui/ash/chrome_shell_delegate.h b/chrome/browser/ui/ash/chrome_shell_delegate.h
index a467a6e..ae87ac1 100644
--- a/chrome/browser/ui/ash/chrome_shell_delegate.h
+++ b/chrome/browser/ui/ash/chrome_shell_delegate.h
@@ -13,6 +13,7 @@
 #include "base/compiler_specific.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/observer_list.h"
+#include "chrome/browser/ui/ash/metrics/chrome_user_metrics_recorder.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
 
@@ -93,6 +94,9 @@
 
   ObserverList<ash::VirtualKeyboardStateObserver> keyboard_state_observer_list_;
 
+  // Proxies events from chrome/browser to ash::UserMetricsRecorder.
+  scoped_ptr<ChromeUserMetricsRecorder> chrome_user_metrics_recorder_;
+
 #if defined(OS_CHROMEOS)
   scoped_ptr<chromeos::DisplayConfigurationObserver>
       display_configuration_observer_;
diff --git a/chrome/browser/ui/ash/chrome_shell_delegate_chromeos.cc b/chrome/browser/ui/ash/chrome_shell_delegate_chromeos.cc
index 1b617147..7eb8da5b 100644
--- a/chrome/browser/ui/ash/chrome_shell_delegate_chromeos.cc
+++ b/chrome/browser/ui/ash/chrome_shell_delegate_chromeos.cc
@@ -217,10 +217,13 @@
   // in Shell::Init.
   display_configuration_observer_.reset(
       new chromeos::DisplayConfigurationObserver());
+
+  chrome_user_metrics_recorder_.reset(new ChromeUserMetricsRecorder);
 }
 
 void ChromeShellDelegate::PreShutdown() {
   display_configuration_observer_.reset();
+  chrome_user_metrics_recorder_.reset();
 }
 
 ash::SessionStateDelegate* ChromeShellDelegate::CreateSessionStateDelegate() {
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_browser.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_browser.cc
index 26a75a8..be2cbe0 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_browser.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_browser.cc
@@ -6,6 +6,7 @@
 
 #include "ash/wm/window_util.h"
 #include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/ui/ash/multi_user/multi_user_util.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/browser_window.h"
@@ -42,6 +43,10 @@
       TabStripModel* tab_strip = browser_->tab_strip_model();
       tab_strip->CloseAllTabs();
     } else {
+      // In ChromeOS multiprofile scenario we might need to teleport the window
+      // back to the current user desktop.
+      multi_user_util::MoveWindowToCurrentDesktop(
+          browser_->window()->GetNativeWindow());
       browser_->window()->Show();
       ash::wm::ActivateWindow(browser_->window()->GetNativeWindow());
     }
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_tab.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_tab.cc
index b1ce6d6..0c263b8 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_tab.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_tab.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_tab.h"
 
 #include "ash/wm/window_util.h"
+#include "chrome/browser/ui/ash/multi_user/multi_user_util.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/browser_window.h"
@@ -43,6 +44,10 @@
   if (event_flags & (ui::EF_SHIFT_DOWN | ui::EF_MIDDLE_MOUSE_BUTTON)) {
     tab_strip->CloseWebContentsAt(index, TabStripModel::CLOSE_USER_GESTURE);
   } else {
+    // In ChromeOS multiprofile scenario we might need to teleport the window
+    // back to the current user desktop.
+    multi_user_util::MoveWindowToCurrentDesktop(
+        browser->window()->GetNativeWindow());
     tab_strip->ActivateTabAt(index, false);
     browser->window()->Show();
     // Need this check to prevent unit tests from crashing.
diff --git a/chrome/browser/ui/ash/metrics/chrome_user_metrics_recorder.cc b/chrome/browser/ui/ash/metrics/chrome_user_metrics_recorder.cc
new file mode 100644
index 0000000..81e9108
--- /dev/null
+++ b/chrome/browser/ui/ash/metrics/chrome_user_metrics_recorder.cc
@@ -0,0 +1,47 @@
+// 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/ui/ash/metrics/chrome_user_metrics_recorder.h"
+
+#include "ash/metrics/task_switch_metrics_recorder.h"
+#include "ash/metrics/user_metrics_recorder.h"
+#include "ash/shell.h"
+#include "base/logging.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_list.h"
+#include "chrome/browser/ui/host_desktop.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+
+ChromeUserMetricsRecorder::ChromeUserMetricsRecorder() {
+  BrowserList::AddObserver(this);
+}
+
+ChromeUserMetricsRecorder::~ChromeUserMetricsRecorder() {
+  DCHECK(BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH)->empty());
+  BrowserList::RemoveObserver(this);
+}
+
+void ChromeUserMetricsRecorder::OnBrowserAdded(Browser* browser) {
+  browser->tab_strip_model()->AddObserver(this);
+}
+
+void ChromeUserMetricsRecorder::OnBrowserRemoved(Browser* browser) {
+  browser->tab_strip_model()->RemoveObserver(this);
+}
+
+void ChromeUserMetricsRecorder::ActiveTabChanged(
+    content::WebContents* old_contents,
+    content::WebContents* new_contents,
+    int index,
+    int reason) {
+  if (reason & CHANGE_REASON_USER_GESTURE)
+    OnTabSwitchedByUserGesture();
+}
+
+void ChromeUserMetricsRecorder::OnTabSwitchedByUserGesture() {
+  ash::Shell::GetInstance()
+      ->metrics()
+      ->task_switch_metrics_recorder()
+      .OnTaskSwitch(ash::TaskSwitchMetricsRecorder::kTabStrip);
+}
diff --git a/chrome/browser/ui/ash/metrics/chrome_user_metrics_recorder.h b/chrome/browser/ui/ash/metrics/chrome_user_metrics_recorder.h
new file mode 100644
index 0000000..81236e9
--- /dev/null
+++ b/chrome/browser/ui/ash/metrics/chrome_user_metrics_recorder.h
@@ -0,0 +1,40 @@
+// 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_UI_ASH_METRICS_CHROME_USER_METRICS_RECORDER_H_
+#define CHROME_BROWSER_UI_ASH_METRICS_CHROME_USER_METRICS_RECORDER_H_
+
+#include "base/macros.h"
+#include "chrome/browser/ui/browser_list_observer.h"
+#include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
+
+namespace content {
+class WebContents;
+}  // namespace content
+
+// A bridge proxy between chrome/browser events and ash::UserMetricsRecorder.
+class ChromeUserMetricsRecorder : public chrome::BrowserListObserver,
+                                  public TabStripModelObserver {
+ public:
+  ChromeUserMetricsRecorder();
+  ~ChromeUserMetricsRecorder() override;
+
+  // chrome::BroswerListObserver:
+  void OnBrowserAdded(Browser* browser) override;
+  void OnBrowserRemoved(Browser* browser) override;
+
+  // TabStripModelObserver:
+  void ActiveTabChanged(content::WebContents* old_contents,
+                        content::WebContents* new_contents,
+                        int index,
+                        int reason) override;
+
+ private:
+  // Called when a different tab becomes active due to a user gesture.
+  void OnTabSwitchedByUserGesture();
+
+  DISALLOW_COPY_AND_ASSIGN(ChromeUserMetricsRecorder);
+};
+
+#endif  // CHROME_BROWSER_UI_ASH_METRICS_CHROME_USER_METRICS_RECORDER_H_
diff --git a/chrome/browser/ui/ash/system_tray_delegate_chromeos.cc b/chrome/browser/ui/ash/system_tray_delegate_chromeos.cc
index 28c6c48..f4e1284 100644
--- a/chrome/browser/ui/ash/system_tray_delegate_chromeos.cc
+++ b/chrome/browser/ui/ash/system_tray_delegate_chromeos.cc
@@ -71,6 +71,7 @@
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/supervised_user/supervised_user_service.h"
 #include "chrome/browser/supervised_user/supervised_user_service_factory.h"
+#include "chrome/browser/ui/ash/cast_config_delegate_chromeos.h"
 #include "chrome/browser/ui/ash/multi_user/multi_user_util.h"
 #include "chrome/browser/ui/ash/networking_config_delegate_chromeos.h"
 #include "chrome/browser/ui/ash/system_tray_delegate_utils.h"
@@ -195,6 +196,7 @@
       have_session_length_limit_(false),
       should_run_bluetooth_discovery_(false),
       session_started_(false),
+      cast_config_delegate_(new CastConfigDelegateChromeos()),
       networking_config_delegate_(new NetworkingConfigDelegateChromeos()),
       volume_control_delegate_(new VolumeController()),
       device_settings_observer_(CrosSettings::Get()->AddSettingsObserver(
@@ -788,6 +790,11 @@
   LoginDisplayHostImpl::default_host()->OpenProxySettings();
 }
 
+ash::CastConfigDelegate* SystemTrayDelegateChromeOS::GetCastConfigDelegate()
+    const {
+  return cast_config_delegate_.get();
+}
+
 ash::NetworkingConfigDelegate*
 SystemTrayDelegateChromeOS::GetNetworkingConfigDelegate() const {
   return networking_config_delegate_.get();
diff --git a/chrome/browser/ui/ash/system_tray_delegate_chromeos.h b/chrome/browser/ui/ash/system_tray_delegate_chromeos.h
index cf9bcee..cbb48829 100644
--- a/chrome/browser/ui/ash/system_tray_delegate_chromeos.h
+++ b/chrome/browser/ui/ash/system_tray_delegate_chromeos.h
@@ -125,6 +125,7 @@
   bool GetBluetoothEnabled() override;
   bool GetBluetoothDiscovering() override;
   void ChangeProxySettings() override;
+  ash::CastConfigDelegate* GetCastConfigDelegate() const override;
   ash::NetworkingConfigDelegate* GetNetworkingConfigDelegate() const override;
   ash::VolumeControlDelegate* GetVolumeControlDelegate() const override;
   void SetVolumeControlDelegate(
@@ -292,6 +293,7 @@
 
   scoped_refptr<device::BluetoothAdapter> bluetooth_adapter_;
   scoped_ptr<device::BluetoothDiscoverySession> bluetooth_discovery_session_;
+  scoped_ptr<ash::CastConfigDelegate> cast_config_delegate_;
   scoped_ptr<ash::NetworkingConfigDelegate> networking_config_delegate_;
   scoped_ptr<ash::VolumeControlDelegate> volume_control_delegate_;
   scoped_ptr<CrosSettingsObserverSubscription> device_settings_observer_;
diff --git a/chrome/browser/ui/autofill/card_unmask_prompt_controller_impl.cc b/chrome/browser/ui/autofill/card_unmask_prompt_controller_impl.cc
index 6de0858..fadae3a 100644
--- a/chrome/browser/ui/autofill/card_unmask_prompt_controller_impl.cc
+++ b/chrome/browser/ui/autofill/card_unmask_prompt_controller_impl.cc
@@ -48,6 +48,7 @@
   if (card_unmask_view_)
     card_unmask_view_->ControllerGone();
 
+  new_card_link_clicked_ = false;
   shown_timestamp_ = base::Time::Now();
   pending_response_ = CardUnmaskDelegate::UnmaskResponse();
   LoadRiskFingerprint();
diff --git a/chrome/browser/ui/autofill/password_generation_popup_controller_impl.cc b/chrome/browser/ui/autofill/password_generation_popup_controller_impl.cc
index 26a3649..5ee343e6 100644
--- a/chrome/browser/ui/autofill/password_generation_popup_controller_impl.cc
+++ b/chrome/browser/ui/autofill/password_generation_popup_controller_impl.cc
@@ -11,11 +11,13 @@
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversion_utils.h"
 #include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/autofill/password_generation_popup_observer.h"
 #include "chrome/browser/ui/autofill/password_generation_popup_view.h"
 #include "chrome/browser/ui/autofill/popup_constants.h"
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/chrome_pages.h"
+#include "chrome/browser/ui/passwords/password_bubble_experiment.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/grit/chromium_strings.h"
 #include "chrome/grit/generated_resources.h"
@@ -87,15 +89,18 @@
       base::Bind(&PasswordGenerationPopupControllerImpl::HandleKeyPressEvent,
                  base::Unretained(this)));
 
-  std::vector<base::string16> pieces;
-  base::SplitStringDontTrim(
-      l10n_util::GetStringUTF16(IDS_PASSWORD_GENERATION_PROMPT),
-      '|',  // separator
-      &pieces);
-  DCHECK_EQ(3u, pieces.size());
-  link_range_ = gfx::Range(pieces[0].size(),
-                           pieces[0].size() + pieces[1].size());
-  help_text_ = JoinString(pieces, base::string16());
+  int link_id = IDS_MANAGE_PASSWORDS_LINK;
+  int help_text_id = IDS_PASSWORD_GENERATION_PROMPT;
+  if (password_bubble_experiment::IsSmartLockBrandingEnabled(
+          Profile::FromBrowserContext(web_contents->GetBrowserContext()))) {
+    help_text_id = IDS_PASSWORD_GENERATION_SMART_LOCK_PROMPT;
+    link_id = IDS_PASSWORD_MANAGER_SMART_LOCK_FOR_PASSWORDS;
+  }
+
+  base::string16 link = l10n_util::GetStringUTF16(link_id);
+  size_t offset;
+  help_text_ = l10n_util::GetStringFUTF16(help_text_id, link, &offset);
+  link_range_ = gfx::Range(offset, offset + link.length());
 }
 
 PasswordGenerationPopupControllerImpl::~PasswordGenerationPopupControllerImpl()
diff --git a/chrome/browser/ui/blocked_content/popup_blocker_browsertest.cc b/chrome/browser/ui/blocked_content/popup_blocker_browsertest.cc
index 963aa2a..e4264d4 100644
--- a/chrome/browser/ui/blocked_content/popup_blocker_browsertest.cc
+++ b/chrome/browser/ui/blocked_content/popup_blocker_browsertest.cc
@@ -45,6 +45,7 @@
 #include "net/dns/mock_host_resolver.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/events/keycodes/dom/dom_code.h"
 #include "ui/events/keycodes/dom/keycode_converter.h"
 
 using content::WebContents;
@@ -637,35 +638,38 @@
 
 #if defined(OS_MACOSX)
   int modifiers = blink::WebInputEvent::MetaKey;
-  InjectRawKeyEvent(tab, blink::WebInputEvent::RawKeyDown, ui::VKEY_COMMAND,
-                    ui::KeycodeConverter::CodeToNativeKeycode("OSLeft"),
-                    modifiers);
+  InjectRawKeyEvent(
+      tab, blink::WebInputEvent::RawKeyDown, ui::VKEY_COMMAND,
+      ui::KeycodeConverter::DomCodeToNativeKeycode(ui::DomCode::OS_LEFT),
+      modifiers);
 #else
   int modifiers = blink::WebInputEvent::ControlKey;
-  InjectRawKeyEvent(tab, blink::WebInputEvent::RawKeyDown, ui::VKEY_CONTROL,
-                    ui::KeycodeConverter::CodeToNativeKeycode("ControlLeft"),
-                    modifiers);
+  InjectRawKeyEvent(
+      tab, blink::WebInputEvent::RawKeyDown, ui::VKEY_CONTROL,
+      ui::KeycodeConverter::DomCodeToNativeKeycode(ui::DomCode::CONTROL_LEFT),
+      modifiers);
 #endif
 
   InjectRawKeyEvent(tab, blink::WebInputEvent::RawKeyDown, ui::VKEY_RETURN,
-                    ui::KeycodeConverter::CodeToNativeKeycode(NULL), modifiers);
+                    ui::KeycodeConverter::InvalidNativeKeycode(), modifiers);
 
   InjectRawKeyEvent(tab, blink::WebInputEvent::Char, ui::VKEY_RETURN,
-                    ui::KeycodeConverter::CodeToNativeKeycode(NULL), modifiers);
+                    ui::KeycodeConverter::InvalidNativeKeycode(), modifiers);
 
   InjectRawKeyEvent(tab, blink::WebInputEvent::KeyUp, ui::VKEY_RETURN,
-                    ui::KeycodeConverter::CodeToNativeKeycode(NULL), modifiers);
+                    ui::KeycodeConverter::InvalidNativeKeycode(), modifiers);
 
 #if defined(OS_MACOSX)
-  InjectRawKeyEvent(tab, blink::WebInputEvent::KeyUp, ui::VKEY_COMMAND,
-                    ui::KeycodeConverter::CodeToNativeKeycode("OSLeft"),
-                    modifiers);
+  InjectRawKeyEvent(
+      tab, blink::WebInputEvent::KeyUp, ui::VKEY_COMMAND,
+      ui::KeycodeConverter::DomCodeToNativeKeycode(ui::DomCode::OS_LEFT),
+      modifiers);
 #else
-  InjectRawKeyEvent(tab, blink::WebInputEvent::KeyUp, ui::VKEY_CONTROL,
-                    ui::KeycodeConverter::CodeToNativeKeycode("ControlLeft"),
-                    modifiers);
+  InjectRawKeyEvent(
+      tab, blink::WebInputEvent::KeyUp, ui::VKEY_CONTROL,
+      ui::KeycodeConverter::DomCodeToNativeKeycode(ui::DomCode::CONTROL_LEFT),
+      modifiers);
 #endif
-
   wait_for_new_tab.Wait();
 
   ASSERT_EQ(1u, chrome::GetBrowserCount(browser()->profile(),
diff --git a/chrome/browser/ui/cocoa/browser_window_cocoa.mm b/chrome/browser/ui/cocoa/browser_window_cocoa.mm
index 5a70b39..dab05bbc 100644
--- a/chrome/browser/ui/cocoa/browser_window_cocoa.mm
+++ b/chrome/browser/ui/cocoa/browser_window_cocoa.mm
@@ -330,11 +330,13 @@
                                             content::WebContents* new_contents,
                                             int index,
                                             int reason) {
+  [controller_ onActiveTabChanged:old_contents to:new_contents];
   // TODO(pkasting): Perhaps the code in
   // TabStripController::activateTabWithContents should move here?  Or this
   // should call that (instead of TabStripModelObserverBridge doing so)?  It's
   // not obvious to me why Mac doesn't handle tab changes in BrowserWindow the
   // way views and GTK do.
+  // See http://crbug.com/340720 for discussion.
 }
 
 void BrowserWindowCocoa::ZoomChangedForActiveTab(bool can_show_bubble) {
diff --git a/chrome/browser/ui/cocoa/browser_window_controller.h b/chrome/browser/ui/cocoa/browser_window_controller.h
index b9676e1..1597b0f 100644
--- a/chrome/browser/ui/cocoa/browser_window_controller.h
+++ b/chrome/browser/ui/cocoa/browser_window_controller.h
@@ -253,6 +253,11 @@
 // Sets whether or not the current page is translated.
 - (void)setCurrentPageIsTranslated:(BOOL)on;
 
+// Invoked via BrowserWindowCocoa::OnActiveTabChanged, happens whenever a
+// new tab becomes active.
+- (void)onActiveTabChanged:(content::WebContents*)oldContents
+                        to:(content::WebContents*)newContents;
+
 // Happens when the zoom level is changed in the active tab, the active tab is
 // changed, or a new browser window or tab is created. |canShowBubble| denotes
 // whether it would be appropriate to show a zoom bubble or not.
diff --git a/chrome/browser/ui/cocoa/browser_window_controller.mm b/chrome/browser/ui/cocoa/browser_window_controller.mm
index b176b64..b33ec48 100644
--- a/chrome/browser/ui/cocoa/browser_window_controller.mm
+++ b/chrome/browser/ui/cocoa/browser_window_controller.mm
@@ -395,9 +395,6 @@
     // Create the bridge for the status bubble.
     statusBubble_ = new StatusBubbleMac([self window], self);
 
-    // Create the permissions bubble.
-    permissionBubbleCocoa_.reset(new PermissionBubbleCocoa([self window]));
-
     // Register for application hide/unhide notifications.
     [[NSNotificationCenter defaultCenter]
          addObserver:self
@@ -1269,6 +1266,26 @@
   [toolbarController_ setTranslateIconLit:on];
 }
 
+- (void)onActiveTabChanged:(content::WebContents*)oldContents
+                        to:(content::WebContents*)newContents {
+  // No need to remove previous bubble. It will close itself.
+  PermissionBubbleManager* manager(nullptr);
+  if (oldContents) {
+    manager = PermissionBubbleManager::FromWebContents(oldContents);
+    if (manager)
+      manager->SetView(nullptr);
+  }
+
+  if (newContents) {
+    if (!permissionBubbleCocoa_.get()) {
+      permissionBubbleCocoa_.reset(new PermissionBubbleCocoa([self window]));
+    }
+    manager = PermissionBubbleManager::FromWebContents(newContents);
+    if (manager)
+      manager->SetView(permissionBubbleCocoa_.get());
+  }
+}
+
 - (void)zoomChangedForActiveTab:(BOOL)canShowBubble {
   [toolbarController_ zoomChangedForActiveTab:canShowBubble];
 }
@@ -1651,14 +1668,6 @@
 
   [infoBarContainerController_ changeWebContents:contents];
 
-  // No need to remove previous bubble. It will close itself.
-  // TODO(leng):  The PermissionBubbleManager for the previous contents should
-  // have SetView(NULL) called.  Fix this when the previous contents are
-  // available here or move to BrowserWindowCocoa::OnActiveTabChanged().
-  // crbug.com/340720
-  PermissionBubbleManager::FromWebContents(contents)->SetView(
-      permissionBubbleCocoa_.get());
-
   // Must do this after bookmark and infobar updates to avoid
   // unnecesary resize in contents.
   [devToolsController_ updateDevToolsForWebContents:contents
diff --git a/chrome/browser/ui/cocoa/download/download_item_button.h b/chrome/browser/ui/cocoa/download/download_item_button.h
index e012491..33646d7 100644
--- a/chrome/browser/ui/cocoa/download/download_item_button.h
+++ b/chrome/browser/ui/cocoa/download/download_item_button.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 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.
 
@@ -17,11 +17,15 @@
  @private
   base::FilePath downloadPath_;
   DownloadItemController* controller_;  // weak
+  base::scoped_nsobject<NSMenu> contextMenu_;
 }
 
 @property(assign, nonatomic) base::FilePath download;
 @property(assign, nonatomic) DownloadItemController* controller;
 
+// Shows the DownloadItemButton's context menu.
+- (void)showContextMenu;
+
 // Overridden from DraggableButton.
 - (void)beginDrag:(NSEvent*)event;
 
diff --git a/chrome/browser/ui/cocoa/download/download_item_button.mm b/chrome/browser/ui/cocoa/download/download_item_button.mm
index 141976df..b2b6ae9 100644
--- a/chrome/browser/ui/cocoa/download/download_item_button.mm
+++ b/chrome/browser/ui/cocoa/download/download_item_button.mm
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 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.
 
@@ -25,6 +25,18 @@
   }
 }
 
+- (void)showContextMenu {
+  base::scoped_nsobject<DownloadShelfContextMenuController> menuController(
+      [[DownloadShelfContextMenuController alloc]
+          initWithItemController:controller_
+                    withDelegate:self]);
+  contextMenu_.reset([[menuController menu] retain]);
+  [NSMenu popUpContextMenu:contextMenu_.get()
+                 withEvent:[NSApp currentEvent]
+                   forView:self];
+  contextMenu_.reset();
+}
+
 // Override to show a context menu on mouse down if clicked over the context
 // menu area.
 - (void)mouseDown:(NSEvent*)event {
@@ -35,15 +47,8 @@
   if ([reinterpret_cast<DownloadItemCell*>(cell) isMouseOverButtonPart]) {
     [self.draggableButton mouseDownImpl:event];
   } else {
-    base::scoped_nsobject<DownloadShelfContextMenuController> menuController(
-        [[DownloadShelfContextMenuController alloc]
-            initWithItemController:controller_
-                      withDelegate:self]);
-
     [cell setHighlighted:YES];
-    [NSMenu popUpContextMenu:[menuController menu]
-                   withEvent:[NSApp currentEvent]
-                     forView:self];
+    [self showContextMenu];
   }
 }
 
@@ -84,4 +89,16 @@
   [self setNeedsDisplay:YES];
 }
 
+- (BOOL)showingContextMenu
+{
+  return contextMenu_.get() != nil;
+}
+
+- (void)viewWillMoveToWindow:(NSWindow *)newWindow {
+  // If the DownloadItemButton's context menu is still visible, dismiss it.
+  if (!newWindow) {
+    [contextMenu_.get() cancelTrackingWithoutAnimation];
+  }
+}
+
 @end
diff --git a/chrome/browser/ui/cocoa/download/download_item_controller.mm b/chrome/browser/ui/cocoa/download/download_item_controller.mm
index 801e739b..7ffaf4e0 100644
--- a/chrome/browser/ui/cocoa/download/download_item_controller.mm
+++ b/chrome/browser/ui/cocoa/download/download_item_controller.mm
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 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.
 
@@ -370,13 +370,7 @@
 }
 
 - (IBAction)showContextMenu:(id)sender {
-  base::scoped_nsobject<DownloadShelfContextMenuController> menuController(
-      [[DownloadShelfContextMenuController alloc]
-        initWithItemController:self
-                  withDelegate:nil]);
-  [NSMenu popUpContextMenu:[menuController menu]
-                 withEvent:[NSApp currentEvent]
-                   forView:[self view]];
+  [progressView_ showContextMenu];
 }
 
 @end
diff --git a/chrome/browser/ui/cocoa/download/download_item_controller_unittest.mm b/chrome/browser/ui/cocoa/download/download_item_controller_unittest.mm
index cf7a98c..b800b99 100644
--- a/chrome/browser/ui/cocoa/download/download_item_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/download/download_item_controller_unittest.mm
@@ -8,6 +8,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/run_loop.h"
 #include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
+#import "chrome/browser/ui/cocoa/download/download_item_button.h"
 #import "chrome/browser/ui/cocoa/download/download_item_controller.h"
 #import "chrome/browser/ui/cocoa/download/download_shelf_controller.h"
 #include "content/public/test/mock_download_item.h"
@@ -44,6 +45,13 @@
 - (void)awakeFromNib;
 @end
 
+@interface DownloadItemButton(DownloadItemButtonTest)
+
+- (BOOL)showingContextMenu;
+
+@end
+
+
 @implementation DownloadItemControllerWithInitCallback
 
 - (id)initWithDownload:(content::DownloadItem*)downloadItem
@@ -179,4 +187,31 @@
   [(id)shelf_ verify];
 }
 
+TEST_F(DownloadItemControllerTest, DismissesContextMenuWhenRemovedFromWindow) {
+  base::scoped_nsobject<DownloadItemController> item(CreateItemController());
+  DownloadItemButton* downloadItemButton = nil;
+  for (NSView *nextSubview in [[item view] subviews]) {
+    if ([nextSubview isKindOfClass:[DownloadItemButton class]]) {
+      downloadItemButton = static_cast<DownloadItemButton *>(nextSubview);
+      break;
+    }
+  }
+
+  // showContextMenu: calls [NSMenu popUpContextMenu:...], which blocks until
+  // the menu is dismissed. Use a block to cancel the menu while waiting for
+  // [NSMenu popUpContextMenu:...] to return (this block will execute on the
+  // main thread, on the next pass through the run loop).
+  [[NSOperationQueue mainQueue] addOperationWithBlock:^{
+    EXPECT_TRUE([downloadItemButton showingContextMenu]);
+    // Simulate the item's removal from the shelf. Ideally we would call an
+    // actual shelf removal method like [item remove] but the shelf and
+    // download item are mock objects.
+    [downloadItemButton removeFromSuperview];
+  }];
+  // The unit test will stop here until the block causes the DownloadItemButton
+  // to dismiss the menu.
+  [item showContextMenu:nil];
+}
+
+
 }  // namespace
diff --git a/chrome/browser/ui/cocoa/download/download_show_all_button.mm b/chrome/browser/ui/cocoa/download/download_show_all_button.mm
index 6a91543..df7ab45 100644
--- a/chrome/browser/ui/cocoa/download/download_show_all_button.mm
+++ b/chrome/browser/ui/cocoa/download/download_show_all_button.mm
@@ -44,7 +44,18 @@
 
 - (void)drawRect:(NSRect)rect {
   NSView* downloadShelfView = [self ancestorWithViewID:VIEW_ID_DOWNLOAD_SHELF];
-  [self cr_drawUsingAncestor:downloadShelfView inRect:rect];
+  // Previously the show all button used cr_drawUsingAncestor:inRect: to use
+  // the download shelf to draw its background. However when the download
+  // shelf has zero height, the shelf's drawing methods don't work as expected
+  // because they constrain their drawing to the shelf's bounds rect. This
+  // situation occurs sometimes when the shelf is about to become visible,
+  // and the result is a very dark show all button
+  //
+  // To work around this problem, we'll call a variant of that method which
+  // does restrict drawing to the ancestor view's bounds.
+  [self cr_drawUsingAncestor:downloadShelfView
+                      inRect:rect
+     clippedToAncestorBounds:NO];
   [super drawRect:rect];
 }
 
diff --git a/chrome/browser/ui/cocoa/extensions/extension_message_bubble_bridge.mm b/chrome/browser/ui/cocoa/extensions/extension_message_bubble_bridge.mm
index cc9832f..137a5f7c 100644
--- a/chrome/browser/ui/cocoa/extensions/extension_message_bubble_bridge.mm
+++ b/chrome/browser/ui/cocoa/extensions/extension_message_bubble_bridge.mm
@@ -34,7 +34,9 @@
 }
 
 base::string16 ExtensionMessageBubbleBridge::GetBodyText() {
-  return controller_->delegate()->GetMessageBody(anchored_to_extension_);
+  return controller_->delegate()->GetMessageBody(
+      anchored_to_extension_,
+      controller_->GetExtensionIdList().size());
 }
 
 base::string16 ExtensionMessageBubbleBridge::GetItemListText() {
diff --git a/chrome/browser/ui/libgtk2ui/gtk2_ui.cc b/chrome/browser/ui/libgtk2ui/gtk2_ui.cc
index 1925e13..29d8e1c3 100644
--- a/chrome/browser/ui/libgtk2ui/gtk2_ui.cc
+++ b/chrome/browser/ui/libgtk2ui/gtk2_ui.cc
@@ -8,6 +8,7 @@
 #include <set>
 
 #include <pango/pango.h>
+#include <X11/Xlib.h>
 
 #include "base/command_line.h"
 #include "base/debug/leak_annotations.h"
@@ -49,6 +50,7 @@
 #include "ui/gfx/image/image.h"
 #include "ui/gfx/skbitmap_operations.h"
 #include "ui/gfx/skia_util.h"
+#include "ui/gfx/x/x11_types.h"
 #include "ui/resources/grit/ui_resources.h"
 #include "ui/views/controls/button/label_button.h"
 #include "ui/views/controls/button/label_button_border.h"
@@ -378,20 +380,27 @@
   return params;
 }
 
-double GetDPI() {
+double GetBaseDPI() {
+  XDisplay* xdisplay = gfx::GetXDisplay();
+  int xscreen = DefaultScreen(xdisplay);
+  return (DisplayHeight(xdisplay, xscreen) * 25.4) /
+         DisplayHeightMM(xdisplay, xscreen);
+}
+
+double GetFontDPI() {
   GtkSettings* gtk_settings = gtk_settings_get_default();
   CHECK(gtk_settings);
   gint gtk_dpi = -1;
   g_object_get(gtk_settings, "gtk-xft-dpi", &gtk_dpi, NULL);
 
   // GTK multiplies the DPI by 1024 before storing it.
-  return (gtk_dpi > 0) ? gtk_dpi / 1024.0 : 96.0;
+  return (gtk_dpi > 0) ? gtk_dpi / 1024.0 : GetBaseDPI();
 }
 
 // Queries GTK for its font DPI setting and returns the number of pixels in a
 // point.
 double GetPixelsInPoint(float device_scale_factor) {
-  double dpi = GetDPI();
+  double dpi = GetFontDPI();
 
   // Take device_scale_factor into account — if Chrome already scales the
   // entire UI up by 2x, we should not also scale up.
@@ -1424,10 +1433,9 @@
 }
 
 float Gtk2UI::GetDeviceScaleFactor() const {
-  const int kCSSDefaultDPI = 96;
-  float scale = GetDPI() / kCSSDefaultDPI;
-  // Round to 2 decimals, e.g. to 1.33.
-  return roundf(scale * 100) / 100;
+  float scale = GetFontDPI() / GetBaseDPI();
+  // Round to 1 decimal, e.g. to 1.4.
+  return roundf(scale * 10) / 10;
 }
 
 }  // namespace libgtk2ui
diff --git a/chrome/browser/ui/panels/panel.cc b/chrome/browser/ui/panels/panel.cc
index 949c612a..7c98b7d6 100644
--- a/chrome/browser/ui/panels/panel.cc
+++ b/chrome/browser/ui/panels/panel.cc
@@ -437,9 +437,6 @@
                     const content::NotificationSource& source,
                     const content::NotificationDetails& details) {
   switch (type) {
-    case content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED:
-      ConfigureAutoResize(content::Source<content::WebContents>(source).ptr());
-      break;
     case chrome::NOTIFICATION_APP_TERMINATING:
       Close();
       break;
@@ -448,6 +445,11 @@
   }
 }
 
+void Panel::RenderViewHostChanged(content::RenderViewHost* old_host,
+                                  content::RenderViewHost* new_host) {
+  ConfigureAutoResize(web_contents());
+}
+
 void Panel::OnExtensionUnloaded(
     content::BrowserContext* browser_context,
     const extensions::Extension* extension,
@@ -593,8 +595,7 @@
       EnableWebContentsAutoResize(web_contents);
   } else {
     if (web_contents) {
-      registrar_.Remove(this, content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED,
-                        content::Source<content::WebContents>(web_contents));
+      content::WebContentsObserver::Observe(nullptr);
 
       // NULL might be returned if the tab has not been added.
       RenderViewHost* render_view_host = web_contents->GetRenderViewHost();
@@ -610,14 +611,7 @@
 
   // We also need to know when the render view host changes in order
   // to turn on auto-resize notifications in the new render view host.
-  if (!registrar_.IsRegistered(
-          this, content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED,
-          content::Source<content::WebContents>(web_contents))) {
-    registrar_.Add(
-        this,
-        content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED,
-        content::Source<content::WebContents>(web_contents));
-  }
+  content::WebContentsObserver::Observe(web_contents);
 }
 
 void Panel::OnContentsAutoResized(const gfx::Size& new_content_size) {
diff --git a/chrome/browser/ui/panels/panel.h b/chrome/browser/ui/panels/panel.h
index fa511d7..877b08c 100644
--- a/chrome/browser/ui/panels/panel.h
+++ b/chrome/browser/ui/panels/panel.h
@@ -17,6 +17,7 @@
 #include "components/sessions/session_id.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
+#include "content/public/browser/web_contents_observer.h"
 #include "extensions/browser/extension_registry_observer.h"
 #include "ui/base/base_window.h"
 #include "ui/gfx/geometry/rect.h"
@@ -53,6 +54,7 @@
 class Panel : public ui::BaseWindow,
               public CommandUpdaterDelegate,
               public content::NotificationObserver,
+              public content::WebContentsObserver,
               public extensions::ExtensionRegistryObserver {
  public:
   enum ExpansionState {
@@ -147,6 +149,10 @@
                const content::NotificationSource& source,
                const content::NotificationDetails& details) override;
 
+  // content::WebContentsObserver overrides.
+  void RenderViewHostChanged(content::RenderViewHost* old_host,
+                             content::RenderViewHost* new_host) override;
+
   //  extensions::ExtensionRegistryObserver.
   void OnExtensionUnloaded(
       content::BrowserContext* browser_context,
diff --git a/chrome/browser/ui/passwords/manage_passwords_bubble_model.cc b/chrome/browser/ui/passwords/manage_passwords_bubble_model.cc
index dd9ed49..2b832256 100644
--- a/chrome/browser/ui/passwords/manage_passwords_bubble_model.cc
+++ b/chrome/browser/ui/passwords/manage_passwords_bubble_model.cc
@@ -13,6 +13,7 @@
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/passwords/manage_passwords_ui_controller.h"
 #include "chrome/browser/ui/passwords/password_bubble_experiment.h"
+#include "chrome/common/url_constants.h"
 #include "chrome/grit/chromium_strings.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/feedback/feedback_data.h"
@@ -118,11 +119,20 @@
 
   if (state_ == password_manager::ui::CONFIRMATION_STATE) {
     base::string16 save_confirmation_link =
-        l10n_util::GetStringUTF16(IDS_MANAGE_PASSWORDS_CONFIRM_GENERATED_LINK);
+        l10n_util::GetStringUTF16(IDS_MANAGE_PASSWORDS_LINK);
+    int confirmation_text_id = IDS_MANAGE_PASSWORDS_CONFIRM_GENERATED_TEXT;
+    if (password_bubble_experiment::IsSmartLockBrandingEnabled(GetProfile())) {
+      std::string management_hostname =
+          GURL(chrome::kPasswordManagerAccountDashboardURL).host();
+      save_confirmation_link = base::UTF8ToUTF16(management_hostname);
+      confirmation_text_id =
+          IDS_MANAGE_PASSWORDS_CONFIRM_GENERATED_SMART_LOCK_TEXT;
+    }
+
     size_t offset;
     save_confirmation_text_ =
-        l10n_util::GetStringFUTF16(IDS_MANAGE_PASSWORDS_CONFIRM_GENERATED_TEXT,
-                                   save_confirmation_link, &offset);
+        l10n_util::GetStringFUTF16(
+            confirmation_text_id, save_confirmation_link, &offset);
     save_confirmation_link_range_ =
         gfx::Range(offset, offset + save_confirmation_link.length());
   }
@@ -239,8 +249,13 @@
 
 void ManagePasswordsBubbleModel::OnManageLinkClicked() {
   dismissal_reason_ = metrics_util::CLICKED_MANAGE;
-  ManagePasswordsUIController::FromWebContents(web_contents())
-      ->NavigateToPasswordManagerSettingsPage();
+  if (password_bubble_experiment::IsSmartLockBrandingEnabled(GetProfile())) {
+    ManagePasswordsUIController::FromWebContents(web_contents())
+        ->NavigateToExternalPasswordManager();
+  } else {
+    ManagePasswordsUIController::FromWebContents(web_contents())
+        ->NavigateToPasswordManagerSettingsPage();
+  }
 }
 
 void ManagePasswordsBubbleModel::OnBrandLinkClicked() {
@@ -313,8 +328,8 @@
   if (never_save_passwords_) {
     title_ = l10n_util::GetStringUTF16(
         IDS_MANAGE_PASSWORDS_BLACKLIST_CONFIRMATION_TITLE);
-  } else if (password_bubble_experiment::IsEnabledSmartLockBranding(
-                 GetProfile())) {
+  } else if (password_bubble_experiment::IsSmartLockBrandingEnabled(
+      GetProfile())) {
     // "Google Smart Lock" should be a hyperlink.
     base::string16 brand_link =
         l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_SMART_LOCK);
diff --git a/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc b/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc
index 4007400..02fa300e 100644
--- a/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc
+++ b/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc
@@ -159,8 +159,7 @@
     UpdateBubbleAndIconVisibility();
 }
 
-void ManagePasswordsUIController::
-    NavigateToPasswordManagerSettingsPage() {
+void ManagePasswordsUIController::NavigateToPasswordManagerSettingsPage() {
 #if defined(OS_ANDROID)
   chrome::android::ChromiumApplication::ShowPasswordSettings();
 #else
@@ -170,6 +169,19 @@
 #endif
 }
 
+void ManagePasswordsUIController::NavigateToExternalPasswordManager() {
+#if defined(OS_ANDROID)
+  NOTREACHED();
+#else
+  chrome::NavigateParams params(
+      chrome::FindBrowserWithWebContents(web_contents()),
+      GURL(chrome::kPasswordManagerAccountDashboardURL),
+      ui::PAGE_TRANSITION_LINK);
+  params.disposition = NEW_FOREGROUND_TAB;
+  chrome::Navigate(&params);
+#endif
+}
+
 void ManagePasswordsUIController::NavigateToSmartLockHelpArticle() {
 #if defined(OS_ANDROID)
   NOTREACHED();
diff --git a/chrome/browser/ui/passwords/manage_passwords_ui_controller.h b/chrome/browser/ui/passwords/manage_passwords_ui_controller.h
index 9abec5c..10debdb 100644
--- a/chrome/browser/ui/passwords/manage_passwords_ui_controller.h
+++ b/chrome/browser/ui/passwords/manage_passwords_ui_controller.h
@@ -104,6 +104,9 @@
   // Open a new tab, pointing to the password manager settings page.
   virtual void NavigateToPasswordManagerSettingsPage();
 
+  // Open a new tab, pointing to passwords.google.com.
+  void NavigateToExternalPasswordManager();
+
   // Open a new tab, pointing to the Smart Lock help article.
   void NavigateToSmartLockHelpArticle();
 
diff --git a/chrome/browser/ui/passwords/password_bubble_experiment.cc b/chrome/browser/ui/passwords/password_bubble_experiment.cc
index 4402e801..aca8198 100644
--- a/chrome/browser/ui/passwords/password_bubble_experiment.cc
+++ b/chrome/browser/ui/passwords/password_bubble_experiment.cc
@@ -12,7 +12,7 @@
 namespace password_bubble_experiment {
 namespace {
 
-const char kBrandingExperimentName[] = "PasswordBubbleBranding";
+const char kBrandingExperimentName[] = "PasswordBranding";
 const char kSmartLockBrandingGroupName[] = "SmartLockBranding";
 
 } // namespace
@@ -23,13 +23,13 @@
   // TODO(vasilii): store the statistics.
 }
 
-bool IsEnabledSmartLockBranding(Profile* profile) {
+bool IsSmartLockBrandingEnabled(Profile* profile) {
   const ProfileSyncService* sync_service =
       ProfileSyncServiceFactory::GetForProfile(profile);
-  return password_manager_util::GetPasswordSyncState(sync_service) &&
+  return password_manager_util::GetPasswordSyncState(sync_service) ==
+             password_manager::SYNCING_NORMAL_ENCRYPTION &&
          base::FieldTrialList::FindFullName(kBrandingExperimentName) ==
              kSmartLockBrandingGroupName;
 }
 
-
 }  // namespace password_bubble_experiment
diff --git a/chrome/browser/ui/passwords/password_bubble_experiment.h b/chrome/browser/ui/passwords/password_bubble_experiment.h
index cf38e82..f20ac7f 100644
--- a/chrome/browser/ui/passwords/password_bubble_experiment.h
+++ b/chrome/browser/ui/passwords/password_bubble_experiment.h
@@ -18,9 +18,9 @@
     PrefService* prefs,
     password_manager::metrics_util::UIDismissalReason reason);
 
-// Returns true if the Save bubble should mention Smart Lock instead of Chrome.
+// Returns true if the password manager should be referred to as Smart Lock.
 // This is only true for signed-in users.
-bool IsEnabledSmartLockBranding(Profile* profile);
+bool IsSmartLockBrandingEnabled(Profile* profile);
 
 }  // namespace password_bubble_experiment
 
diff --git a/chrome/browser/ui/views/extensions/extension_message_bubble_view.cc b/chrome/browser/ui/views/extensions/extension_message_bubble_view.cc
index bc0619f8..2959f9a9 100644
--- a/chrome/browser/ui/views/extensions/extension_message_bubble_view.cc
+++ b/chrome/browser/ui/views/extensions/extension_message_bubble_view.cc
@@ -123,7 +123,8 @@
   message->SetMultiLine(true);
   message->SetHorizontalAlignment(gfx::ALIGN_LEFT);
   message->SetText(delegate->GetMessageBody(
-      anchor_view_->id() == VIEW_ID_BROWSER_ACTION));
+      anchor_view_->id() == VIEW_ID_BROWSER_ACTION,
+      controller_->GetExtensionIdList().size()));
   message->SizeToFit(views::Widget::GetLocalizedContentsWidth(
       IDS_EXTENSION_WIPEOUT_BUBBLE_WIDTH_CHARS));
   layout->AddView(message);
diff --git a/chrome/browser/ui/views/extensions/extension_uninstall_dialog_view.cc b/chrome/browser/ui/views/extensions/extension_uninstall_dialog_view.cc
index d211a53..c402e8b 100644
--- a/chrome/browser/ui/views/extensions/extension_uninstall_dialog_view.cc
+++ b/chrome/browser/ui/views/extensions/extension_uninstall_dialog_view.cc
@@ -69,8 +69,7 @@
  public:
   ExtensionUninstallDialogDelegateView(
       ExtensionUninstallDialogViews* dialog_view,
-      const extensions::Extension* extension,
-      const extensions::Extension* triggering_extension,
+      bool triggered_by_extension,
       gfx::ImageSkia* image);
   ~ExtensionUninstallDialogDelegateView() override;
 
@@ -135,7 +134,7 @@
   }
 
   view_ = new ExtensionUninstallDialogDelegateView(
-      this, extension_, triggering_extension_, &icon_);
+      this, triggering_extension_.get() != nullptr, &icon_);
   constrained_window::CreateBrowserModalDialogViews(view_, parent_)->Show();
 }
 
@@ -162,11 +161,10 @@
 
 ExtensionUninstallDialogDelegateView::ExtensionUninstallDialogDelegateView(
     ExtensionUninstallDialogViews* dialog_view,
-    const extensions::Extension* extension,
-    const extensions::Extension* triggering_extension,
+    bool triggered_by_extension,
     gfx::ImageSkia* image)
     : dialog_(dialog_view),
-      triggered_by_extension_(triggering_extension != NULL),
+      triggered_by_extension_(triggered_by_extension),
       report_abuse_checkbox_(nullptr) {
   // Scale down to icon size, but allow smaller icons (don't scale up).
   gfx::Size size(image->width(), image->height());
diff --git a/chrome/browser/ui/views/frame/system_menu_model_builder.cc b/chrome/browser/ui/views/frame/system_menu_model_builder.cc
index e877f97..0e5d48fb 100644
--- a/chrome/browser/ui/views/frame/system_menu_model_builder.cc
+++ b/chrome/browser/ui/views/frame/system_menu_model_builder.cc
@@ -9,8 +9,10 @@
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/host_desktop.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/toolbar/wrench_menu_model.h"
 #include "chrome/common/chrome_switches.h"
+#include "chrome/common/url_constants.h"
 #include "chrome/grit/generated_resources.h"
 #include "ui/base/accelerators/accelerator.h"
 #include "ui/base/models/simple_menu_model.h"
@@ -25,6 +27,24 @@
 #include "ui/base/l10n/l10n_util.h"
 #endif
 
+namespace {
+
+// Given a |browser| that's an app or popup window, checks if it's hosting the
+// settings page.
+bool IsChromeSettingsAppOrPopupWindow(Browser* browser) {
+  DCHECK(browser);
+  TabStripModel* tab_strip = browser->tab_strip_model();
+  DCHECK_EQ(1, tab_strip->count());
+  const GURL gurl(tab_strip->GetWebContentsAt(0)->GetURL());
+  if (gurl.SchemeIs(content::kChromeUIScheme) &&
+      gurl.host().find(chrome::kChromeUISettingsHost) != std::string::npos) {
+    return true;
+  }
+  return false;
+}
+
+}  // namespace
+
 SystemMenuModelBuilder::SystemMenuModelBuilder(
     ui::AcceleratorProvider* provider,
     Browser* browser)
@@ -108,7 +128,13 @@
   model->AddItemWithStringId(IDC_CLOSE_WINDOW, IDS_CLOSE);
 #endif
 
-  AppendTeleportMenu(model);
+  // Avoid appending the teleport menu for the settings window.  This window's
+  // presentation is unique: it's a normal browser window with an app-like
+  // frame, which doesn't have a user icon badge.  Thus if teleported it's not
+  // clear what user it applies to. Rather than bother to implement badging just
+  // for this rare case, simply prevent the user from teleporting the window.
+  if (!IsChromeSettingsAppOrPopupWindow(browser()))
+    AppendTeleportMenu(model);
 }
 
 void SystemMenuModelBuilder::AddFrameToggleItems(ui::SimpleMenuModel* model) {
diff --git a/chrome/browser/ui/webui/certificate_viewer_webui.cc b/chrome/browser/ui/webui/certificate_viewer_webui.cc
index 8bbbfdca..7f9c668fc 100644
--- a/chrome/browser/ui/webui/certificate_viewer_webui.cc
+++ b/chrome/browser/ui/webui/certificate_viewer_webui.cc
@@ -187,7 +187,7 @@
   // Set the last node as the top of the certificate hierarchy.
   cert_info.Set("hierarchy", children);
 
-  base::JSONWriter::Write(&cert_info, &data);
+  base::JSONWriter::Write(cert_info, &data);
 
   return data;
 }
diff --git a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
index fc43f0d..1ef2156d 100644
--- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
+++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
@@ -96,7 +96,6 @@
 #if !defined(OS_ANDROID)
 #include "chrome/browser/ui/webui/ntp/new_tab_ui.h"
 #include "chrome/browser/ui/webui/quota_internals/quota_internals_ui.h"
-#include "chrome/browser/ui/webui/suggestions_internals/suggestions_internals_ui.h"
 #include "chrome/browser/ui/webui/sync_file_system_internals/sync_file_system_internals_ui.h"
 #include "chrome/browser/ui/webui/system_info_ui.h"
 #include "chrome/browser/ui/webui/uber/uber_ui.h"
@@ -406,8 +405,6 @@
        ::switches::AboutInSettingsEnabled())) {
     return &NewWebUI<options::OptionsUI>;
   }
-  if (url.host() == chrome::kChromeUISuggestionsInternalsHost)
-    return &NewWebUI<SuggestionsInternalsUI>;
   if (url.host() == chrome::kChromeUISyncFileSystemInternalsHost)
     return &NewWebUI<SyncFileSystemInternalsUI>;
   if (url.host() == chrome::kChromeUISystemInfoHost)
diff --git a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
index ce43512..e71da5a 100644
--- a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
@@ -153,8 +153,7 @@
       password_changed(false),
       show_users(false),
       use_offline(false),
-      has_users(false),
-      session_is_ephemeral(false) {
+      has_users(false) {
 }
 
 GaiaScreenHandler::GaiaScreenHandler(
@@ -218,10 +217,6 @@
   params.SetString("email", context.email);
   params.SetBoolean("isEnrollingConsumerManagement",
                     is_enrolling_consumer_management);
-  if (StartupUtils::IsWebviewSigninEnabled()) {
-    params.SetString("deviceId", context.device_id);
-    params.SetBoolean("sessionIsEphemeral", context.session_is_ephemeral);
-  }
 
   UpdateAuthParams(&params,
                    context.has_users,
@@ -338,9 +333,6 @@
 
 void GaiaScreenHandler::UpdateGaia(const GaiaContext& context) {
   base::DictionaryValue params;
-  if (StartupUtils::IsWebviewSigninEnabled()) {
-    params.SetString("deviceId", context.device_id);
-  }
   UpdateAuthParams(&params, context.has_users,
                    context.is_enrolling_consumer_management);
   CallJS("updateAuthExtension", params);
@@ -438,7 +430,6 @@
               &GaiaScreenHandler::HandleToggleWebviewSignin);
   AddCallback("toggleEasyBootstrap",
               &GaiaScreenHandler::HandleToggleEasyBootstrap);
-  AddCallback("attemptLogin", &GaiaScreenHandler::HandleAttemptLogin);
 }
 
 void GaiaScreenHandler::HandleFrameLoadingCompleted(int status) {
@@ -503,8 +494,7 @@
     const std::string& email,
     const std::string& password,
     const std::string& auth_code,
-    bool using_saml,
-    const std::string& device_id) {
+    bool using_saml) {
   if (!Delegate())
     return;
 
@@ -521,7 +511,6 @@
   user_context.SetAuthFlow(using_saml
                                ? UserContext::AUTH_FLOW_GAIA_WITH_SAML
                                : UserContext::AUTH_FLOW_GAIA_WITHOUT_SAML);
-  user_context.SetDeviceId(device_id);
   Delegate()->CompleteLogin(user_context);
 }
 
@@ -601,21 +590,6 @@
   LoadAuthExtension(kForceReload, kSilentLoad, kNoOfflineUI);
 }
 
-void GaiaScreenHandler::HandleAttemptLogin(const std::string& email) {
-  std::string device_id =
-      user_manager::UserManager::Get()->GetKnownUserDeviceId(
-          gaia::CanonicalizeEmail(gaia::SanitizeEmail(email)));
-
-  if (!device_id.empty() && StartupUtils::IsWebviewSigninEnabled()) {
-    base::DictionaryValue params;
-    params.SetString("deviceId", device_id);
-    CallJS("updateDeviceId", params);
-  } else {
-    // Mark current temporary device Id as used.
-    temporary_device_id_ = std::string();
-  }
-}
-
 void GaiaScreenHandler::HandleGaiaUIReady() {
   if (focus_stolen_) {
     // Set focus to the Gaia page.
@@ -958,17 +932,6 @@
     context.has_users = !Delegate()->GetUsers().empty();
   }
 
-  if (!context.email.empty()) {
-    context.device_id = user_manager::UserManager::Get()->GetKnownUserDeviceId(
-        gaia::CanonicalizeEmail(context.email));
-  }
-
-  if (context.device_id.empty())
-    context.device_id = GetTemporaryDeviceId();
-
-  context.session_is_ephemeral =
-      ChromeUserManager::Get()->AreEphemeralUsersEnabled();
-
   populated_email_.clear();
 
   LoadGaia(context);
@@ -988,12 +951,4 @@
   signin_screen_handler_ = handler;
 }
 
-std::string GaiaScreenHandler::GetTemporaryDeviceId() {
-  if (temporary_device_id_.empty())
-    temporary_device_id_ = base::GenerateGUID();
-
-  DCHECK(!temporary_device_id_.empty());
-  return temporary_device_id_;
-}
-
 }  // namespace chromeos
diff --git a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h
index abc6b3d..7a7575c1 100644
--- a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h
@@ -53,14 +53,8 @@
   // GAIA ID of the current user.
   std::string gaia_id;
 
-  // Device Id of the current user.
-  std::string device_id;
-
   // Whether consumer management enrollment is in progress.
   bool is_enrolling_consumer_management;
-
-  // If user session would be ephemeral.
-  bool session_is_ephemeral;
 };
 
 // A class that handles WebUI hooks in Gaia screen.
@@ -121,8 +115,7 @@
                                     const std::string& email,
                                     const std::string& password,
                                     const std::string& auth_code,
-                                    bool using_saml,
-                                    const std::string& device_id);
+                                    bool using_saml);
   void HandleCompleteAuthenticationAuthCodeOnly(const std::string& auth_code);
   void HandleCompleteLogin(const std::string& gaia_id,
                            const std::string& typed_email,
@@ -137,8 +130,6 @@
 
   void HandleToggleEasyBootstrap();
 
-  void HandleAttemptLogin(const std::string& email);
-
   void HandleToggleWebviewSignin();
 
   // This is called when ConsumerManagementService::SetOwner() returns.
@@ -277,10 +268,6 @@
   // GAIA extension loader.
   scoped_ptr<ScopedGaiaAuthExtension> auth_extension_;
 
-  // Temporary DeviceId to be used for new users.
-  // If it's empty, new deviceId should be generated.
-  std::string temporary_device_id_;
-
   base::WeakPtrFactory<GaiaScreenHandler> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(GaiaScreenHandler);
diff --git a/chrome/browser/ui/webui/help/version_updater_win.cc b/chrome/browser/ui/webui/help/version_updater_win.cc
index 2c59ece8..9e47d47e 100644
--- a/chrome/browser/ui/webui/help/version_updater_win.cc
+++ b/chrome/browser/ui/webui/help/version_updater_win.cc
@@ -4,10 +4,11 @@
 
 #include "base/memory/weak_ptr.h"
 #include "base/strings/string16.h"
+#include "base/task_runner_util.h"
 #include "base/win/win_util.h"
 #include "base/win/windows_version.h"
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/first_run/upgrade_util_win.h"
+#include "chrome/browser/first_run/upgrade_util.h"
 #include "chrome/browser/google/google_update_win.h"
 #include "chrome/browser/lifetime/application_lifetime.h"
 #include "chrome/browser/ui/webui/help/version_updater.h"
@@ -49,6 +50,10 @@
   void BeginUpdateCheckOnFileThread(bool install_update_if_possible);
 #endif  // GOOGLE_CHROME_BUILD
 
+  // A task run on the UI thread with the result of checking for a pending
+  // restart.
+  void OnPendingRestartCheck(bool is_update_pending_restart);
+
   // The widget owning the UI for the update check.
   gfx::AcceleratedWidget owner_widget_;
 
@@ -99,7 +104,19 @@
   if (new_version.empty()) {
     // Google Update says that no new version is available. Check to see if a
     // restart is needed for a previously-applied update to take effect.
-    status = upgrade_util::IsRunningOldChrome() ? NEARLY_UPDATED : UPDATED;
+    if (base::PostTaskAndReplyWithResult(
+            content::BrowserThread::GetBlockingPool(),
+            FROM_HERE,
+            base::Bind(&upgrade_util::IsUpdatePendingRestart),
+            base::Bind(&VersionUpdaterWin::OnPendingRestartCheck,
+                       weak_factory_.GetWeakPtr()))) {
+      // Early exit since callback_ will be Run in OnPendingRestartCheck.
+      return;
+    }
+    // Failure to post the task means that Chrome is shutting down. A pending
+    // update (if there is one) will be applied as Chrome exits, so tell the
+    // caller that it is up to date in either case.
+    status = UPDATED;
   } else {
     // Notify the caller that the update is now beginning and initiate it.
     status = UPDATING;
@@ -156,6 +173,11 @@
 }
 #endif  // GOOGLE_CHROME_BUILD
 
+void VersionUpdaterWin::OnPendingRestartCheck(bool is_update_pending_restart) {
+  callback_.Run(is_update_pending_restart ? NEARLY_UPDATED : UPDATED, 0,
+                base::string16());
+}
+
 }  // namespace
 
 VersionUpdater* VersionUpdater::Create(content::WebContents* web_contents) {
diff --git a/chrome/browser/ui/webui/ntp/new_tab_page_handler.cc b/chrome/browser/ui/webui/ntp/new_tab_page_handler.cc
index de548df..d908496 100644
--- a/chrome/browser/ui/webui/ntp/new_tab_page_handler.cc
+++ b/chrome/browser/ui/webui/ntp/new_tab_page_handler.cc
@@ -175,7 +175,6 @@
                                            base::DictionaryValue* values) {
   values->SetInteger("most_visited_page_id", MOST_VISITED_PAGE_ID);
   values->SetInteger("apps_page_id", APPS_PAGE_ID);
-  values->SetInteger("suggestions_page_id", SUGGESTIONS_PAGE_ID);
 
   PrefService* prefs = profile->GetPrefs();
   int shown_page = prefs->GetInteger(prefs::kNtpShownPage);
diff --git a/chrome/browser/ui/webui/ntp/new_tab_page_handler.h b/chrome/browser/ui/webui/ntp/new_tab_page_handler.h
index 7e4e99b..d822354 100644
--- a/chrome/browser/ui/webui/ntp/new_tab_page_handler.h
+++ b/chrome/browser/ui/webui/ntp/new_tab_page_handler.h
@@ -73,9 +73,7 @@
     INDEX_MASK = (1 << kPageIdOffset) - 1,
     MOST_VISITED_PAGE_ID = 1 << kPageIdOffset,
     APPS_PAGE_ID = 2 << kPageIdOffset,
-    BOOKMARKS_PAGE_ID = 3 << kPageIdOffset,
-    SUGGESTIONS_PAGE_ID = 4 << kPageIdOffset,
-    LAST_PAGE_ID = SUGGESTIONS_PAGE_ID
+    LAST_PAGE_ID = APPS_PAGE_ID,
   };
   static const int kHistogramEnumerationMax =
       (LAST_PAGE_ID >> kPageIdOffset) + 1;
diff --git a/chrome/browser/ui/webui/ntp/new_tab_ui.cc b/chrome/browser/ui/webui/ntp/new_tab_ui.cc
index e91fe6b..d43f22f 100644
--- a/chrome/browser/ui/webui/ntp/new_tab_ui.cc
+++ b/chrome/browser/ui/webui/ntp/new_tab_ui.cc
@@ -26,7 +26,6 @@
 #include "chrome/browser/ui/webui/ntp/ntp_resource_cache.h"
 #include "chrome/browser/ui/webui/ntp/ntp_resource_cache_factory.h"
 #include "chrome/browser/ui/webui/ntp/ntp_user_data_logger.h"
-#include "chrome/browser/ui/webui/ntp/suggestions_page_handler.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/grit/generated_resources.h"
@@ -99,8 +98,6 @@
     web_ui->AddMessageHandler(new FaviconWebUIHandler());
     web_ui->AddMessageHandler(new NewTabPageHandler());
     web_ui->AddMessageHandler(new CoreAppLauncherHandler());
-    if (NewTabUI::IsDiscoveryInNTPEnabled())
-      web_ui->AddMessageHandler(new SuggestionsHandler());
     web_ui->AddMessageHandler(new NewTabPageSyncHandler());
 
     ExtensionService* service =
@@ -124,13 +121,6 @@
   scoped_ptr<NewTabHTMLSource> html_source(
       new NewTabHTMLSource(profile->GetOriginalProfile()));
 
-  // These two resources should be loaded only if suggestions NTP is enabled.
-  html_source->AddResource("suggestions_page.css", "text/css",
-      NewTabUI::IsDiscoveryInNTPEnabled() ? IDR_SUGGESTIONS_PAGE_CSS : 0);
-  if (NewTabUI::IsDiscoveryInNTPEnabled()) {
-    html_source->AddResource("suggestions_page.js", "application/javascript",
-        IDR_SUGGESTIONS_PAGE_JS);
-  }
   // content::URLDataSource assumes the ownership of the html_source.
   content::URLDataSource::Add(profile, html_source.release());
 
@@ -224,8 +214,6 @@
     user_prefs::PrefRegistrySyncable* registry) {
   CoreAppLauncherHandler::RegisterProfilePrefs(registry);
   NewTabPageHandler::RegisterProfilePrefs(registry);
-  if (NewTabUI::IsDiscoveryInNTPEnabled())
-    SuggestionsHandler::RegisterProfilePrefs(registry);
   MostVisitedHandler::RegisterProfilePrefs(registry);
   browser_sync::ForeignSessionHandler::RegisterProfilePrefs(registry);
 }
@@ -241,13 +229,6 @@
 }
 
 // static
-bool NewTabUI::IsDiscoveryInNTPEnabled() {
-  // TODO(beaudoin): The flag was removed during a clean-up pass. We leave that
-  // here to easily enable it back when we will explore this option again.
-  return false;
-}
-
-// static
 void NewTabUI::SetUrlTitleAndDirection(base::DictionaryValue* dictionary,
                                        const base::string16& title,
                                        const GURL& gurl) {
diff --git a/chrome/browser/ui/webui/ntp/new_tab_ui.h b/chrome/browser/ui/webui/ntp/new_tab_ui.h
index 4fdee9fe..a6eae7a 100644
--- a/chrome/browser/ui/webui/ntp/new_tab_ui.h
+++ b/chrome/browser/ui/webui/ntp/new_tab_ui.h
@@ -42,9 +42,6 @@
   // Returns whether or not to show apps pages.
   static bool ShouldShowApps();
 
-  // Returns whether or not "Discovery" in the NTP is Enabled.
-  static bool IsDiscoveryInNTPEnabled();
-
   // Adds "url", "title", and "direction" keys on incoming dictionary, setting
   // title as the url as a fallback on empty title.
   static void SetUrlTitleAndDirection(base::DictionaryValue* dictionary,
diff --git a/chrome/browser/ui/webui/ntp/ntp_resource_cache.cc b/chrome/browser/ui/webui/ntp/ntp_resource_cache.cc
index 22cfbe9..73f49e1 100644
--- a/chrome/browser/ui/webui/ntp/ntp_resource_cache.cc
+++ b/chrome/browser/ui/webui/ntp/ntp_resource_cache.cc
@@ -421,8 +421,6 @@
       l10n_util::GetStringUTF16(IDS_NEW_TAB_TITLE));
   load_time_data.SetString("mostvisited",
       l10n_util::GetStringUTF16(IDS_NEW_TAB_MOST_VISITED));
-  load_time_data.SetString("suggestions",
-      l10n_util::GetStringUTF16(IDS_NEW_TAB_SUGGESTIONS));
   load_time_data.SetString("restoreThumbnailsShort",
       l10n_util::GetStringUTF16(IDS_NEW_TAB_RESTORE_THUMBNAILS_SHORT_LINK));
   load_time_data.SetString("webStoreTitle",
@@ -477,8 +475,6 @@
           GURL(extension_urls::GetWebstoreLaunchURL()), app_locale).spec());
   load_time_data.SetString("appInstallHintText",
       l10n_util::GetStringUTF16(IDS_NEW_TAB_APP_INSTALL_HINT_LABEL));
-  load_time_data.SetBoolean("isDiscoveryInNTPEnabled",
-      NewTabUI::IsDiscoveryInNTPEnabled());
   load_time_data.SetString("collapseSessionMenuItemText",
       l10n_util::GetStringUTF16(IDS_NEW_TAB_OTHER_SESSIONS_COLLAPSE_SESSION));
   load_time_data.SetString("expandSessionMenuItemText",
diff --git a/chrome/browser/ui/webui/ntp/suggestions_combiner.cc b/chrome/browser/ui/webui/ntp/suggestions_combiner.cc
deleted file mode 100644
index bf99814..0000000
--- a/chrome/browser/ui/webui/ntp/suggestions_combiner.cc
+++ /dev/null
@@ -1,152 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/webui/ntp/suggestions_combiner.h"
-
-#include <algorithm>
-
-#include "base/values.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_iterator.h"
-#include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chrome/browser/ui/webui/ntp/suggestions_page_handler.h"
-#include "chrome/browser/ui/webui/ntp/suggestions_source.h"
-#include "content/public/browser/web_contents.h"
-
-namespace {
-
-static const size_t kSuggestionsCount = 8;
-
-}  // namespace
-
-SuggestionsCombiner::SuggestionsCombiner(
-    SuggestionsCombiner::Delegate* delegate,
-    Profile* profile)
-    : sources_fetching_count_(0),
-      delegate_(delegate),
-      suggestions_count_(kSuggestionsCount),
-      page_values_(new base::ListValue()),
-      debug_enabled_(false),
-      profile_(profile) {
-}
-
-SuggestionsCombiner::~SuggestionsCombiner() {
-}
-
-void SuggestionsCombiner::AddSource(SuggestionsSource* source) {
-  source->SetCombiner(this);
-  source->SetDebug(debug_enabled_);
-  sources_.push_back(source);
-}
-
-void SuggestionsCombiner::EnableDebug(bool enable) {
-  debug_enabled_ = enable;
-  for (size_t i = 0; i < sources_.size(); ++i) {
-    sources_[i]->SetDebug(enable);
-  }
-}
-
-void SuggestionsCombiner::FetchItems(Profile* profile) {
-  sources_fetching_count_ = sources_.size();
-  for (size_t i = 0; i < sources_.size(); ++i) {
-    sources_[i]->FetchItems(profile);
-  }
-}
-
-base::ListValue* SuggestionsCombiner::GetPageValues() {
-  return page_values_.get();
-}
-
-void SuggestionsCombiner::OnItemsReady() {
-  DCHECK_GT(sources_fetching_count_, 0);
-  sources_fetching_count_--;
-  if (sources_fetching_count_ == 0) {
-    FillPageValues();
-    delegate_->OnSuggestionsReady();
-  }
-}
-
-void SuggestionsCombiner::SetSuggestionsCount(size_t suggestions_count) {
-  suggestions_count_ = suggestions_count;
-}
-
-void SuggestionsCombiner::FillPageValues() {
-  int total_weight = 0;
-  for (size_t i = 0; i < sources_.size(); ++i)
-    total_weight += sources_[i]->GetWeight();
-  DCHECK_GT(total_weight, 0);
-
-  page_values_.reset(new base::ListValue());
-
-  // Evaluate how many items to obtain from each source. We use error diffusion
-  // to ensure that we get the total desired number of items.
-  int error = 0;
-
-  // Holds the index at which the next item should be added for each source.
-  std::vector<size_t> next_item_index_for_source;
-  next_item_index_for_source.reserve(sources_.size());
-  for (size_t i = 0; i < sources_.size(); ++i) {
-    int numerator = sources_[i]->GetWeight() * suggestions_count_ + error;
-    error = numerator % total_weight;
-    int item_count = std::min(numerator / total_weight,
-        sources_[i]->GetItemCount());
-
-    for (int j = 0; j < item_count; ++j)
-      page_values_->Append(sources_[i]->PopItem());
-    next_item_index_for_source.push_back(page_values_->GetSize());
-  }
-
-  // Fill in extra items, prioritizing the first source.
-  // Rather than updating |next_item_index_for_source| we keep track of the
-  // number of extra items that were added and offset indices by that much.
-  size_t extra_items_added = 0;
-  for (size_t i = 0; i < sources_.size() &&
-      page_values_->GetSize() < suggestions_count_; ++i) {
-
-    size_t index = next_item_index_for_source[i] + extra_items_added;
-    while (page_values_->GetSize() < suggestions_count_) {
-      base::DictionaryValue* item = sources_[i]->PopItem();
-      if (!item)
-        break;
-      page_values_->Insert(index++, item);
-      extra_items_added++;
-    }
-  }
-
-  // Add page value information common to all sources.
-  for (size_t i = 0; i < page_values_->GetSize(); i++) {
-    base::DictionaryValue* page_value;
-    if (page_values_->GetDictionary(i, &page_value))
-      AddExtendedInformation(page_value);
-  }
-}
-
-void SuggestionsCombiner::AddExtendedInformation(
-    base::DictionaryValue* page_value) {
-  if (debug_enabled_) {
-    std::string url_string;
-    if (page_value->GetString("url", &url_string)) {
-      GURL url(url_string);
-      page_value->SetBoolean("already_open", IsUrlAlreadyOpen(url));
-    }
-  }
-}
-
-bool SuggestionsCombiner::IsUrlAlreadyOpen(const GURL &url) {
-  for (chrome::BrowserIterator it; !it.done(); it.Next()) {
-    const Browser* browser = *it;
-    if (browser->profile()->IsOffTheRecord() ||
-        !browser->profile()->IsSameProfile(profile_))
-      continue;
-
-    for (int i = 0; i < browser->tab_strip_model()->count(); i++) {
-      const content::WebContents* tab =
-          browser->tab_strip_model()->GetWebContentsAt(i);
-      if (tab->GetURL() == url)
-        return true;
-    }
-  }
-  return false;
-}
diff --git a/chrome/browser/ui/webui/ntp/suggestions_combiner.h b/chrome/browser/ui/webui/ntp/suggestions_combiner.h
deleted file mode 100644
index ca5041a0..0000000
--- a/chrome/browser/ui/webui/ntp/suggestions_combiner.h
+++ /dev/null
@@ -1,108 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_WEBUI_NTP_SUGGESTIONS_COMBINER_H_
-#define CHROME_BROWSER_UI_WEBUI_NTP_SUGGESTIONS_COMBINER_H_
-
-#include <vector>
-
-#include "base/basictypes.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/memory/scoped_vector.h"
-
-class GURL;
-class SuggestionsHandler;
-class SuggestionsSource;
-class Profile;
-
-namespace base {
-class DictionaryValue;
-class ListValue;
-}
-
-// Combines many different sources of suggestions and generates data from it.
-class SuggestionsCombiner {
- public:
-  // Interface to be implemented by classes that will be notified of events from
-  // the SuggestionsCombiner.
-  class Delegate {
-   public:
-    virtual ~Delegate() {}
-
-    // Method that is called when new suggestions are ready from the
-    // SuggestionsCombiner.
-    virtual void OnSuggestionsReady() = 0;
-  };
-
-  virtual ~SuggestionsCombiner();
-
-  explicit SuggestionsCombiner(SuggestionsCombiner::Delegate* delegate,
-                               Profile* profile);
-
-  // Add a new source. The SuggestionsCombiner takes ownership of |source|.
-  void AddSource(SuggestionsSource* source);
-
-  // Enables or disables debug mode. If debug mode is enabled, the sources are
-  // expected to provide additional data, which could be displayed, for example,
-  // in the chrome://suggestions-internals/ page.
-  void EnableDebug(bool enable);
-
-  // Fetch a new set of items from the various suggestion sources.
-  void FetchItems(Profile* profile);
-
-  base::ListValue* GetPageValues();
-
-  // Called by a source when its items are ready. Make sure suggestion sources
-  // call this method exactly once for each call to
-  // SuggestionsSource::FetchItems.
-  void OnItemsReady();
-
-  void SetSuggestionsCount(size_t suggestions_count);
-
- private:
-  friend class SuggestionsCombinerTest;
-
-  // Fill the page values from the suggestion sources so they can be sent to
-  // the JavaScript side. This should only be called when all the suggestion
-  // sources have items ready.
-  void FillPageValues();
-
-  // Add extra information to page values that should be common across all
-  // suggestion sources.
-  void AddExtendedInformation(base::DictionaryValue* page_value);
-
-  // Checks if a URL is already open for the current profile. URLs open in an
-  // incognito window are not reported.
-  bool IsUrlAlreadyOpen(const GURL& url);
-
-  typedef ScopedVector<SuggestionsSource> SuggestionsSources;
-
-  // List of all the suggestions sources that will be combined to generate a
-  // single list of suggestions.
-  SuggestionsSources sources_;
-
-  // Counter tracking the number of sources that are currently asynchronously
-  // fetching their data.
-  int sources_fetching_count_;
-
-  // The delegate to notify once items are ready.
-  SuggestionsCombiner::Delegate* delegate_;
-
-  // Number of suggestions to generate. Used to distribute the suggestions
-  // between the various sources.
-  size_t suggestions_count_;
-
-  // Informations to send to the javascript side.
-  scoped_ptr<base::ListValue> page_values_;
-
-  // Whether debug mode is enabled or not (debug mode provides more data in the
-  // results).
-  bool debug_enabled_;
-
-  Profile* profile_;
-
-  DISALLOW_COPY_AND_ASSIGN(SuggestionsCombiner);
-};
-
-#endif  // CHROME_BROWSER_UI_WEBUI_NTP_SUGGESTIONS_COMBINER_H_
diff --git a/chrome/browser/ui/webui/ntp/suggestions_combiner_unittest.cc b/chrome/browser/ui/webui/ntp/suggestions_combiner_unittest.cc
deleted file mode 100644
index d6bc880..0000000
--- a/chrome/browser/ui/webui/ntp/suggestions_combiner_unittest.cc
+++ /dev/null
@@ -1,298 +0,0 @@
-// Copyright (c) 2012 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.
-
-// TODO(beaudoin): What is really needed here?
-
-#include <deque>
-#include <string>
-
-#include "base/memory/scoped_ptr.h"
-#include "base/stl_util.h"
-#include "base/strings/string_util.h"
-#include "base/values.h"
-#include "chrome/browser/ui/webui/ntp/suggestions_combiner.h"
-#include "chrome/browser/ui/webui/ntp/suggestions_page_handler.h"
-#include "chrome/browser/ui/webui/ntp/suggestions_source.h"
-#include "chrome/test/base/testing_profile.h"
-#include "content/public/test/test_browser_thread_bundle.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace {
-
-struct SourceInfo {
-  int weight;
-  const char* source_name;
-  int number_of_suggestions;
-};
-
-struct TestDescription {
-  SourceInfo sources[3];
-  const char* results[8];
-} test_suite[] = {
-  // One source, more than 8 items.
-  {
-    {{1, "A", 10}},
-    {"A 0", "A 1", "A 2", "A 3", "A 4", "A 5", "A 6", "A 7"}
-  },
-  // One source, exactly 8 items.
-  {
-    {{1, "A", 8}},
-    {"A 0", "A 1", "A 2", "A 3", "A 4", "A 5", "A 6", "A 7"}
-  },
-  // One source, not enough items.
-  {
-    {{1, "A", 3}},
-    {"A 0", "A 1", "A 2"}
-  },
-  // One source, no items.
-  {
-    {{1, "A", 0}},
-    {}
-  },
-  // Two sources, equal weight, more than 8 items.
-  {
-    {{1, "A", 10}, {1, "B", 10}},
-    {"A 0", "A 1", "A 2", "A 3", "B 0", "B 1", "B 2", "B 3"}
-  },
-  // Two sources, equal weight, exactly 8 items.
-  {
-    {{1, "A", 4}, {1, "B", 4}},
-    {"A 0", "A 1", "A 2", "A 3", "B 0", "B 1", "B 2", "B 3"}
-  },
-  // Two sources, equal weight, exactly 8 items but source A has more.
-  {
-    {{1, "A", 5}, {1, "B", 3}},
-    {"A 0", "A 1", "A 2", "A 3", "A 4", "B 0", "B 1", "B 2"}
-  },
-  // Two sources, equal weight, exactly 8 items but source B has more.
-  {
-    {{1, "A", 2}, {1, "B", 6}},
-    {"A 0", "A 1", "B 0", "B 1", "B 2", "B 3", "B 4", "B 5"}
-  },
-  // Two sources, equal weight, exactly 8 items but source A has none.
-  {
-    {{1, "A", 0}, {1, "B", 8}},
-    {"B 0", "B 1", "B 2", "B 3", "B 4", "B 5", "B 6", "B 7"}
-  },
-  // Two sources, equal weight, exactly 8 items but source B has none.
-  {
-    {{1, "A", 8}, {1, "B", 0}},
-    {"A 0", "A 1", "A 2", "A 3", "A 4", "A 5", "A 6", "A 7"}
-  },
-  // Two sources, equal weight, less than 8 items.
-  {
-    {{1, "A", 3}, {1, "B", 3}},
-    {"A 0", "A 1", "A 2", "B 0", "B 1", "B 2"}
-  },
-  // Two sources, equal weight, less than 8 items but source A has more.
-  {
-    {{1, "A", 4}, {1, "B", 3}},
-    {"A 0", "A 1", "A 2", "A 3", "B 0", "B 1", "B 2"}
-  },
-  // Two sources, equal weight, less than 8 items but source B has more.
-  {
-    {{1, "A", 1}, {1, "B", 3}},
-    {"A 0", "B 0", "B 1", "B 2"}
-  },
-  // Two sources, weights 3/4 A  1/4 B, more than 8 items.
-  {
-    {{3, "A", 10}, {1, "B", 10}},
-    {"A 0", "A 1", "A 2", "A 3", "A 4", "A 5", "B 0", "B 1"}
-  },
-  // Two sources, weights 1/8 A  7/8 B, more than 8 items.
-  {
-    {{1, "A", 10}, {7, "B", 10}},
-    {"A 0", "B 0", "B 1", "B 2", "B 3", "B 4", "B 5", "B 6"}
-  },
-  // Two sources, weights 1/3 A  2/3 B, more than 8 items.
-  {
-    {{1, "A", 10}, {2, "B", 10}},
-    {"A 0", "A 1", "B 0", "B 1", "B 2", "B 3", "B 4", "B 5"}
-  },
-  // Three sources, weights 1/2 A  1/4 B  1/4 C, more than 8 items.
-  {
-    {{2, "A", 10}, {1, "B", 10}, {1, "C", 10}},
-    {"A 0", "A 1", "A 2", "A 3", "B 0", "B 1", "C 0", "C 1"}
-  },
-  // Three sources, weights 1/3 A  1/3 B  1/3 C, more than 8 items.
-  {
-    {{1, "A", 10}, {1, "B", 10}, {1, "C", 10}},
-    {"A 0", "A 1", "B 0", "B 1", "B 2", "C 0", "C 1", "C 2"}
-  },
-  // Extra items should be grouped together.
-  {
-    {{1, "A", 3}, {1, "B", 4}, {10, "C", 1}},
-    {"A 0", "A 1", "A 2", "B 0", "B 1", "B 2", "B 3", "C 0"}
-  }
-};
-
-}  // namespace
-
-// Stub for a SuggestionsSource that can provide a number of fake suggestions.
-// Fake suggestions are DictionaryValue with a single "title" string field
-// containing the |source_name| followed by the index of the suggestion.
-// Not in the empty namespace since it's a friend of SuggestionsCombiner.
-class SuggestionsSourceStub : public SuggestionsSource {
- public:
-  explicit SuggestionsSourceStub(int weight,
-      const std::string& source_name, int number_of_suggestions)
-      : combiner_(NULL),
-        weight_(weight),
-        source_name_(source_name),
-        number_of_suggestions_(number_of_suggestions),
-        debug_(false) {
-  }
-  ~SuggestionsSourceStub() override { STLDeleteElements(&items_); }
-
-  // Call this method to simulate that the SuggestionsSource has received all
-  // its suggestions.
-  void Done() {
-    combiner_->OnItemsReady();
-  }
-
- private:
-  // SuggestionsSource Override and implementation.
-  void SetDebug(bool enable) override { debug_ = enable; }
-  int GetWeight() override { return weight_; }
-  int GetItemCount() override { return items_.size(); }
-  base::DictionaryValue* PopItem() override {
-    if (items_.empty())
-      return NULL;
-    base::DictionaryValue* item = items_.front();
-    items_.pop_front();
-    return item;
-  }
-
-  void FetchItems(Profile* profile) override {
-    char num_str[21];  // Enough to hold all numbers up to 64-bits.
-    for (int i = 0; i < number_of_suggestions_; ++i) {
-      base::snprintf(num_str, sizeof(num_str), "%d", i);
-      AddSuggestion(source_name_ + ' ' + num_str);
-    }
-  }
-
-  // Adds a fake suggestion. This suggestion is a DictionaryValue with a single
-  // "title" field containing |title|.
-  void AddSuggestion(const std::string& title) {
-    base::DictionaryValue* item = new base::DictionaryValue();
-    item->SetString("title", title);
-    items_.push_back(item);
-  }
-
-  void SetCombiner(SuggestionsCombiner* combiner) override {
-    DCHECK(!combiner_);
-    combiner_ = combiner;
-  }
-
-  // Our combiner.
-  SuggestionsCombiner* combiner_;
-
-  int weight_;
-  std::string source_name_;
-  int number_of_suggestions_;
-  bool debug_;
-
-  // Keep the results of the db query here.
-  std::deque<base::DictionaryValue*> items_;
-
-  DISALLOW_COPY_AND_ASSIGN(SuggestionsSourceStub);
-};
-
-class SuggestionsCombinerTest : public testing::Test {
- public:
-  SuggestionsCombinerTest() {
-  }
-
- protected:
-  content::TestBrowserThreadBundle thread_bundle_;
-  Profile* profile_;
-  SuggestionsHandler* suggestions_handler_;
-  SuggestionsCombiner* combiner_;
-
-  void Reset() {
-    delete combiner_;
-    combiner_ = new SuggestionsCombiner(suggestions_handler_, profile_);
-  }
-
- private:
-  void SetUp() override {
-    profile_ = new TestingProfile();
-    suggestions_handler_ = new SuggestionsHandler();
-    combiner_ = new SuggestionsCombiner(suggestions_handler_, profile_);
-  }
-
-  void TearDown() override {
-    delete combiner_;
-    delete suggestions_handler_;
-    delete profile_;
-  }
-
-  DISALLOW_COPY_AND_ASSIGN(SuggestionsCombinerTest);
-};
-
-TEST_F(SuggestionsCombinerTest, NoSource) {
-  combiner_->FetchItems(NULL);
-  EXPECT_EQ(0UL, combiner_->GetPageValues()->GetSize());
-}
-
-TEST_F(SuggestionsCombinerTest, SourcesAreNotDoneFetching) {
-  combiner_->AddSource(new SuggestionsSourceStub(1, "sourceA", 10));
-  combiner_->AddSource(new SuggestionsSourceStub(1, "sourceB", 10));
-  combiner_->FetchItems(NULL);
-  EXPECT_EQ(0UL, combiner_->GetPageValues()->GetSize());
-}
-
-TEST_F(SuggestionsCombinerTest, TestSuite) {
-  size_t test_count = arraysize(test_suite);
-  for (size_t i = 0; i < test_count; ++i) {
-    const TestDescription& description = test_suite[i];
-    size_t source_count = arraysize(description.sources);
-
-    scoped_ptr<SuggestionsSourceStub*[]> sources(
-        new SuggestionsSourceStub*[source_count]);
-
-    // Setup sources.
-    for (size_t j = 0; j < source_count; ++j) {
-      const SourceInfo& source_info = description.sources[j];
-      // A NULL |source_name| means we shouldn't add this source.
-      if (source_info.source_name) {
-        sources[j] = new SuggestionsSourceStub(source_info.weight,
-            source_info.source_name, source_info.number_of_suggestions);
-        combiner_->AddSource(sources[j]);
-      } else {
-        sources[j] = NULL;
-      }
-    }
-
-    // Start fetching.
-    combiner_->FetchItems(NULL);
-
-    // Sources complete.
-    for (size_t j = 0; j < source_count; ++j) {
-      if (sources[j])
-        sources[j]->Done();
-    }
-
-    // Verify expectations.
-    base::ListValue* results = combiner_->GetPageValues();
-    size_t result_count = results->GetSize();
-    EXPECT_LE(result_count, 8UL);
-    for (size_t j = 0; j < 8; ++j) {
-      if (j < result_count) {
-        std::string value;
-        base::DictionaryValue* dictionary;
-        results->GetDictionary(j, &dictionary);
-        dictionary->GetString("title", &value);
-        EXPECT_STREQ(description.results[j], value.c_str()) <<
-            " test index:" << i;
-      } else {
-        EXPECT_EQ(description.results[j], static_cast<const char*>(NULL)) <<
-            " test index:" << i;
-      }
-    }
-
-    Reset();
-  }
-}
-
diff --git a/chrome/browser/ui/webui/ntp/suggestions_page_handler.cc b/chrome/browser/ui/webui/ntp/suggestions_page_handler.cc
deleted file mode 100644
index d8b97451..0000000
--- a/chrome/browser/ui/webui/ntp/suggestions_page_handler.cc
+++ /dev/null
@@ -1,198 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/webui/ntp/suggestions_page_handler.h"
-
-#include <math.h>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/md5.h"
-#include "base/metrics/histogram.h"
-#include "base/strings/string16.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/threading/thread.h"
-#include "base/values.h"
-#include "chrome/browser/history/top_sites_factory.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/webui/favicon_source.h"
-#include "chrome/browser/ui/webui/ntp/ntp_stats.h"
-#include "chrome/browser/ui/webui/ntp/suggestions_combiner.h"
-#include "chrome/browser/ui/webui/ntp/suggestions_source_top_sites.h"
-#include "chrome/browser/ui/webui/ntp/thumbnail_source.h"
-#include "chrome/common/url_constants.h"
-#include "components/history/core/browser/page_usage_data.h"
-#include "components/history/core/browser/top_sites.h"
-#include "components/pref_registry/pref_registry_syncable.h"
-#include "content/public/browser/navigation_controller.h"
-#include "content/public/browser/navigation_entry.h"
-#include "content/public/browser/url_data_source.h"
-#include "content/public/browser/user_metrics.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/browser/web_ui.h"
-#include "ui/base/page_transition_types.h"
-#include "url/gurl.h"
-
-using base::UserMetricsAction;
-
-SuggestionsHandler::SuggestionsHandler()
-    : scoped_observer_(this),
-      got_first_suggestions_request_(false),
-      suggestions_viewed_(false),
-      user_action_logged_(false) {
-}
-
-SuggestionsHandler::~SuggestionsHandler() {
-  if (!user_action_logged_ && suggestions_viewed_) {
-    const GURL ntp_url = GURL(chrome::kChromeUINewTabURL);
-    int action_id = NTP_FOLLOW_ACTION_OTHER;
-    content::NavigationEntry* entry =
-        web_ui()->GetWebContents()->GetController().GetLastCommittedEntry();
-    if (entry && (entry->GetURL() != ntp_url)) {
-      action_id =
-          ui::PageTransitionStripQualifier(entry->GetTransitionType());
-    }
-
-    UMA_HISTOGRAM_ENUMERATION("NewTabPage.SuggestedSitesAction", action_id,
-                              NUM_NTP_FOLLOW_ACTIONS);
-  }
-}
-
-void SuggestionsHandler::RegisterMessages() {
-  Profile* profile = Profile::FromWebUI(web_ui());
-  // Set up our sources for thumbnail and favicon data.
-  content::URLDataSource::Add(profile, new ThumbnailSource(profile, false));
-  content::URLDataSource::Add(
-      profile, new FaviconSource(profile, FaviconSource::FAVICON));
-
-  // TODO(georgey) change the source of the web-sites to provide our data.
-  // Initial commit uses top sites as a data source.
-  scoped_refptr<history::TopSites> top_sites =
-      TopSitesFactory::GetForProfile(profile);
-  if (top_sites) {
-    // TopSites updates itself after a delay. This is especially noticable when
-    // your profile is empty. Ask TopSites to update itself when we're about to
-    // show the new tab page.
-    top_sites->SyncWithHistory();
-
-    // Register as TopSitesObserver so that we can update ourselves when the
-    // TopSites changes.
-    scoped_observer_.Add(top_sites.get());
-  }
-
-  // Setup the suggestions sources.
-  SuggestionsCombiner* combiner = new SuggestionsCombiner(this, profile);
-  combiner->AddSource(new SuggestionsSourceTopSites());
-  suggestions_combiner_.reset(combiner);
-
-  // We pre-emptively make a fetch for suggestions so we have the results
-  // sooner.
-  suggestions_combiner_->FetchItems(profile);
-
-  web_ui()->RegisterMessageCallback("getSuggestions",
-      base::Bind(&SuggestionsHandler::HandleGetSuggestions,
-                 base::Unretained(this)));
-  // Register ourselves for any suggestions item blacklisting.
-  web_ui()->RegisterMessageCallback("blacklistURLFromSuggestions",
-      base::Bind(&SuggestionsHandler::HandleBlacklistURL,
-                 base::Unretained(this)));
-  web_ui()->RegisterMessageCallback("removeURLsFromSuggestionsBlacklist",
-      base::Bind(&SuggestionsHandler::HandleRemoveURLsFromBlacklist,
-                 base::Unretained(this)));
-  web_ui()->RegisterMessageCallback("clearSuggestionsURLsBlacklist",
-      base::Bind(&SuggestionsHandler::HandleClearBlacklist,
-                 base::Unretained(this)));
-  web_ui()->RegisterMessageCallback("suggestedSitesAction",
-      base::Bind(&SuggestionsHandler::HandleSuggestedSitesAction,
-                 base::Unretained(this)));
-  web_ui()->RegisterMessageCallback("suggestedSitesSelected",
-      base::Bind(&SuggestionsHandler::HandleSuggestedSitesSelected,
-                 base::Unretained(this)));
-}
-
-void SuggestionsHandler::HandleGetSuggestions(const base::ListValue* args) {
-  if (!got_first_suggestions_request_) {
-    // If it's the first request we get, return the prefetched data.
-    SendPagesValue();
-    got_first_suggestions_request_ = true;
-  } else {
-    suggestions_combiner_->FetchItems(Profile::FromWebUI(web_ui()));
-  }
-}
-
-void SuggestionsHandler::OnSuggestionsReady() {
-  // If we got the results as a result of a suggestions request initiated by the
-  // JavaScript then we send back the page values.
-  if (got_first_suggestions_request_)
-    SendPagesValue();
-}
-
-void SuggestionsHandler::SendPagesValue() {
-  if (suggestions_combiner_->GetPageValues()) {
-    // TODO(georgey) add actual blacklist.
-    bool has_blacklisted_urls = false;
-    base::FundamentalValue has_blacklisted_urls_value(has_blacklisted_urls);
-    web_ui()->CallJavascriptFunction("ntp.setSuggestionsPages",
-                                     *suggestions_combiner_->GetPageValues(),
-                                     has_blacklisted_urls_value);
-  }
-}
-
-void SuggestionsHandler::HandleBlacklistURL(const base::ListValue* args) {
-  std::string url = base::UTF16ToUTF8(ExtractStringValue(args));
-  BlacklistURL(GURL(url));
-}
-
-void SuggestionsHandler::HandleRemoveURLsFromBlacklist(
-    const base::ListValue* args) {
-  DCHECK_GT(args->GetSize(), 0U);
-  // TODO(georgey) remove URLs from blacklist.
-}
-
-void SuggestionsHandler::HandleClearBlacklist(const base::ListValue* args) {
-  // TODO(georgey) clear blacklist.
-}
-
-void SuggestionsHandler::HandleSuggestedSitesAction(
-    const base::ListValue* args) {
-  DCHECK(args);
-
-  double action_id;
-  if (!args->GetDouble(0, &action_id))
-    NOTREACHED();
-
-  UMA_HISTOGRAM_ENUMERATION("NewTabPage.SuggestedSitesAction",
-                            static_cast<int>(action_id),
-                            NUM_NTP_FOLLOW_ACTIONS);
-  suggestions_viewed_ = true;
-  user_action_logged_ = true;
-}
-
-void SuggestionsHandler::HandleSuggestedSitesSelected(
-    const base::ListValue* args) {
-  suggestions_viewed_ = true;
-}
-
-void SuggestionsHandler::TopSitesLoaded(history::TopSites* top_sites) {
-}
-
-void SuggestionsHandler::TopSitesChanged(history::TopSites* top_sites) {
-  // Suggestions urls changed, query again.
-  suggestions_combiner_->FetchItems(Profile::FromWebUI(web_ui()));
-}
-
-void SuggestionsHandler::BlacklistURL(const GURL& url) {
-  // TODO(georgey) blacklist an URL.
-}
-
-std::string SuggestionsHandler::GetDictionaryKeyForURL(const std::string& url) {
-  return base::MD5String(url);
-}
-
-// static
-void SuggestionsHandler::RegisterProfilePrefs(
-    user_prefs::PrefRegistrySyncable* registry) {
-  // TODO(georgey) add user preferences (such as own blacklist) as needed.
-}
diff --git a/chrome/browser/ui/webui/ntp/suggestions_page_handler.h b/chrome/browser/ui/webui/ntp/suggestions_page_handler.h
deleted file mode 100644
index de7712fc..0000000
--- a/chrome/browser/ui/webui/ntp/suggestions_page_handler.h
+++ /dev/null
@@ -1,99 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_WEBUI_NTP_SUGGESTIONS_PAGE_HANDLER_H_
-#define CHROME_BROWSER_UI_WEBUI_NTP_SUGGESTIONS_PAGE_HANDLER_H_
-
-#include <string>
-
-#include "base/scoped_observer.h"
-#include "chrome/browser/ui/webui/ntp/suggestions_combiner.h"
-#include "components/history/core/browser/history_types.h"
-#include "components/history/core/browser/top_sites_observer.h"
-#include "content/public/browser/web_ui_message_handler.h"
-
-class GURL;
-
-namespace base {
-class ListValue;
-class Value;
-}
-
-namespace user_prefs {
-class PrefRegistrySyncable;
-}
-
-// The handler for Javascript messages related to the "suggestions" view.
-//
-// This class manages one preference:
-// - The URL blacklist: URLs we do not want to show in the thumbnails list.  It
-//   is a dictionary for quick access (it associates a dummy boolean to the URL
-//   string).
-class SuggestionsHandler : public content::WebUIMessageHandler,
-                           public SuggestionsCombiner::Delegate,
-                           public history::TopSitesObserver {
- public:
-  SuggestionsHandler();
-  ~SuggestionsHandler() override;
-
-  // WebUIMessageHandler override and implementation.
-  void RegisterMessages() override;
-
-  // Callback for the "getSuggestions" message.
-  void HandleGetSuggestions(const base::ListValue* args);
-
-  // Callback for the "blacklistURLFromSuggestions" message.
-  void HandleBlacklistURL(const base::ListValue* args);
-
-  // Callback for the "removeURLsFromSuggestionsBlacklist" message.
-  void HandleRemoveURLsFromBlacklist(const base::ListValue* args);
-
-  // Callback for the "clearSuggestionsURLsBlacklist" message.
-  void HandleClearBlacklist(const base::ListValue* args);
-
-  // Callback for the "suggestedSitesAction" message.
-  void HandleSuggestedSitesAction(const base::ListValue* args);
-
-  // Callback for the "suggestedSitesSelected" message.
-  void HandleSuggestedSitesSelected(const base::ListValue* args);
-
-  // history::TopSitesObserver implementation.
-  void TopSitesLoaded(history::TopSites* top_sites) override;
-  void TopSitesChanged(history::TopSites* top_sites) override;
-
-  // SuggestionsCombiner::Delegate implementation.
-  void OnSuggestionsReady() override;
-
-  static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
-
- private:
-  // Puts the passed URL in the blacklist (so it does not show as a thumbnail).
-  void BlacklistURL(const GURL& url);
-
-  // Returns the key used in url_blacklist_ for the passed |url|.
-  std::string GetDictionaryKeyForURL(const std::string& url);
-
-  // Sends pages_value_ to the javascript side to and resets page_value_.
-  void SendPagesValue();
-
-  // Scoped observer to help with TopSitesObserver registration.
-  ScopedObserver<history::TopSites, history::TopSitesObserver> scoped_observer_;
-
-  // We pre-fetch the first set of result pages.  This variable is false until
-  // we get the first getSuggestions() call.
-  bool got_first_suggestions_request_;
-
-  // Used to combine suggestions from various sources.
-  scoped_ptr<SuggestionsCombiner> suggestions_combiner_;
-
-  // Whether the user has viewed the 'suggested' pane.
-  bool suggestions_viewed_;
-
-  // Whether the user has performed a "tracked" action to leave the page or not.
-  bool user_action_logged_;
-
-  DISALLOW_COPY_AND_ASSIGN(SuggestionsHandler);
-};
-
-#endif  // CHROME_BROWSER_UI_WEBUI_NTP_SUGGESTIONS_PAGE_HANDLER_H_
diff --git a/chrome/browser/ui/webui/ntp/suggestions_source.h b/chrome/browser/ui/webui/ntp/suggestions_source.h
deleted file mode 100644
index fd174d50..0000000
--- a/chrome/browser/ui/webui/ntp/suggestions_source.h
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_WEBUI_NTP_SUGGESTIONS_SOURCE_H_
-#define CHROME_BROWSER_UI_WEBUI_NTP_SUGGESTIONS_SOURCE_H_
-
-#include "base/basictypes.h"
-
-class Profile;
-class SuggestionsCombiner;
-
-namespace base {
-class DictionaryValue;
-}
-
-// Interface for a source of suggested pages. The various sources will be
-// combined by the SuggestionsCombiner.
-class SuggestionsSource {
-
- public:
-  virtual ~SuggestionsSource() {}
-
- protected:
-  SuggestionsSource() {}
-
-  friend class SuggestionsCombiner;
-
-  // Enables or disables debug mode for the current source. The source is
-  // expected to provide additional data when debug mode is enabled.
-  virtual void SetDebug(bool enable) = 0;
-
-  // The source's weight indicates how many items from this source will be
-  // selected by the combiner. If a source weight is x and the total weight of
-  // all the sources is y, then the combiner will select x/y items from it.
-  virtual int GetWeight() = 0;
-
-  // Returns the number of items this source can produce.
-  virtual int GetItemCount() = 0;
-
-  // Removes the most important item from this source and returns it. The
-  // returned item must be in the right format to be sent to the javascript,
-  // which you typically get by calling NewTabUI::SetUrlTitleAndDirection. If
-  // the source is empty this method returns null.
-  // The caller takes ownership of the returned item.
-  virtual base::DictionaryValue* PopItem() = 0;
-
-  // Requests that the source fetch its items. If the source is already fetching
-  // it does not have to reset and can continue fetching.
-  virtual void FetchItems(Profile* profile) = 0;
-
-  // Sets the combiner holding this suggestion source. This method can only
-  // be called once.
-  virtual void SetCombiner(SuggestionsCombiner* combiner) = 0;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(SuggestionsSource);
-};
-
-#endif  // CHROME_BROWSER_UI_WEBUI_NTP_SUGGESTIONS_SOURCE_H_
diff --git a/chrome/browser/ui/webui/ntp/suggestions_source_top_sites.cc b/chrome/browser/ui/webui/ntp/suggestions_source_top_sites.cc
deleted file mode 100644
index cdac4b5..0000000
--- a/chrome/browser/ui/webui/ntp/suggestions_source_top_sites.cc
+++ /dev/null
@@ -1,139 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/webui/ntp/suggestions_source_top_sites.h"
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/command_line.h"
-#include "base/stl_util.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/values.h"
-#include "chrome/browser/history/history_service_factory.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/webui/ntp/new_tab_ui.h"
-#include "chrome/browser/ui/webui/ntp/suggestions_combiner.h"
-#include "chrome/common/chrome_switches.h"
-#include "components/history/core/browser/history_service.h"
-#include "components/history/core/browser/top_sites.h"
-#include "components/history/core/browser/visit_filter.h"
-
-
-namespace {
-
-// The weight used by the combiner to determine which ratio of suggestions
-// should be obtained from this source.
-const int kSuggestionsTopListWeight = 1;
-
-}  // namespace
-
-SuggestionsSourceTopSites::SuggestionsSourceTopSites()
-    : combiner_(NULL),
-      debug_(false) {
-}
-
-SuggestionsSourceTopSites::~SuggestionsSourceTopSites() {
-  STLDeleteElements(&items_);
-}
-
-void SuggestionsSourceTopSites::SetDebug(bool enable) {
-  debug_ = enable;
-}
-
-inline int SuggestionsSourceTopSites::GetWeight() {
-  return kSuggestionsTopListWeight;
-}
-
-int SuggestionsSourceTopSites::GetItemCount() {
-  return items_.size();
-}
-
-base::DictionaryValue* SuggestionsSourceTopSites::PopItem() {
-  if (items_.empty())
-    return NULL;
-
-  base::DictionaryValue* item = items_.front();
-  items_.pop_front();
-  return item;
-}
-
-void SuggestionsSourceTopSites::FetchItems(Profile* profile) {
-  DCHECK(combiner_);
-  STLDeleteElements(&items_);
-
-  history_tracker_.TryCancelAll();
-  history::HistoryService* history = HistoryServiceFactory::GetForProfile(
-      profile, ServiceAccessType::EXPLICIT_ACCESS);
-  // |history| may be null during unit tests.
-  if (history) {
-    history::VisitFilter time_filter;
-    time_filter.SetFilterTime(base::Time::Now());
-    time_filter.SetFilterWidth(GetFilterWidth());
-    time_filter.set_sorting_order(GetSortingOrder());
-
-    history->QueryFilteredURLs(
-        0,
-        time_filter,
-        debug_,
-        base::Bind(&SuggestionsSourceTopSites::OnSuggestionsUrlsAvailable,
-                   base::Unretained(this)),
-        &history_tracker_);
-  }
-}
-
-void SuggestionsSourceTopSites::SetCombiner(SuggestionsCombiner* combiner) {
-  DCHECK(!combiner_);
-  combiner_ = combiner;
-}
-
-void SuggestionsSourceTopSites::OnSuggestionsUrlsAvailable(
-    const history::FilteredURLList* data) {
-  DCHECK(data);
-  DCHECK(combiner_);
-  for (size_t i = 0; i < data->size(); i++) {
-    const history::FilteredURL& suggested_url = (*data)[i];
-    if (suggested_url.url.is_empty())
-      continue;
-
-    base::DictionaryValue* page_value = new base::DictionaryValue();
-    NewTabUI::SetUrlTitleAndDirection(page_value,
-                                      suggested_url.title,
-                                      suggested_url.url);
-    page_value->SetDouble("score", suggested_url.score);
-    if (debug_) {
-      if (suggested_url.extended_info.total_visits) {
-        page_value->SetInteger("extended_info.total visits",
-                               suggested_url.extended_info.total_visits);
-      }
-      if (suggested_url.extended_info.visits) {
-        page_value->SetInteger("extended_info.visits",
-                               suggested_url.extended_info.visits);
-      }
-      if (suggested_url.extended_info.duration_opened) {
-        page_value->SetInteger("extended_info.duration opened",
-                               suggested_url.extended_info.duration_opened);
-      }
-      if (!suggested_url.extended_info.last_visit_time.is_null()) {
-        base::TimeDelta deltaTime =
-            base::Time::Now() - suggested_url.extended_info.last_visit_time;
-        page_value->SetInteger("extended_info.seconds since last visit",
-                               deltaTime.InSeconds());
-      }
-    }
-    items_.push_back(page_value);
-  }
-
-  combiner_->OnItemsReady();
-}
-
-// static
-base::TimeDelta SuggestionsSourceTopSites::GetFilterWidth() {
-  return base::TimeDelta::FromHours(1);
-}
-
-// static
-history::VisitFilter::SortingOrder
-SuggestionsSourceTopSites::GetSortingOrder() {
-  return history::VisitFilter::ORDER_BY_RECENCY;
-}
diff --git a/chrome/browser/ui/webui/ntp/suggestions_source_top_sites.h b/chrome/browser/ui/webui/ntp/suggestions_source_top_sites.h
deleted file mode 100644
index 3d22043..0000000
--- a/chrome/browser/ui/webui/ntp/suggestions_source_top_sites.h
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_WEBUI_NTP_SUGGESTIONS_SOURCE_TOP_SITES_H_
-#define CHROME_BROWSER_UI_WEBUI_NTP_SUGGESTIONS_SOURCE_TOP_SITES_H_
-
-#include <deque>
-
-#include "base/basictypes.h"
-#include "base/task/cancelable_task_tracker.h"
-#include "chrome/browser/ui/webui/ntp/suggestions_source.h"
-#include "components/history/core/browser/history_types.h"
-#include "components/history/core/browser/visit_filter.h"
-
-class SuggestionsCombiner;
-class Profile;
-
-namespace base {
-class DictionaryValue;
-}
-
-// A SuggestionsSource that uses the local TopSites database to provide
-// suggestions.
-class SuggestionsSourceTopSites : public SuggestionsSource {
- public:
-  SuggestionsSourceTopSites();
-  ~SuggestionsSourceTopSites() override;
-
- protected:
-  // SuggestionsSource overrides:
-  void SetDebug(bool enable) override;
-  int GetWeight() override;
-  int GetItemCount() override;
-  base::DictionaryValue* PopItem() override;
-  void FetchItems(Profile* profile) override;
-  void SetCombiner(SuggestionsCombiner* combiner) override;
-
-  void OnSuggestionsUrlsAvailable(const history::FilteredURLList* data);
-
- private:
-
-  // Gets the sorting order from the command-line arguments. Defaults to
-  // |ORDER_BY_RECENCY| if there are no command-line argument specifying a
-  // sorting order.
-  static history::VisitFilter::SortingOrder GetSortingOrder();
-
-  // Gets the filter width from the command-line arguments. Defaults to one
-  // hour if there are no command-line argument setting the filter width.
-  static base::TimeDelta GetFilterWidth();
-
-  // Our combiner.
-  SuggestionsCombiner* combiner_;
-
-  // Keep the results of the db query here.
-  std::deque<base::DictionaryValue*> items_;
-
-  // Whether the source should provide additional debug information or not.
-  bool debug_;
-
-  base::CancelableTaskTracker history_tracker_;
-
-  DISALLOW_COPY_AND_ASSIGN(SuggestionsSourceTopSites);
-};
-
-#endif  // CHROME_BROWSER_UI_WEBUI_NTP_SUGGESTIONS_SOURCE_TOP_SITES_H_
diff --git a/chrome/browser/ui/webui/options/browser_options_handler.cc b/chrome/browser/ui/webui/options/browser_options_handler.cc
index 13dfafa..ce01268 100644
--- a/chrome/browser/ui/webui/options/browser_options_handler.cc
+++ b/chrome/browser/ui/webui/options/browser_options_handler.cc
@@ -58,6 +58,7 @@
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/chrome_select_file_policy.h"
 #include "chrome/browser/ui/host_desktop.h"
+#include "chrome/browser/ui/passwords/password_bubble_experiment.h"
 #include "chrome/browser/ui/webui/favicon_source.h"
 #include "chrome/browser/ui/webui/options/options_handlers_helper.h"
 #include "chrome/common/chrome_constants.h"
@@ -307,7 +308,11 @@
     { "metricsReportingResetRestart", IDS_OPTIONS_ENABLE_LOGGING_RESTART },
     { "networkPredictionEnabledDescription",
       IDS_NETWORK_PREDICTION_ENABLED_DESCRIPTION },
-    { "passwordManagerEnabled", IDS_OPTIONS_PASSWORD_MANAGER_ENABLE },
+    { "passwordManagerEnabled",
+      password_bubble_experiment::IsSmartLockBrandingEnabled(
+          Profile::FromWebUI(web_ui())) ?
+      IDS_OPTIONS_PASSWORD_MANAGER_SMART_LOCK_ENABLE :
+      IDS_OPTIONS_PASSWORD_MANAGER_ENABLE },
     { "passwordsAndAutofillGroupName",
       IDS_OPTIONS_PASSWORDS_AND_FORMS_GROUP_NAME },
     { "privacyClearDataButton", IDS_OPTIONS_PRIVACY_CLEAR_DATA_BUTTON },
diff --git a/chrome/browser/ui/webui/options/password_manager_handler.cc b/chrome/browser/ui/webui/options/password_manager_handler.cc
index 4957e149..ec0f9c3 100644
--- a/chrome/browser/ui/webui/options/password_manager_handler.cc
+++ b/chrome/browser/ui/webui/options/password_manager_handler.cc
@@ -17,6 +17,7 @@
 #include "chrome/browser/ui/ash/ash_util.h"
 #endif
 #include "chrome/browser/ui/passwords/manage_passwords_view_utils.h"
+#include "chrome/browser/ui/passwords/password_bubble_experiment.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/grit/generated_resources.h"
@@ -74,25 +75,32 @@
   };
 
   RegisterStrings(localized_strings, resources, arraysize(resources));
-  RegisterTitle(localized_strings, "passwordsPage",
-                IDS_PASSWORDS_EXCEPTIONS_WINDOW_TITLE);
+
+  int title_id =
+      password_bubble_experiment::IsSmartLockBrandingEnabled(GetProfile()) ?
+      IDS_PASSWORDS_EXCEPTIONS_SMART_LOCK_WINDOW_TITLE :
+      IDS_PASSWORDS_EXCEPTIONS_WINDOW_TITLE;
+  RegisterTitle(localized_strings, "passwordsPage", title_id);
 
   localized_strings->SetString("passwordManagerLearnMoreURL",
                                chrome::kPasswordManagerLearnMoreURL);
   localized_strings->SetString("passwordsManagePasswordsLink",
                                chrome::kPasswordManagerAccountDashboardURL);
 
-  std::vector<base::string16> pieces;
-  base::SplitStringDontTrim(
-      l10n_util::GetStringUTF16(IDS_MANAGE_PASSWORDS_REMOTE_TEXT),
-      '|',  // separator
-      &pieces);
-  DCHECK_EQ(3U, pieces.size());
+  std::string management_hostname =
+      GURL(chrome::kPasswordManagerAccountDashboardURL).host();
+  base::string16 link_text = base::UTF8ToUTF16(management_hostname);
+  size_t offset;
+  base::string16 full_text = l10n_util::GetStringFUTF16(
+      IDS_MANAGE_PASSWORDS_REMOTE_TEXT, link_text, &offset);
+
   localized_strings->SetString("passwordsManagePasswordsBeforeLinkText",
-                               pieces[0]);
-  localized_strings->SetString("passwordsManagePasswordsLinkText", pieces[1]);
+                               full_text.substr(0, offset));
+  localized_strings->SetString("passwordsManagePasswordsLinkText",
+                               full_text.substr(offset,
+                                                offset + link_text.size()));
   localized_strings->SetString("passwordsManagePasswordsAfterLinkText",
-                               pieces[2]);
+                               full_text.substr(offset + link_text.size()));
 
   bool disable_show_passwords = false;
 
diff --git a/chrome/browser/ui/webui/options/preferences_browsertest.cc b/chrome/browser/ui/webui/options/preferences_browsertest.cc
index 4a6511e..99805dc 100644
--- a/chrome/browser/ui/webui/options/preferences_browsertest.cc
+++ b/chrome/browser/ui/webui/options/preferences_browsertest.cc
@@ -68,7 +68,7 @@
 // Helper for pretty-printing the contents of base::Value in case of failures.
 void PrintTo(const base::Value& value, std::ostream* stream) {
   std::string json;
-  JSONWriter::Write(&value, &json);
+  JSONWriter::Write(value, &json);
   *stream << json;
 }
 
@@ -192,7 +192,7 @@
       .WillRepeatedly(Return(true));
   policy::BrowserPolicyConnector::SetPolicyProviderForTesting(
       &policy_provider_);
-};
+}
 
 void PreferencesBrowserTest::SetUserPolicies(
     const std::vector<std::string>& names,
@@ -376,9 +376,8 @@
     ExpectClearCommit(name);
   else
     ExpectNoCommit(name);
-  scoped_ptr<base::Value> commit_ptr(new base::FundamentalValue(commit));
   std::string commit_json;
-  base::JSONWriter::Write(commit_ptr.get(), &commit_json);
+  base::JSONWriter::Write(base::FundamentalValue(commit), &commit_json);
   std::stringstream javascript;
   javascript << "testEnv.runAndReply(function() {"
              << "    Preferences.clearPref("
diff --git a/chrome/browser/ui/webui/options/sync_setup_handler_unittest.cc b/chrome/browser/ui/webui/options/sync_setup_handler_unittest.cc
index ef6108e4..a0c5de4 100644
--- a/chrome/browser/ui/webui/options/sync_setup_handler_unittest.cc
+++ b/chrome/browser/ui/webui/options/sync_setup_handler_unittest.cc
@@ -93,7 +93,7 @@
   result.SetBoolean("wifiCredentialsSynced",
                     types.Has(syncer::WIFI_CREDENTIALS));
   std::string args;
-  base::JSONWriter::Write(&result, &args);
+  base::JSONWriter::Write(result, &args);
   return args;
 }
 
diff --git a/chrome/browser/ui/webui/policy_ui.cc b/chrome/browser/ui/webui/policy_ui.cc
index d2e73e7..03d4348 100644
--- a/chrome/browser/ui/webui/policy_ui.cc
+++ b/chrome/browser/ui/webui/policy_ui.cc
@@ -36,6 +36,7 @@
 #include "components/policy/core/common/policy_namespace.h"
 #include "components/policy/core/common/policy_service.h"
 #include "components/policy/core/common/policy_types.h"
+#include "components/policy/core/common/remote_commands/remote_commands_service.h"
 #include "components/policy/core/common/schema.h"
 #include "components/policy/core/common/schema_map.h"
 #include "components/policy/core/common/schema_registry.h"
@@ -52,6 +53,7 @@
 #include "ui/base/l10n/time_format.h"
 
 #if defined(OS_CHROMEOS)
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #include "chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h"
 #include "chrome/browser/chromeos/policy/device_local_account_policy_service.h"
@@ -215,7 +217,7 @@
 
 // Utility function that returns a JSON serialization of the given |dict|.
 scoped_ptr<base::StringValue> DictionaryToJSONString(
-    const base::DictionaryValue* dict) {
+    const base::DictionaryValue& dict) {
   std::string json_string;
   base::JSONWriter::WriteWithOptions(dict,
                                      base::JSONWriter::OPTIONS_PRETTY_PRINT,
@@ -228,14 +230,14 @@
 scoped_ptr<base::Value> CopyAndConvert(const base::Value* value) {
   const base::DictionaryValue* dict = NULL;
   if (value->GetAsDictionary(&dict))
-    return DictionaryToJSONString(dict);
+    return DictionaryToJSONString(*dict);
 
   scoped_ptr<base::Value> copy(value->DeepCopy());
   base::ListValue* list = NULL;
   if (copy->GetAsList(&list)) {
     for (size_t i = 0; i < list->GetSize(); ++i) {
       if (list->GetDictionary(i, &dict))
-        list->Set(i, DictionaryToJSONString(dict).release());
+        list->Set(i, DictionaryToJSONString(*dict).release());
     }
   }
 
@@ -807,9 +809,22 @@
 }
 
 void PolicyUIHandler::HandleReloadPolicies(const base::ListValue* args) {
-  GetPolicyService()->RefreshPolicies(
-      base::Bind(&PolicyUIHandler::OnRefreshPoliciesDone,
-                 weak_factory_.GetWeakPtr()));
+#if defined(OS_CHROMEOS)
+  // Allow user to manually fetch remote commands, in case invalidation
+  // service is not working properly.
+  // TODO(binjin): evaluate and possibly remove this after invalidation
+  // service is landed and tested. http://crbug.com/480982
+  policy::BrowserPolicyConnectorChromeOS* connector =
+      g_browser_process->platform_part()->browser_policy_connector_chromeos();
+  policy::RemoteCommandsService* remote_commands_service =
+      connector->GetDeviceCloudPolicyManager()
+          ->core()
+          ->remote_commands_service();
+  if (remote_commands_service)
+    remote_commands_service->FetchRemoteCommands();
+#endif
+  GetPolicyService()->RefreshPolicies(base::Bind(
+      &PolicyUIHandler::OnRefreshPoliciesDone, weak_factory_.GetWeakPtr()));
 }
 
 void PolicyUIHandler::OnRefreshPoliciesDone() const {
diff --git a/chrome/browser/ui/webui/signin/profile_signin_confirmation_dialog.cc b/chrome/browser/ui/webui/signin/profile_signin_confirmation_dialog.cc
index 1c688bb..5ad9d87 100644
--- a/chrome/browser/ui/webui/signin/profile_signin_confirmation_dialog.cc
+++ b/chrome/browser/ui/webui/signin/profile_signin_confirmation_dialog.cc
@@ -173,7 +173,7 @@
 #if defined(OS_WIN)
   dict.SetBoolean("hideTitle", true);
 #endif
-  base::JSONWriter::Write(&dict, &data);
+  base::JSONWriter::Write(dict, &data);
   return data;
 }
 
diff --git a/chrome/browser/ui/webui/suggestions_internals/suggestions_internals_ui.cc b/chrome/browser/ui/webui/suggestions_internals/suggestions_internals_ui.cc
deleted file mode 100644
index d55e8a76..0000000
--- a/chrome/browser/ui/webui/suggestions_internals/suggestions_internals_ui.cc
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/webui/suggestions_internals/suggestions_internals_ui.h"
-
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/webui/favicon_source.h"
-#include "chrome/browser/ui/webui/suggestions_internals/suggestions_internals_ui_handler.h"
-#include "chrome/common/url_constants.h"
-#include "content/public/browser/url_data_source.h"
-#include "content/public/browser/web_ui.h"
-#include "content/public/browser/web_ui_controller.h"
-#include "content/public/browser/web_ui_data_source.h"
-#include "grit/browser_resources.h"
-
-SuggestionsInternalsUI::SuggestionsInternalsUI(content::WebUI* web_ui)
-    : content::WebUIController(web_ui) {
-  // Set up the chrome://suggestions-internals/ source.
-  content::WebUIDataSource* html_source = content::WebUIDataSource::Create(
-      chrome::kChromeUISuggestionsInternalsHost);
-  html_source->AddResourcePath("suggestions_internals.css",
-                               IDR_SUGGESTIONS_INTERNALS_CSS);
-  html_source->AddResourcePath("suggestions_internals.js",
-                               IDR_SUGGESTIONS_INTERNALS_JS);
-  html_source->SetDefaultResource(IDR_SUGGESTIONS_INTERNALS_HTML);
-
-  Profile* profile = Profile::FromWebUI(web_ui);
-  content::WebUIDataSource::Add(profile, html_source);
-  content::URLDataSource::Add(
-      profile, new FaviconSource(profile, FaviconSource::FAVICON));
-
-  // AddMessageHandler takes ownership of SuggestionsInternalsUIHandler
-  web_ui->AddMessageHandler(new SuggestionsInternalsUIHandler(profile));
-}
-
-SuggestionsInternalsUI::~SuggestionsInternalsUI() { }
diff --git a/chrome/browser/ui/webui/suggestions_internals/suggestions_internals_ui.h b/chrome/browser/ui/webui/suggestions_internals/suggestions_internals_ui.h
deleted file mode 100644
index f80fd85..0000000
--- a/chrome/browser/ui/webui/suggestions_internals/suggestions_internals_ui.h
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_WEBUI_SUGGESTIONS_INTERNALS_SUGGESTIONS_INTERNALS_UI_H_
-#define CHROME_BROWSER_UI_WEBUI_SUGGESTIONS_INTERNALS_SUGGESTIONS_INTERNALS_UI_H_
-
-#include "base/basictypes.h"
-#include "content/public/browser/web_ui_controller.h"
-
-// The UI for chrome://suggestions-internals/
-class SuggestionsInternalsUI : public content::WebUIController {
- public:
-  explicit SuggestionsInternalsUI(content::WebUI* contents);
-  ~SuggestionsInternalsUI() override;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(SuggestionsInternalsUI);
-};
-
-#endif  // CHROME_BROWSER_UI_WEBUI_SUGGESTIONS_INTERNALS_SUGGESTIONS_INTERNALS_UI_H_
diff --git a/chrome/browser/ui/webui/suggestions_internals/suggestions_internals_ui_handler.cc b/chrome/browser/ui/webui/suggestions_internals/suggestions_internals_ui_handler.cc
deleted file mode 100644
index 020d441..0000000
--- a/chrome/browser/ui/webui/suggestions_internals/suggestions_internals_ui_handler.cc
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/webui/suggestions_internals/suggestions_internals_ui_handler.h"
-
-#include "base/bind.h"
-#include "base/values.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/webui/ntp/suggestions_combiner.h"
-#include "content/public/browser/web_ui.h"
-
-namespace {
-
-const size_t kSuggestionsCount = 100;
-
-}  // namespace
-
-SuggestionsInternalsUIHandler::SuggestionsInternalsUIHandler(Profile* profile)
-    : profile_(profile) {}
-
-SuggestionsInternalsUIHandler::~SuggestionsInternalsUIHandler() {}
-
-void SuggestionsInternalsUIHandler::OnSuggestionsReady() {
-  if (suggestions_combiner_->GetPageValues()) {
-    web_ui()->CallJavascriptFunction("suggestionsInternals.setSuggestions",
-                                     *suggestions_combiner_->GetPageValues());
-  }
-}
-
-void SuggestionsInternalsUIHandler::RegisterMessages() {
-  // Setup the suggestions sources.
-  suggestions_combiner_.reset(new SuggestionsCombiner(this, profile_));
-  suggestions_combiner_->SetSuggestionsCount(kSuggestionsCount);
-  suggestions_combiner_->EnableDebug(true);
-
-  web_ui()->RegisterMessageCallback("getSuggestions",
-      base::Bind(&SuggestionsInternalsUIHandler::HandleGetSuggestions,
-                 base::Unretained(this)));
-}
-
-void SuggestionsInternalsUIHandler::HandleGetSuggestions(
-    const base::ListValue* one_element_input_string) {
-  suggestions_combiner_->FetchItems(Profile::FromWebUI(web_ui()));
-}
diff --git a/chrome/browser/ui/webui/suggestions_internals/suggestions_internals_ui_handler.h b/chrome/browser/ui/webui/suggestions_internals/suggestions_internals_ui_handler.h
deleted file mode 100644
index f20b32fd..0000000
--- a/chrome/browser/ui/webui/suggestions_internals/suggestions_internals_ui_handler.h
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_WEBUI_SUGGESTIONS_INTERNALS_SUGGESTIONS_INTERNALS_UI_HANDLER_H_
-#define CHROME_BROWSER_UI_WEBUI_SUGGESTIONS_INTERNALS_SUGGESTIONS_INTERNALS_UI_HANDLER_H_
-
-#include "base/memory/scoped_ptr.h"
-#include "chrome/browser/ui/webui/ntp/suggestions_combiner.h"
-#include "content/public/browser/web_ui_message_handler.h"
-
-class Profile;
-
-namespace base {
-class ListValue;
-}
-
-// UI Handler for chrome://suggestions-internals/
-class SuggestionsInternalsUIHandler : public content::WebUIMessageHandler,
-                                      public SuggestionsCombiner::Delegate {
- public:
-  explicit SuggestionsInternalsUIHandler(Profile* profile);
-  ~SuggestionsInternalsUIHandler() override;
-
-  // SuggestionsCombiner::Delegate implementation.
-  void OnSuggestionsReady() override;
-
- protected:
-  // WebUIMessageHandler implementation.
-  // Register our handler to get callbacks from javascript.
-  void RegisterMessages() override;
-
-  void HandleGetSuggestions(const base::ListValue* one_element_input_string);
-
-  // Used to combine suggestions from various sources.
-  scoped_ptr<SuggestionsCombiner> suggestions_combiner_;
-
-  Profile* profile_;
-
-  DISALLOW_COPY_AND_ASSIGN(SuggestionsInternalsUIHandler);
-};
-
-#endif  // CHROME_BROWSER_UI_WEBUI_SUGGESTIONS_INTERNALS_SUGGESTIONS_INTERNALS_UI_HANDLER_H_
diff --git a/chrome/browser/unload_browsertest.cc b/chrome/browser/unload_browsertest.cc
index c19dc05..98d5097 100644
--- a/chrome/browser/unload_browsertest.cc
+++ b/chrome/browser/unload_browsertest.cc
@@ -238,15 +238,8 @@
 // Navigate to a page with an infinite beforeunload handler.
 // Then two two sync crosssite requests to ensure
 // we correctly nav to each one.
-// Flaky on Win and Linux; http://crbug.com/462671.
-#if defined(OS_WIN) || defined(OS_LINUX)
-#define MAYBE_CrossSiteInfiniteBeforeUnloadSync \
-    DISABLED_CrossSiteInfiniteBeforeUnloadSync
-#else
-#define MAYBE_CrossSiteInfiniteBeforeUnloadSync \
-    CrossSiteInfiniteBeforeUnloadSync
-#endif
-IN_PROC_BROWSER_TEST_F(UnloadTest, MAYBE_CrossSiteInfiniteBeforeUnloadSync) {
+// Flaky on Win, Linux, and Mac; http://crbug.com/462671.
+IN_PROC_BROWSER_TEST_F(UnloadTest, DISABLED_CrossSiteInfiniteBeforeUnloadSync) {
   // Tests makes no sense in single-process mode since the renderer is hung.
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kSingleProcess))
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 3f20e2d..acc96c7 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -2076,6 +2076,10 @@
       'browser/policy/cloud/cloud_policy_invalidator.h',
       'browser/policy/cloud/policy_header_service_factory.cc',
       'browser/policy/cloud/policy_header_service_factory.h',
+      'browser/policy/cloud/remote_commands_invalidator.cc',
+      'browser/policy/cloud/remote_commands_invalidator.h',
+      'browser/policy/cloud/remote_commands_invalidator_impl.cc',
+      'browser/policy/cloud/remote_commands_invalidator_impl.h',
       'browser/policy/cloud/user_cloud_policy_invalidator.cc',
       'browser/policy/cloud/user_cloud_policy_invalidator.h',
       'browser/policy/cloud/user_cloud_policy_invalidator_factory.cc',
diff --git a/chrome/chrome_browser_chromeos.gypi b/chrome/chrome_browser_chromeos.gypi
index aa01ca0..0c028c80 100644
--- a/chrome/chrome_browser_chromeos.gypi
+++ b/chrome/chrome_browser_chromeos.gypi
@@ -855,6 +855,8 @@
         'browser/chromeos/policy/remote_commands/device_command_screenshot_job.h',
         'browser/chromeos/policy/remote_commands/device_commands_factory_chromeos.cc',
         'browser/chromeos/policy/remote_commands/device_commands_factory_chromeos.h',
+        'browser/chromeos/policy/remote_commands/affiliated_remote_commands_invalidator.cc',
+        'browser/chromeos/policy/remote_commands/affiliated_remote_commands_invalidator.h',
         'browser/chromeos/policy/remote_commands/screenshot_delegate.cc',
         'browser/chromeos/policy/remote_commands/screenshot_delegate.h',
         'browser/chromeos/policy/server_backed_device_state.cc',
diff --git a/chrome/chrome_browser_ui.gypi b/chrome/chrome_browser_ui.gypi
index 9509ee2..c66e42af 100644
--- a/chrome/chrome_browser_ui.gypi
+++ b/chrome/chrome_browser_ui.gypi
@@ -548,6 +548,8 @@
       'browser/ui/ash/ash_keyboard_controller_proxy.h',
       'browser/ui/ash/ash_util.cc',
       'browser/ui/ash/ash_util.h',
+      'browser/ui/ash/cast_config_delegate_chromeos.cc',
+      'browser/ui/ash/cast_config_delegate_chromeos.h',
       'browser/ui/ash/chrome_launcher_prefs.cc',
       'browser/ui/ash/chrome_launcher_prefs.h',
       'browser/ui/ash/chrome_new_window_delegate.cc',
@@ -599,6 +601,8 @@
       'browser/ui/ash/launcher/multi_profile_browser_status_monitor.h',
       'browser/ui/ash/media_delegate_chromeos.cc',
       'browser/ui/ash/media_delegate_chromeos.h',
+      'browser/ui/ash/metrics/chrome_user_metrics_recorder.cc',
+      'browser/ui/ash/metrics/chrome_user_metrics_recorder.h',
       'browser/ui/ash/multi_user/multi_user_context_menu_chromeos.cc',
       'browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos.cc',
       'browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos.h',
@@ -1793,13 +1797,6 @@
       'browser/ui/webui/ntp/ntp_resource_cache_factory.cc',
       'browser/ui/webui/ntp/ntp_resource_cache_factory.h',
       'browser/ui/webui/ntp/ntp_stats.h',
-      'browser/ui/webui/ntp/suggestions_combiner.cc',
-      'browser/ui/webui/ntp/suggestions_combiner.h',
-      'browser/ui/webui/ntp/suggestions_page_handler.cc',
-      'browser/ui/webui/ntp/suggestions_page_handler.h',
-      'browser/ui/webui/ntp/suggestions_source.h',
-      'browser/ui/webui/ntp/suggestions_source_top_sites.cc',
-      'browser/ui/webui/ntp/suggestions_source_top_sites.h',
       'browser/ui/webui/ntp/thumbnail_source.cc',
       'browser/ui/webui/ntp/thumbnail_source.h',
       'browser/ui/webui/options/advanced_options_utils.h',
@@ -1932,10 +1929,6 @@
       'browser/ui/webui/signin/profile_signin_confirmation_dialog.h',
       'browser/ui/webui/signin/profile_signin_confirmation_ui.cc',
       'browser/ui/webui/signin/profile_signin_confirmation_ui.h',
-      'browser/ui/webui/suggestions_internals/suggestions_internals_ui.cc',
-      'browser/ui/webui/suggestions_internals/suggestions_internals_ui.h',
-      'browser/ui/webui/suggestions_internals/suggestions_internals_ui_handler.cc',
-      'browser/ui/webui/suggestions_internals/suggestions_internals_ui_handler.h',
       'browser/ui/webui/sync_file_system_internals/dump_database_handler.cc',
       'browser/ui/webui/sync_file_system_internals/dump_database_handler.h',
       'browser/ui/webui/sync_file_system_internals/extension_statuses_handler.cc',
@@ -3156,7 +3149,7 @@
         }],
         ['enable_media_router==1', {
           'dependencies': [
-              'browser/media/router/media_router.gyp:media_router',
+            'browser/media/router/media_router.gyp:media_router',
           ],
           'sources': [ '<@(chrome_browser_ui_media_router_sources)' ],
         }],
diff --git a/chrome/chrome_renderer.gypi b/chrome/chrome_renderer.gypi
index 9609443..9f618ca 100644
--- a/chrome/chrome_renderer.gypi
+++ b/chrome/chrome_renderer.gypi
@@ -252,6 +252,7 @@
         '../components/components.gyp:content_settings_content_common',
         '../components/components.gyp:cdm_renderer',
         '../components/components.gyp:data_reduction_proxy_content_common',
+        '../components/components.gyp:data_reduction_proxy_core_common',
         '../components/components.gyp:network_hints_renderer',
         '../components/components.gyp:error_page_renderer',
         '../components/components.gyp:startup_metric_utils',
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index fc8c4a5..0291a8f 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -843,7 +843,7 @@
       'browser/ui/app_list/search/webstore/webstore_provider_browsertest.cc',
       'browser/ui/app_list/speech_recognizer_browsertest.cc',
     ],
-    'chrome_browser_tests_media_router_webui_sources': [
+    'chrome_browser_tests_media_router_sources': [
       'browser/ui/webui/media_router/media_router_dialog_controller_browsertest.cc',
     ],
     # Javascript sources. These are combined with the .cc files in the GYP build
@@ -2246,7 +2246,8 @@
          ],
         }],
         ['enable_media_router==1', {
-          'sources': [ '<@(chrome_browser_tests_media_router_webui_sources)' ],
+          'sources': [ '<@(chrome_browser_tests_media_router_sources)' ],
+          'dependencies': [ 'browser/media/router/media_router.gyp:media_router_test_support' ],
         }],
         ['OS=="win"', {
           'sources': [
diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi
index e800ea2..2e5c92a2 100644
--- a/chrome/chrome_tests_unit.gypi
+++ b/chrome/chrome_tests_unit.gypi
@@ -970,6 +970,7 @@
     'chrome_unit_tests_configuration_policy_sources': [
       'browser/net/proxy_policy_handler_unittest.cc',
       'browser/policy/cloud/cloud_policy_invalidator_unittest.cc',
+      'browser/policy/cloud/remote_commands_invalidator_unittest.cc',
       'browser/policy/cloud/user_policy_signin_service_unittest.cc',
       'browser/policy/file_selection_dialogs_policy_handler_unittest.cc',
       'browser/policy/javascript_policy_handler_unittest.cc',
@@ -1419,6 +1420,21 @@
       'browser/supervised_user/supervised_user_url_filter_unittest.cc',
       'browser/supervised_user/supervised_user_whitelist_service_unittest.cc',
     ],
+    'chrome_unit_tests_media_router_sources': [
+      'browser/media/router/issue_manager_unittest.cc',
+      'browser/media/router/issue_unittest.cc',
+      'browser/media/router/media_router_type_converters_unittest.cc',
+      'browser/media/router/media_route_unittest.cc',
+      'browser/media/router/media_sink_unittest.cc',
+      '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/ui/webui/media_router/media_cast_mode_unittest.cc',
+      'browser/ui/webui/media_router/media_router_dialog_controller_unittest.cc',
+      'browser/ui/webui/media_router/media_router_test.cc',
+      'browser/ui/webui/media_router/media_router_test.h',
+      'browser/ui/webui/media_router/query_result_manager_unittest.cc',
+    ],
     # Everything but Android and iOS (iOS is handled separately).
     'chrome_unit_tests_non_android_sources': [
       # Bookmark export/import are handled via the BookmarkColumns
@@ -1522,10 +1538,7 @@
       'browser/ui/toolbar/wrench_menu_model_unittest.cc',
       'browser/ui/website_settings/permission_menu_model_unittest.cc',
       'browser/ui/webui/help/version_updater_chromeos_unittest.cc',
-      'browser/ui/webui/media_router/media_cast_mode_unittest.cc',
-      'browser/ui/webui/media_router/query_result_manager_unittest.cc',
       'browser/ui/webui/ntp/ntp_user_data_logger_unittest.cc',
-      'browser/ui/webui/ntp/suggestions_combiner_unittest.cc',
       'browser/ui/webui/options/autofill_options_handler_unittest.cc',
       'browser/ui/webui/options/language_options_handler_unittest.cc',
       'browser/ui/webui/options/pepper_flash_content_settings_utils_unittest.cc',
@@ -2349,9 +2362,8 @@
           'sources': [ '<@(chrome_unit_tests_print_preview_sources)' ],
         }],
         ['enable_media_router==1', {
-          'includes': [
-            'browser/media/router/media_router_tests.gypi',
-          ],
+          'sources': [ '<@(chrome_unit_tests_media_router_sources)' ],
+          'dependencies': [ 'browser/media/router/media_router.gyp:media_router_test_support' ],
         }],
         ['enable_captive_portal_detection==1', {
           'sources': [ '<@(chrome_unit_tests_captive_portal_sources)' ],
diff --git a/chrome/common/BUILD.gn b/chrome/common/BUILD.gn
index b3726f9..4378b37a 100644
--- a/chrome/common/BUILD.gn
+++ b/chrome/common/BUILD.gn
@@ -110,9 +110,6 @@
       "//extensions/strings",
       "//media/cast:net",
     ]
-    if (enable_media_router) {
-      defines += [ "ENABLE_MEDIA_ROUTER=1" ]
-    }
     if (is_chromeos) {
       sources +=
           rebase_path(gypi_values.chrome_common_extensions_chromeos_sources,
@@ -243,9 +240,6 @@
                            ".",
                            "//chrome")
   }
-  if (enable_media_router) {
-    defines += [ "ENABLE_MEDIA_ROUTER=1" ]
-  }
 }
 
 import("//chrome/version.gni")
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index e8d60b3..86f222f 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -291,6 +291,9 @@
 const char kDisableOfflineAutoReloadVisibleOnly[] =
     "disable-offline-auto-reload-visible-only";
 
+// Disable out-of-process V8 proxy resolver.
+const char kDisableOutOfProcessPac[] = "disable-out-of-process-pac";
+
 // Disable the setting to prompt the user for their OS account password before
 // revealing plaintext passwords in the password manager.
 const char kDisablePasswordManagerReauthentication[] =
@@ -319,10 +322,6 @@
 // Disables support for the QUIC protocol.
 const char kDisableQuic[]                   = "disable-quic";
 
-// Disable use of pacing of QUIC packets.
-// This only has an effect if QUIC protocol is enabled.
-const char kDisableQuicPacing[]             = "disable-quic-pacing";
-
 // Disable use of Chromium's port selection for the ephemeral port via bind().
 // This only has an effect if QUIC protocol is enabled.
 const char kDisableQuicPortSelection[]      = "disable-quic-port-selection";
@@ -511,10 +510,6 @@
 // Enables support for the QUIC protocol.  This is a temporary testing flag.
 const char kEnableQuic[]                    = "enable-quic";
 
-// Disable use of pacing of QUIC packets.
-// This only has an effect if QUIC protocol is enabled.
-const char kEnableQuicPacing[]              = "enable-quic-pacing";
-
 // Enable use of Chromium's port selection for the ephemeral port via bind().
 // This only has an effect if QUIC protocol is enabled.
 const char kEnableQuicPortSelection[]       = "enable-quic-port-selection";
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index 709f6da6..0af2b1b09 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -86,6 +86,7 @@
 extern const char kDisableNTPOtherSessionsMenu[];
 extern const char kDisableOfflineAutoReload[];
 extern const char kDisableOfflineAutoReloadVisibleOnly[];
+extern const char kDisableOutOfProcessPac[];
 extern const char kDisablePasswordManagerReauthentication[];
 extern const char kDisablePdfMaterialUI[];
 extern const char kDisablePermissionsBubbles[];
@@ -94,7 +95,6 @@
 extern const char kDisablePrintPreview[];
 extern const char kDisablePromptOnRepost[];
 extern const char kDisableQuic[];
-extern const char kDisableQuicPacing[];
 extern const char kDisableQuicPortSelection[];
 extern const char kDisableSavePasswordBubble[];
 extern const char kDisableSdchPersistence[];
@@ -148,7 +148,6 @@
 extern const char kEnableProfiling[];
 extern const char kEnableQueryExtraction[];
 extern const char kEnableQuic[];
-extern const char kEnableQuicPacing[];
 extern const char kEnableQuicPortSelection[];
 extern const char kEnableSavePasswordBubble[];
 extern const char kEnableSdchPersistence[];
diff --git a/chrome/common/extensions/api/_api_features.json b/chrome/common/extensions/api/_api_features.json
index 883b32de..e24ff6d 100644
--- a/chrome/common/extensions/api/_api_features.json
+++ b/chrome/common/extensions/api/_api_features.json
@@ -508,6 +508,7 @@
     "contexts": ["blessed_extension"]
   },
   "instanceID": {
+    "channel": "dev",
     "dependencies": ["permission:gcm"],
     "contexts": ["blessed_extension"]
   },
diff --git a/chrome/common/extensions/api/file_manager_private.idl b/chrome/common/extensions/api/file_manager_private.idl
index 64295c78..683f56d 100644
--- a/chrome/common/extensions/api/file_manager_private.idl
+++ b/chrome/common/extensions/api/file_manager_private.idl
@@ -174,6 +174,14 @@
   public
 };
 
+// Source of the volume data.
+enum Source {
+  file,
+  device,
+  network,
+  system
+};
+
 // A file task represents an action that the file manager can perform over the
 // currently selected files. See
 // chrome/browser/chromeos/extensions/file_manager/file_tasks.h for details
@@ -290,6 +298,9 @@
   // Extension providing this volume (for provided file systems).
   DOMString? extensionId;
 
+  // Source of the volume's data.
+  Source source;
+
   // Label of the volume (if available).
   DOMString? volumeLabel;
 
@@ -320,6 +331,9 @@
   // Flag that specifies whether the volume contains media.
   boolean hasMedia;
 
+  // Flag that specifies whether the volume is configurable.
+  boolean configurable;
+
   // Additional data about mount, for example, that the filesystem is not
   // supported.
   MountCondition? mountCondition;
@@ -905,10 +919,9 @@
   static void addProvidedFileSystem(DOMString extension_id,
                                     SimpleCallback callback);
 
-  // Requests configuring an existing file system. If not possible, then returns
+  // Requests configuring an existing volume. If not possible, then returns
   // an error via chrome.runtime.lastError.
-  static void configureProvidedFileSystem(DOMString volumeId,
-                                          SimpleCallback callback);
+  static void configureVolume(DOMString volumeId, SimpleCallback callback);
 };
 
 interface Events {
diff --git a/chrome/common/extensions/api/launcher_page.idl b/chrome/common/extensions/api/launcher_page.idl
index a6a1943d..7e7896a8 100644
--- a/chrome/common/extensions/api/launcher_page.idl
+++ b/chrome/common/extensions/api/launcher_page.idl
@@ -7,6 +7,7 @@
 namespace launcherPage {
   callback PushSubpageCallback = void();
   callback ShowCallback = void();
+  callback HideCallback = void();
   callback SetEnabledCallback = void();
 
   interface Functions {
@@ -24,6 +25,9 @@
     // page.
     static void show(optional ShowCallback callback);
 
+    // Returns the launcher to the start page if the launcher page is showing.
+    static void hide(optional HideCallback callback);
+
     // Sets whether the launcher page is enabled in the launcher. If disabled,
     // the launcher page will not be shown when the area at the bottom of the
     // launcher is pressed.
diff --git a/chrome/common/logging_chrome.cc b/chrome/common/logging_chrome.cc
index 7d26587..c8458ef9 100644
--- a/chrome/common/logging_chrome.cc
+++ b/chrome/common/logging_chrome.cc
@@ -333,14 +333,19 @@
       command_line.HasSwitch(switches::kNoErrorDialogs))
     SuppressDialogs();
 
-  // Use a minimum log level if the command line asks for one,
-  // otherwise leave it at the default level (INFO).
-  if (command_line.HasSwitch(switches::kLoggingLevel)) {
-    std::string log_level = command_line.GetSwitchValueASCII(
-        switches::kLoggingLevel);
+  // Use a minimum log level if the command line asks for one. Ignore this
+  // switch if there's vlog level switch present too (as both of these switches
+  // refer to the same underlying log level, and the vlog level switch has
+  // already been processed inside logging::InitLogging). If there is neither
+  // log level nor vlog level specified, then just leave the default level
+  // (INFO).
+  if (command_line.HasSwitch(switches::kLoggingLevel) &&
+      logging::GetMinLogLevel() >= 0) {
+    std::string log_level =
+        command_line.GetSwitchValueASCII(switches::kLoggingLevel);
     int level = 0;
-    if (base::StringToInt(log_level, &level) &&
-        level >= 0 && level < LOG_NUM_SEVERITIES) {
+    if (base::StringToInt(log_level, &level) && level >= 0 &&
+        level < LOG_NUM_SEVERITIES) {
       logging::SetMinLogLevel(level);
     } else {
       DLOG(WARNING) << "Bad log level: " << log_level;
diff --git a/chrome/common/render_messages.h b/chrome/common/render_messages.h
index 287b47e..fc9eb17 100644
--- a/chrome/common/render_messages.h
+++ b/chrome/common/render_messages.h
@@ -292,6 +292,10 @@
 IPC_MESSAGE_ROUTED1(ChromeViewMsg_SetClientSidePhishingDetection,
                     bool /* enable_phishing_detection */)
 
+// Reloads the image selected by the most recently opened context menu
+// (if there indeed is an image at that location).
+IPC_MESSAGE_ROUTED0(ChromeViewMsg_RequestReloadImageForContextNode)
+
 // Asks the renderer for a thumbnail of the image selected by the most
 // recently opened context menu, if there is one. If the image's area
 // is greater than thumbnail_min_area it will be downscaled to
diff --git a/chrome/common/url_constants.cc b/chrome/common/url_constants.cc
index 72c4d66..01e5949 100644
--- a/chrome/common/url_constants.cc
+++ b/chrome/common/url_constants.cc
@@ -76,8 +76,6 @@
 const char kChromeUIContentSettingsURL[] = "chrome://settings/content";
 const char kChromeUISettingsFrameURL[] = "chrome://settings-frame/";
 const char kChromeUISuggestionsURL[] = "chrome://suggestions/";
-const char kChromeUISuggestionsInternalsURL[] =
-    "chrome://suggestions-internals/";
 const char kChromeUISupervisedUserPassphrasePageURL[] =
     "chrome://managed-user-passphrase/";
 const char kChromeUITermsURL[] = "chrome://terms/";
@@ -229,7 +227,6 @@
 const char kChromeUIShorthangHost[] = "shorthang";
 const char kChromeUISignInInternalsHost[] = "signin-internals";
 const char kChromeUISuggestionsHost[] = "suggestions";
-const char kChromeUISuggestionsInternalsHost[] = "suggestions-internals";
 const char kChromeUISupervisedUserPassphrasePageHost[] =
     "managed-user-passphrase";
 const char kChromeUISyncHost[] = "sync";
@@ -573,8 +570,7 @@
 #endif
 
 const char kRemoveNonCWSExtensionURL[] =
-    "https://support.google.com/chrome/answer/2811969?"
-    "p=ui_remove_non_cws_extensions&rd=1";
+    "https://support.google.com/chrome/?p=ui_remove_non_cws_extensions";
 
 #if defined(OS_WIN)
 const char kNotificationsHelpURL[] =
diff --git a/chrome/common/url_constants.h b/chrome/common/url_constants.h
index 36163c2..90960f5 100644
--- a/chrome/common/url_constants.h
+++ b/chrome/common/url_constants.h
@@ -72,7 +72,6 @@
 extern const char kChromeUIContentSettingsURL[];
 extern const char kChromeUISettingsFrameURL[];
 extern const char kChromeUISuggestionsURL[];
-extern const char kChromeUISuggestionsInternalsURL[];
 extern const char kChromeUISupervisedUserPassphrasePageURL[];
 extern const char kChromeUITermsURL[];
 extern const char kChromeUIThemeURL[];
@@ -216,7 +215,6 @@
 extern const char kChromeUIShorthangHost[];
 extern const char kChromeUISignInInternalsHost[];
 extern const char kChromeUISuggestionsHost[];
-extern const char kChromeUISuggestionsInternalsHost[];
 extern const char kChromeUISupervisedUserPassphrasePageHost[];
 extern const char kChromeUISyncHost[];
 extern const char kChromeUISyncFileSystemInternalsHost[];
diff --git a/chrome/installer/linux/rpm/expected_deps_x86_64 b/chrome/installer/linux/rpm/expected_deps_x86_64
index 1b5cd370..f7085e2 100644
--- a/chrome/installer/linux/rpm/expected_deps_x86_64
+++ b/chrome/installer/linux/rpm/expected_deps_x86_64
@@ -20,6 +20,7 @@
 libfontconfig.so.1()(64bit)
 libfreetype.so.6()(64bit)
 libgcc_s.so.1()(64bit)
+libgcc_s.so.1(GCC_3.0)(64bit)
 libgcc_s.so.1(GCC_4.0.0)(64bit)
 libgconf-2.so.4()(64bit)
 libgdk_pixbuf-2.0.so.0()(64bit)
diff --git a/chrome/renderer/BUILD.gn b/chrome/renderer/BUILD.gn
index cd1cb304..e5857448 100644
--- a/chrome/renderer/BUILD.gn
+++ b/chrome/renderer/BUILD.gn
@@ -39,6 +39,7 @@
     "//components/content_settings/content/common",
     "//components/cdm/renderer",
     "//components/data_reduction_proxy/content/common",
+    "//components/data_reduction_proxy/core/common",
     "//components/network_hints/renderer",
     "//components/error_page/renderer",
     "//components/password_manager/content/renderer",
diff --git a/chrome/renderer/DEPS b/chrome/renderer/DEPS
index 2dbacc1..cd2cd8e3 100644
--- a/chrome/renderer/DEPS
+++ b/chrome/renderer/DEPS
@@ -9,6 +9,7 @@
   "+components/content_settings/core/common",
   "+components/crx_file",
   "+components/data_reduction_proxy/content/common",
+  "+components/data_reduction_proxy/core/common",
   "+components/dom_distiller/core",
   "+components/nacl/common",
   "+components/nacl/renderer",
diff --git a/chrome/renderer/autofill/autofill_renderer_browsertest.cc b/chrome/renderer/autofill/autofill_renderer_browsertest.cc
index e6f4ec1..a8a8301 100644
--- a/chrome/renderer/autofill/autofill_renderer_browsertest.cc
+++ b/chrome/renderer/autofill/autofill_renderer_browsertest.cc
@@ -258,6 +258,7 @@
     GetMainFrame()->view()->advanceFocus(false);
 
   // Not a user gesture, so no IPC message to browser.
+  DisableUserGestureSimulationForAutofill();
   full_name.setValue("Alice", true);
   GetMainFrame()->toWebLocalFrame()->autofillClient()->textFieldDidChange(
       full_name);
@@ -266,6 +267,7 @@
                          AutofillHostMsg_TextFieldDidChange::ID));
 
   // A user gesture will send a message to the browser.
+  EnableUserGestureSimulationForAutofill();
   SimulateUserInputChangeForElement(&full_name, "Alice");
   ASSERT_NE(nullptr, render_thread_->sink().GetFirstMessageMatching(
                          AutofillHostMsg_TextFieldDidChange::ID));
diff --git a/chrome/renderer/chrome_content_renderer_client.cc b/chrome/renderer/chrome_content_renderer_client.cc
index 8e92dfc..7613f47 100644
--- a/chrome/renderer/chrome_content_renderer_client.cc
+++ b/chrome/renderer/chrome_content_renderer_client.cc
@@ -59,6 +59,7 @@
 #include "components/autofill/content/renderer/password_autofill_agent.h"
 #include "components/autofill/content/renderer/password_generation_agent.h"
 #include "components/content_settings/core/common/content_settings_pattern.h"
+#include "components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h"
 #include "components/dom_distiller/core/url_constants.h"
 #include "components/nacl/renderer/ppb_nacl_private.h"
 #include "components/nacl/renderer/ppb_nacl_private_impl.h"
@@ -83,6 +84,7 @@
 #include "third_party/WebKit/public/platform/WebURL.h"
 #include "third_party/WebKit/public/platform/WebURLError.h"
 #include "third_party/WebKit/public/platform/WebURLRequest.h"
+#include "third_party/WebKit/public/platform/WebURLResponse.h"
 #include "third_party/WebKit/public/web/WebCache.h"
 #include "third_party/WebKit/public/web/WebDataSource.h"
 #include "third_party/WebKit/public/web/WebDocument.h"
@@ -1653,3 +1655,18 @@
   return scoped_ptr<blink::WebAppBannerClient>(
       new AppBannerClient(render_frame));
 }
+
+void ChromeContentRendererClient::AddImageContextMenuProperties(
+    const blink::WebURLResponse& response,
+    std::map<std::string, std::string>* properties) {
+  DCHECK(properties);
+  WebString header_key(ASCIIToUTF16(
+      data_reduction_proxy::chrome_proxy_header()));
+  if (!response.httpHeaderField(header_key).isNull() &&
+      response.httpHeaderField(header_key).utf8().find(
+          data_reduction_proxy::chrome_proxy_lo_fi_directive()) !=
+              std::string::npos) {
+    (*properties)[data_reduction_proxy::chrome_proxy_header()] =
+        data_reduction_proxy::chrome_proxy_lo_fi_directive();
+  }
+}
diff --git a/chrome/renderer/chrome_content_renderer_client.h b/chrome/renderer/chrome_content_renderer_client.h
index ca206a1f..764edae9 100644
--- a/chrome/renderer/chrome_content_renderer_client.h
+++ b/chrome/renderer/chrome_content_renderer_client.h
@@ -5,6 +5,7 @@
 #ifndef CHROME_RENDERER_CHROME_CONTENT_RENDERER_CLIENT_H_
 #define CHROME_RENDERER_CHROME_CONTENT_RENDERER_CLIENT_H_
 
+#include <map>
 #include <set>
 #include <string>
 #include <vector>
@@ -150,6 +151,9 @@
   void RecordRapporURL(const std::string& metric, const GURL& url) override;
   scoped_ptr<blink::WebAppBannerClient> CreateAppBannerClient(
       content::RenderFrame* render_frame) override;
+  void AddImageContextMenuProperties(
+      const blink::WebURLResponse& response,
+      std::map<std::string, std::string>* properties) override;
 
 #if defined(ENABLE_EXTENSIONS)
   // Takes ownership.
diff --git a/chrome/renderer/chrome_render_frame_observer.cc b/chrome/renderer/chrome_render_frame_observer.cc
index 1518bf6..9921dcc 100644
--- a/chrome/renderer/chrome_render_frame_observer.cc
+++ b/chrome/renderer/chrome_render_frame_observer.cc
@@ -94,6 +94,8 @@
     return false;
 
   IPC_BEGIN_MESSAGE_MAP(ChromeRenderFrameObserver, message)
+    IPC_MESSAGE_HANDLER(ChromeViewMsg_RequestReloadImageForContextNode,
+                        OnRequestReloadImageForContextNode)
     IPC_MESSAGE_HANDLER(ChromeViewMsg_RequestThumbnailForContextNode,
                         OnRequestThumbnailForContextNode)
     IPC_MESSAGE_HANDLER(PrintMsg_PrintNodeUnderContextMenu,
@@ -123,6 +125,14 @@
   }
 }
 
+void ChromeRenderFrameObserver::OnRequestReloadImageForContextNode() {
+  WebNode context_node = render_frame()->GetContextMenuNode();
+  if (!context_node.isNull() && context_node.isElementNode() &&
+      render_frame()->GetWebFrame()) {
+    render_frame()->GetWebFrame()->reloadImage(context_node);
+  }
+}
+
 void ChromeRenderFrameObserver::OnRequestThumbnailForContextNode(
     int thumbnail_min_area_pixels,
     const gfx::Size& thumbnail_max_size_pixels) {
diff --git a/chrome/renderer/chrome_render_frame_observer.h b/chrome/renderer/chrome_render_frame_observer.h
index 83cce6a..1534895 100644
--- a/chrome/renderer/chrome_render_frame_observer.h
+++ b/chrome/renderer/chrome_render_frame_observer.h
@@ -26,6 +26,7 @@
 
   // IPC handlers
   void OnSetIsPrerendering(bool is_prerendering);
+  void OnRequestReloadImageForContextNode();
   void OnRequestThumbnailForContextNode(
       int thumbnail_min_area_pixels,
       const gfx::Size& thumbnail_max_size_pixels);
diff --git a/chrome/renderer/extensions/renderer_permissions_policy_delegate.cc b/chrome/renderer/extensions/renderer_permissions_policy_delegate.cc
index dabf649..58b1ed1 100644
--- a/chrome/renderer/extensions/renderer_permissions_policy_delegate.cc
+++ b/chrome/renderer/extensions/renderer_permissions_policy_delegate.cc
@@ -30,12 +30,8 @@
     int tab_id,
     int process_id,
     std::string* error) {
-  const ExtensionsClient::ScriptingWhitelist& whitelist =
-      ExtensionsClient::Get()->GetScriptingWhitelist();
-  if (std::find(whitelist.begin(), whitelist.end(), extension->id()) !=
-      whitelist.end()) {
+  if (PermissionsData::CanExecuteScriptEverywhere(extension))
     return true;
-  }
 
   if (dispatcher_->IsExtensionActive(kWebStoreAppId)) {
     if (error)
diff --git a/chrome/renderer/net/net_error_helper.cc b/chrome/renderer/net/net_error_helper.cc
index 00c2964..a3ab4e55 100644
--- a/chrome/renderer/net/net_error_helper.cc
+++ b/chrome/renderer/net/net_error_helper.cc
@@ -230,7 +230,7 @@
                              &error_strings);
 
   std::string json;
-  JSONWriter::Write(&error_strings, &json);
+  JSONWriter::Write(error_strings, &json);
 
   std::string js = "if (window.updateForDnsProbe) "
                    "updateForDnsProbe(" + json + ");";
diff --git a/chrome/service/cloud_print/print_system_win.cc b/chrome/service/cloud_print/print_system_win.cc
index ac090c2..550a5633 100644
--- a/chrome/service/cloud_print/print_system_win.cc
+++ b/chrome/service/cloud_print/print_system_win.cc
@@ -545,7 +545,7 @@
           PrinterSemanticCapsAndDefaultsToCdd(semantic_info));
       if (description) {
         base::JSONWriter::WriteWithOptions(
-            description.get(), base::JSONWriter::OPTIONS_PRETTY_PRINT,
+            *description, base::JSONWriter::OPTIONS_PRETTY_PRINT,
             &printer_info.printer_capabilities);
       }
     }
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 65cf46cf..83e07bb9 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -854,9 +854,10 @@
     }
     if (enable_media_router) {
       sources += rebase_path(
-              chrome_tests_gypi_values.chrome_browser_tests_media_router_webui_sources,
+              chrome_tests_gypi_values.chrome_browser_tests_media_router_sources,
               ".",
               "//chrome")
+      deps += [ "//chrome/browser/media/router:test_support" ]
     }
     if (is_win) {
       deps += [
@@ -1283,7 +1284,6 @@
                       ".",
                       "//chrome")
     }
-
     if (is_ios || is_chromeos) {
       sources -=
           [ "../browser/metrics/signin_status_metrics_provider_unittest.cc" ]
@@ -1490,14 +1490,18 @@
               ".",
               "//chrome")
     }
+    if (enable_media_router) {
+      sources +=
+          rebase_path(unit_gypi_values.chrome_unit_tests_media_router_sources,
+                      ".",
+                      "//chrome")
+      deps += [ "//chrome/browser/media/router:test_support" ]
+    }
     if (enable_webrtc) {
       sources += rebase_path(unit_gypi_values.chrome_unit_tests_webrtc_sources,
                              ".",
                              "//chrome")
     }
-    if (enable_media_router) {
-      deps += [ "//chrome/browser/media/router:unit_tests" ]
-    }
     if (is_chromeos) {
       sources +=
           rebase_path(unit_gypi_values.chrome_unit_tests_chromeos_sources,
@@ -1739,6 +1743,7 @@
         "//chrome/browser",
         "//chrome/renderer",
         "//media/cast:test_support",
+        "//testing/gmock",
         "//testing/gtest",
         "//testing/perf",
       ]
diff --git a/chrome/test/base/chrome_render_view_test.cc b/chrome/test/base/chrome_render_view_test.cc
index 4f47f69..d968e0c6 100644
--- a/chrome/test/base/chrome_render_view_test.cc
+++ b/chrome/test/base/chrome_render_view_test.cc
@@ -18,6 +18,7 @@
 #include "content/public/browser/native_web_keyboard_event.h"
 #include "content/public/common/renderer_preferences.h"
 #include "content/public/renderer/render_view.h"
+#include "testing/gmock/include/gmock/gmock.h"
 #include "third_party/WebKit/public/platform/WebURLRequest.h"
 #include "third_party/WebKit/public/web/WebFrame.h"
 #include "third_party/WebKit/public/web/WebInputEvent.h"
@@ -44,6 +45,34 @@
 using blink::WebScriptSource;
 using blink::WebString;
 using blink::WebURLRequest;
+using content::RenderFrame;
+using testing::NiceMock;
+using testing::Return;
+using testing::_;
+
+namespace {
+
+// An autofill agent that treats all typing as user gesture.
+class MockAutofillAgent : public AutofillAgent {
+ public:
+  MockAutofillAgent(RenderFrame* render_frame,
+                    PasswordAutofillAgent* password_autofill_agent,
+                    PasswordGenerationAgent* password_generation_agent)
+      : AutofillAgent(render_frame,
+                      password_autofill_agent,
+                      password_generation_agent) {
+    ON_CALL(*this, IsUserGesture()).WillByDefault(Return(true));
+  }
+
+  ~MockAutofillAgent() override {}
+
+  MOCK_CONST_METHOD0(IsUserGesture, bool());
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MockAutofillAgent);
+};
+
+}  // namespace
 
 ChromeRenderViewTest::ChromeRenderViewTest()
     : password_autofill_agent_(NULL),
@@ -71,9 +100,9 @@
       new autofill::TestPasswordAutofillAgent(view_->GetMainRenderFrame());
   password_generation_ =
       new autofill::TestPasswordGenerationAgent(view_->GetMainRenderFrame());
-  autofill_agent_ =
-      new AutofillAgent(view_->GetMainRenderFrame(), password_autofill_agent_,
-                        password_generation_);
+  autofill_agent_ = new NiceMock<MockAutofillAgent>(view_->GetMainRenderFrame(),
+                                                    password_autofill_agent_,
+                                                    password_generation_);
 }
 
 void ChromeRenderViewTest::TearDown() {
@@ -96,12 +125,12 @@
 }
 
 content::ContentBrowserClient*
-    ChromeRenderViewTest::CreateContentBrowserClient() {
+ChromeRenderViewTest::CreateContentBrowserClient() {
   return new chrome::ChromeContentBrowserClient();
 }
 
 content::ContentRendererClient*
-    ChromeRenderViewTest::CreateContentRendererClient() {
+ChromeRenderViewTest::CreateContentRendererClient() {
   ChromeContentRendererClient* client = new ChromeContentRendererClient();
 #if defined(ENABLE_EXTENSIONS)
   extension_dispatcher_delegate_.reset(
@@ -114,3 +143,13 @@
 #endif
   return client;
 }
+
+void ChromeRenderViewTest::EnableUserGestureSimulationForAutofill() {
+  EXPECT_CALL(*(static_cast<MockAutofillAgent*>(autofill_agent_)),
+              IsUserGesture()).WillRepeatedly(Return(true));
+}
+
+void ChromeRenderViewTest::DisableUserGestureSimulationForAutofill() {
+  EXPECT_CALL(*(static_cast<MockAutofillAgent*>(autofill_agent_)),
+              IsUserGesture()).WillRepeatedly(Return(false));
+}
diff --git a/chrome/test/base/chrome_render_view_test.h b/chrome/test/base/chrome_render_view_test.h
index c2e06a7c..154a9fd 100644
--- a/chrome/test/base/chrome_render_view_test.h
+++ b/chrome/test/base/chrome_render_view_test.h
@@ -34,6 +34,9 @@
   content::ContentBrowserClient* CreateContentBrowserClient() override;
   content::ContentRendererClient* CreateContentRendererClient() override;
 
+  void EnableUserGestureSimulationForAutofill();
+  void DisableUserGestureSimulationForAutofill();
+
 #if defined(ENABLE_EXTENSIONS)
   scoped_ptr<extensions::DispatcherDelegate> extension_dispatcher_delegate_;
 #endif
diff --git a/chrome/test/chromedriver/chrome/console_logger.cc b/chrome/test/chromedriver/chrome/console_logger.cc
index 9300e63..d5557024 100644
--- a/chrome/test/chromedriver/chrome/console_logger.cc
+++ b/chrome/test/chromedriver/chrome/console_logger.cc
@@ -93,7 +93,7 @@
 
   // Don't know how to format, log full JSON.
   std::string message_json;
-  base::JSONWriter::Write(&params, &message_json);
+  base::JSONWriter::Write(params, &message_json);
   log_->AddEntry(Log::kWarning, message_json);
   return Status(kOk);
 }
diff --git a/chrome/test/chromedriver/chrome/devtools_client_impl.cc b/chrome/test/chromedriver/chrome/devtools_client_impl.cc
index 4992c80..56da77b36 100644
--- a/chrome/test/chromedriver/chrome/devtools_client_impl.cc
+++ b/chrome/test/chromedriver/chrome/devtools_client_impl.cc
@@ -496,7 +496,7 @@
     if (message_dict->GetDictionary("result", &unscoped_result))
       command_response->result.reset(unscoped_result->DeepCopy());
     else if (message_dict->GetDictionary("error", &unscoped_error))
-      base::JSONWriter::Write(unscoped_error, &command_response->error);
+      base::JSONWriter::Write(*unscoped_error, &command_response->error);
     else
       command_response->result.reset(new base::DictionaryValue());
     return true;
diff --git a/chrome/test/chromedriver/chrome/devtools_client_impl_unittest.cc b/chrome/test/chromedriver/chrome/devtools_client_impl_unittest.cc
index 158caf3..4a0a4b00 100644
--- a/chrome/test/chromedriver/chrome/devtools_client_impl_unittest.cc
+++ b/chrome/test/chromedriver/chrome/devtools_client_impl_unittest.cc
@@ -70,7 +70,7 @@
     base::DictionaryValue result;
     result.SetInteger("param", 1);
     response.Set("result", result.DeepCopy());
-    base::JSONWriter::Write(&response, message);
+    base::JSONWriter::Write(response, message);
     --queued_messages_;
     return SyncWebSocket::kOk;
   }
@@ -120,7 +120,7 @@
   Status status = client.SendCommandAndGetResult("method", params, &result);
   ASSERT_EQ(kOk, status.code());
   std::string json;
-  base::JSONWriter::Write(result.get(), &json);
+  base::JSONWriter::Write(*result, &json);
   ASSERT_STREQ("{\"param\":1}", json.c_str());
 }
 
@@ -725,7 +725,7 @@
     response.SetInteger("id", id);
     response.Set("result", new base::DictionaryValue());
     std::string json_response;
-    base::JSONWriter::Write(&response, &json_response);
+    base::JSONWriter::Write(response, &json_response);
     queued_response_.push_back(json_response);
 
     // Push one event.
@@ -733,7 +733,7 @@
     event.SetString("method", "updateEvent");
     event.Set("params", new base::DictionaryValue());
     std::string json_event;
-    base::JSONWriter::Write(&event, &json_event);
+    base::JSONWriter::Write(event, &json_event);
     queued_response_.push_back(json_event);
 
     return true;
diff --git a/chrome/test/chromedriver/chrome/dom_tracker.cc b/chrome/test/chromedriver/chrome/dom_tracker.cc
index 40f2f88..5f5fbcb 100644
--- a/chrome/test/chromedriver/chrome/dom_tracker.cc
+++ b/chrome/test/chromedriver/chrome/dom_tracker.cc
@@ -43,7 +43,7 @@
 
     if (!ProcessNodeList(nodes)) {
       std::string json;
-      base::JSONWriter::Write(nodes, &json);
+      base::JSONWriter::Write(*nodes, &json);
       return Status(kUnknownError,
                     "DOM.setChildNodes has invalid 'nodes': " + json);
     }
@@ -54,7 +54,7 @@
 
     if (!ProcessNode(node)) {
       std::string json;
-      base::JSONWriter::Write(node, &json);
+      base::JSONWriter::Write(*node, &json);
       return Status(kUnknownError,
                     "DOM.childNodeInserted has invalid 'node': " + json);
     }
diff --git a/chrome/test/chromedriver/chrome/frame_tracker.cc b/chrome/test/chromedriver/chrome/frame_tracker.cc
index c18b948e..c87e0d8 100644
--- a/chrome/test/chromedriver/chrome/frame_tracker.cc
+++ b/chrome/test/chromedriver/chrome/frame_tracker.cc
@@ -52,7 +52,7 @@
     if (!context->GetInteger("id", &context_id) ||
         !context->GetString("frameId", &frame_id)) {
       std::string json;
-      base::JSONWriter::Write(context, &json);
+      base::JSONWriter::Write(*context, &json);
       return Status(
           kUnknownError,
           "Runtime.executionContextCreated has invalid 'context': " + json);
diff --git a/chrome/test/chromedriver/chrome/log.cc b/chrome/test/chromedriver/chrome/log.cc
index a40f9b2..ed1190a 100644
--- a/chrome/test/chromedriver/chrome/log.cc
+++ b/chrome/test/chromedriver/chrome/log.cc
@@ -85,7 +85,7 @@
 std::string PrettyPrintValue(const base::Value& value) {
   std::string json;
   base::JSONWriter::WriteWithOptions(
-      &value, base::JSONWriter::OPTIONS_PRETTY_PRINT, &json);
+      value, base::JSONWriter::OPTIONS_PRETTY_PRINT, &json);
 #if defined(OS_WIN)
   base::RemoveChars(json, "\r", &json);
 #endif
diff --git a/chrome/test/chromedriver/chrome/util.cc b/chrome/test/chromedriver/chrome/util.cc
index b7f1a5cd..02206f3 100644
--- a/chrome/test/chromedriver/chrome/util.cc
+++ b/chrome/test/chromedriver/chrome/util.cc
@@ -9,6 +9,6 @@
 
 std::string SerializeValue(const base::Value* value) {
   std::string json;
-  base::JSONWriter::Write(value, &json);
+  base::JSONWriter::Write(*value, &json);
   return json;
 }
diff --git a/chrome/test/chromedriver/chrome/web_view_impl.cc b/chrome/test/chromedriver/chrome/web_view_impl.cc
index c9cce52..9febe2b7 100644
--- a/chrome/test/chromedriver/chrome/web_view_impl.cc
+++ b/chrome/test/chromedriver/chrome/web_view_impl.cc
@@ -237,7 +237,7 @@
                                  const base::ListValue& args,
                                  scoped_ptr<base::Value>* result) {
   std::string json;
-  base::JSONWriter::Write(&args, &json);
+  base::JSONWriter::Write(args, &json);
   // TODO(zachconrad): Second null should be array of shadow host ids.
   std::string expression = base::StringPrintf(
       "(%s).apply(null, [null, %s, %s])",
@@ -763,7 +763,7 @@
                              bool* found_node,
                              int* node_id) {
   std::string json;
-  base::JSONWriter::Write(&args, &json);
+  base::JSONWriter::Write(args, &json);
   // TODO(zachconrad): Second null should be array of shadow host ids.
   std::string expression = base::StringPrintf(
       "(%s).apply(null, [null, %s, %s, true])",
diff --git a/chrome/test/chromedriver/chrome_launcher.cc b/chrome/test/chromedriver/chrome_launcher.cc
index dcf44d5..6326e14d 100644
--- a/chrome/test/chromedriver/chrome_launcher.cc
+++ b/chrome/test/chromedriver/chrome_launcher.cc
@@ -692,7 +692,7 @@
     }
   } else {
     manifest->SetString("key", public_key_base64);
-    base::JSONWriter::Write(manifest, &manifest_data);
+    base::JSONWriter::Write(*manifest, &manifest_data);
     if (base::WriteFile(
             manifest_path, manifest_data.c_str(), manifest_data.size()) !=
         static_cast<int>(manifest_data.size())) {
@@ -788,7 +788,7 @@
   }
 
   std::string prefs_str;
-  base::JSONWriter::Write(prefs, &prefs_str);
+  base::JSONWriter::Write(*prefs, &prefs_str);
   VLOG(0) << "Populating " << path.BaseName().value()
           << " file: " << PrettyPrintValue(*prefs);
   if (static_cast<int>(prefs_str.length()) != base::WriteFile(
diff --git a/chrome/test/chromedriver/performance_logger.cc b/chrome/test/chromedriver/performance_logger.cc
index ea38f77..800e8ec94 100644
--- a/chrome/test/chromedriver/performance_logger.cc
+++ b/chrome/test/chromedriver/performance_logger.cc
@@ -123,7 +123,7 @@
   log_message_dict.SetString("message.method", method);
   log_message_dict.Set("message.params", params.DeepCopy());
   std::string log_message_json;
-  base::JSONWriter::Write(&log_message_dict, &log_message_json);
+  base::JSONWriter::Write(log_message_dict, &log_message_json);
 
   // TODO(klm): extract timestamp from params?
   // Look at where it is for Page, Network, Timeline, and trace events.
diff --git a/chrome/test/chromedriver/server/http_handler.cc b/chrome/test/chromedriver/server/http_handler.cc
index 279858c..157b94a 100644
--- a/chrome/test/chromedriver/server/http_handler.cc
+++ b/chrome/test/chromedriver/server/http_handler.cc
@@ -709,7 +709,7 @@
   body_params.SetString("sessionId", session_id);
   std::string body;
   base::JSONWriter::WriteWithOptions(
-      &body_params, base::JSONWriter::OPTIONS_OMIT_DOUBLE_TYPE_PRESERVATION,
+      body_params, base::JSONWriter::OPTIONS_OMIT_DOUBLE_TYPE_PRESERVATION,
       &body);
   scoped_ptr<net::HttpServerResponseInfo> response(
       new net::HttpServerResponseInfo(net::HTTP_OK));
diff --git a/chrome/test/chromedriver/server/http_handler_unittest.cc b/chrome/test/chromedriver/server/http_handler_unittest.cc
index 55eaeb7..59c191f 100644
--- a/chrome/test/chromedriver/server/http_handler_unittest.cc
+++ b/chrome/test/chromedriver/server/http_handler_unittest.cc
@@ -74,7 +74,7 @@
   body.SetInteger("value", 1);
   body.SetString("sessionId", "session_id");
   std::string json;
-  base::JSONWriter::Write(&body, &json);
+  base::JSONWriter::Write(body, &json);
   ASSERT_EQ(json, response.body());
 }
 
@@ -119,7 +119,7 @@
   body.SetInteger("value", 1);
   body.SetString("sessionId", "session_id");
   std::string json;
-  base::JSONWriter::Write(&body, &json);
+  base::JSONWriter::Write(body, &json);
   ASSERT_EQ(json, response.body());
 }
 
diff --git a/chrome/test/data/extensions/api_test/bluetooth_low_energy/register_advertisement/manifest.json b/chrome/test/data/extensions/api_test/bluetooth_low_energy/register_advertisement/manifest.json
new file mode 100644
index 0000000..5d4b11f
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/bluetooth_low_energy/register_advertisement/manifest.json
@@ -0,0 +1,16 @@
+{
+  "manifest_version": 2,
+  "name": "Test the Bluetooth Low Energy registerAdvertisement API",
+  "version": "1.0",
+  "app": {
+    "background": {
+      "scripts": ["runtest.js"]
+    }
+  },
+  "bluetooth": {
+    "low_energy": true,
+    "peripheral": true,
+    "uuids": ["1234"]
+  },
+  "key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqbc71rRrqz+62pGVmZGDzTK8P4IHTTyN4jBLBJasDTrRllQp4Pb6INnSr08HQM3aaZMYKWkAJTm4gbCDNzvHfIZMAMY6OZfnm0eqiZnxFFgKgIzdr4Z/EyAXVd1Rm1JKhncde2S/U3zWStDb5iYfWZJBIiWVT98q7cW6sstsMOmrHAIAKCzK+mzycFptlRWzAf+8NR9bq1jNZe+h1kJBgY0xnVlGZm+NIhZd/Ke8Y+G2vM4rtuDvp5971HVV294HD28hWbsoOqBf85gPa6tKE57FhLomi/aJVBVBiCfHExXjK1hB2QeM/r7e8P//ZZPoYszSzHJVBw/heRLFOMezIwIDAQAB"
+}
diff --git a/chrome/test/data/extensions/api_test/bluetooth_low_energy/register_advertisement/runtest.js b/chrome/test/data/extensions/api_test/bluetooth_low_energy/register_advertisement/runtest.js
new file mode 100644
index 0000000..6ead665e
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/bluetooth_low_energy/register_advertisement/runtest.js
@@ -0,0 +1,38 @@
+// 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.
+
+var registerAdvertisement =
+    chrome.bluetoothLowEnergy.registerAdvertisement;
+var unregisterAdvertisement =
+    chrome.bluetoothLowEnergy.unregisterAdvertisement;
+
+var serviceUuidsValue = ['value1', 'value2'];
+var manufacturerDataValue = [{id: 321, data: [1, 2, 3]},
+                             {id: 567, data: [8, 2, 3]}]
+var solicitUuidsValue = ['value3', 'value4'];
+var serviceDataValue = [{uuid: 'uuid8', data: [1, 2, 3]},
+                        {uuid: 'uuid36', data: [8, 2, 3]}]
+
+var advertisement = {
+  type: 'broadcast',
+  serviceUuids: serviceUuidsValue,
+  manufacturerData: manufacturerDataValue,
+  solicitUuids: solicitUuidsValue,
+  serviceData: serviceDataValue
+};
+
+registerAdvertisement(advertisement, function (advertisementId) {
+  if (chrome.runtime.lastError || !advertisementId) {
+    chrome.test.fail(chrome.runtime.lastError.message);
+    return;
+  }
+
+  unregisterAdvertisement(advertisementId, function () {
+    if (chrome.runtime.lastError) {
+      chrome.test.fail(chrome.runtime.lastError.message);
+      return;
+    }
+    chrome.test.succeed();
+  });
+});
diff --git a/chrome/test/data/extensions/api_test/file_browser/mount_test/test.js b/chrome/test/data/extensions/api_test/file_browser/mount_test/test.js
index ff09363..e288fd5 100644
--- a/chrome/test/data/extensions/api_test/file_browser/mount_test/test.js
+++ b/chrome/test/data/extensions/api_test/file_browser/mount_test/test.js
@@ -13,7 +13,9 @@
   isParentDevice: false,
   isReadOnly: false,
   hasMedia: false,
-  profile: {profileId: "", displayName: "", isCurrentProfile: true}
+  configurable: false,
+  source: 'device',
+  profile: {profileId: '', displayName: '', isCurrentProfile: true},
 };
 
 var expectedVolume2 = {
@@ -26,7 +28,9 @@
   isParentDevice: true,
   isReadOnly: true,
   hasMedia: true,
-  profile: {profileId: "", displayName: "", isCurrentProfile: true}
+  configurable: false,
+  source: 'device',
+  profile: {profileId: '', displayName: '', isCurrentProfile: true}
 };
 
 var expectedVolume3 = {
@@ -39,7 +43,9 @@
   isParentDevice: true,
   isReadOnly: false,
   hasMedia: false,
-  profile: {profileId: "", displayName: "", isCurrentProfile: true}
+  configurable: false,
+  source: 'device',
+  profile: {profileId: '', displayName: '', isCurrentProfile: true}
 };
 
 var expectedDownloadsVolume = {
@@ -48,7 +54,9 @@
   volumeType: 'downloads',
   isReadOnly: false,
   hasMedia: false,
-  profile: {profileId: "", displayName: "", isCurrentProfile: true}
+  configurable: false,
+  source: 'system',
+  profile: {profileId: '', displayName: '', isCurrentProfile: true}
 };
 
 var expectedDriveVolume = {
@@ -58,7 +66,9 @@
   volumeType: 'drive',
   isReadOnly: false,
   hasMedia: false,
-  profile: {profileId: "", displayName: "", isCurrentProfile: true}
+  configurable: false,
+  source: 'network',
+  profile: {profileId: '', displayName: '', isCurrentProfile: true}
 };
 
 var expectedArchiveVolume = {
@@ -68,7 +78,23 @@
   volumeType: 'archive',
   isReadOnly: true,
   hasMedia: false,
-  profile: {profileId: "", displayName: "", isCurrentProfile: true}
+  configurable: false,
+  source: 'file',
+  profile: {profileId: '', displayName: '', isCurrentProfile: true}
+};
+
+var expectedProvidedVolume = {
+  volumeId: 'provided:',
+  volumeLabel: '',
+  volumeType: 'provided',
+  isReadOnly: true,
+  hasMedia: false,
+  configurable: true,
+  extensionId: 'testing-extension-id',
+  source: 'network',
+  mountContext: 'auto',
+  fileSystemId: '',
+  profile: {profileId: '', displayName: '', isCurrentProfile: true}
 };
 
 // List of expected mount points.
@@ -78,9 +104,10 @@
   expectedArchiveVolume,
   expectedDownloadsVolume,
   expectedDriveVolume,
+  expectedProvidedVolume,
   expectedVolume1,
   expectedVolume2,
-  expectedVolume3,
+  expectedVolume3
 ];
 
 function validateObject(received, expected, name) {
diff --git a/chrome/test/data/extensions/api_test/file_system_provider/configure/test.js b/chrome/test/data/extensions/api_test/file_system_provider/configure/test.js
index 5518d90..4053d11 100644
--- a/chrome/test/data/extensions/api_test/file_system_provider/configure/test.js
+++ b/chrome/test/data/extensions/api_test/file_system_provider/configure/test.js
@@ -41,11 +41,11 @@
             chrome.test.assertEq('device', extensions[0].source);
           }));
 
-      chrome.fileManagerPrivate.configureProvidedFileSystem(test_util.volumeId,
+      chrome.fileManagerPrivate.configureVolume(test_util.volumeId,
           chrome.test.callbackPass(function() {}));
     },
 
-    // Verify that chrome.fileManager.configureProvidedFileSystem is well wired
+    // Verify that chrome.fileManager.configureVolume is well wired
     // to onConfigureRequested().
     function configureSuccess() {
       var configured = false;
@@ -59,7 +59,7 @@
       chrome.fileSystemProvider.onConfigureRequested.addListener(
           onConfigureRequested);
 
-      chrome.fileManagerPrivate.configureProvidedFileSystem(test_util.volumeId,
+      chrome.fileManagerPrivate.configureVolume(test_util.volumeId,
           chrome.test.callbackPass(function() {
             chrome.test.assertTrue(configured);
           }));
@@ -77,7 +77,7 @@
       chrome.fileSystemProvider.onConfigureRequested.addListener(
           onConfigureRequested);
 
-      chrome.fileManagerPrivate.configureProvidedFileSystem(test_util.volumeId,
+      chrome.fileManagerPrivate.configureVolume(test_util.volumeId,
           chrome.test.callbackFail('Failed to complete configuration.'));
     },
 
diff --git a/chrome/test/data/extensions/api_test/fullscreen/has_permission/window.js b/chrome/test/data/extensions/api_test/fullscreen/has_permission/window.js
index fc0876d..dfcbba3 100644
--- a/chrome/test/data/extensions/api_test/fullscreen/has_permission/window.js
+++ b/chrome/test/data/extensions/api_test/fullscreen/has_permission/window.js
@@ -6,7 +6,9 @@
   function requestFullscreen() {
     document.onwebkitfullscreenchange = chrome.test.succeed;
     document.onwebkitfullscreenerror = chrome.test.fail;
-    document.body.webkitRequestFullscreen();
+    chrome.test.runWithUserGesture(function() {
+      document.body.webkitRequestFullscreen();
+    });
   };
   document.body.onclick = requestFullscreen;  // enables manual testing.
   chrome.test.runTests([requestFullscreen]);
diff --git a/chrome/test/data/extensions/api_test/instance_id/channel/manifest.json b/chrome/test/data/extensions/api_test/instance_id/channel/manifest.json
new file mode 100644
index 0000000..36268c2
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/instance_id/channel/manifest.json
@@ -0,0 +1,10 @@
+{
+  "manifest_version": 2,
+  "name": "Test InstanceID App",
+  "version": "1.0",
+  "description": "Tests InstanceID API",
+  "background": {
+    "scripts": ["test.js"]
+  },
+  "permissions": ["gcm"]
+}
diff --git a/chrome/test/data/extensions/api_test/instance_id/channel/test.js b/chrome/test/data/extensions/api_test/instance_id/channel/test.js
new file mode 100644
index 0000000..298fa2c
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/instance_id/channel/test.js
@@ -0,0 +1,12 @@
+// 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.
+
+chrome.test.runTests([
+  function test() {
+    if (chrome.instanceID)
+      chrome.test.fail();
+    else
+      chrome.test.succeed();
+  }
+]);
diff --git a/chrome/test/data/extensions/platform_apps/custom_launcher_page/main.js b/chrome/test/data/extensions/platform_apps/custom_launcher_page/main.js
index ce4fdc07..4ccc500 100644
--- a/chrome/test/data/extensions/platform_apps/custom_launcher_page/main.js
+++ b/chrome/test/data/extensions/platform_apps/custom_launcher_page/main.js
@@ -31,6 +31,12 @@
   });
 }
 
+function hideCustomLauncherPage() {
+  chrome.launcherPage.hide(function() {
+      chrome.test.sendMessage('launcherPageHidden');
+  });
+}
+
 document.addEventListener('DOMContentLoaded', function() {
   chrome.test.sendMessage('Launched');
 });
diff --git a/chromecast/browser/cast_browser_main_parts.cc b/chromecast/browser/cast_browser_main_parts.cc
index cab3c615..91b13ce 100644
--- a/chromecast/browser/cast_browser_main_parts.cc
+++ b/chromecast/browser/cast_browser_main_parts.cc
@@ -55,6 +55,7 @@
 #endif
 
 #if defined(USE_AURA)
+#include "ui/aura/env.h"
 #include "ui/aura/test/test_screen.h"
 #include "ui/gfx/screen.h"
 #endif
@@ -373,6 +374,11 @@
   cast_browser_process_->cast_service()->Finalize();
   cast_browser_process_->metrics_service_client()->Finalize();
   cast_browser_process_.reset();
+
+#if defined(USE_AURA)
+  aura::Env::DeleteInstance();
+#endif
+
   DeregisterKillOnAlarm();
 #endif
 
diff --git a/chromecast/browser/cast_browser_process.cc b/chromecast/browser/cast_browser_process.cc
index ccd04ae9..25fcd44 100644
--- a/chromecast/browser/cast_browser_process.cc
+++ b/chromecast/browser/cast_browser_process.cc
@@ -18,10 +18,6 @@
 #include "components/crash/browser/crash_dump_manager_android.h"
 #endif  // defined(OS_ANDROID)
 
-#if defined(USE_AURA)
-#include "ui/aura/env.h"
-#endif
-
 namespace chromecast {
 namespace shell {
 
@@ -44,9 +40,6 @@
   DCHECK_EQ(g_instance, this);
   if (pref_service_)
     pref_service_->CommitPendingWrite();
-#if defined(USE_AURA)
-  aura::Env::DeleteInstance();
-#endif
   g_instance = NULL;
 }
 
diff --git a/chromecast/chromecast_tests.gypi b/chromecast/chromecast_tests.gypi
index 95ade70..a5a7204f 100644
--- a/chromecast/chromecast_tests.gypi
+++ b/chromecast/chromecast_tests.gypi
@@ -12,8 +12,8 @@
       'type': '<(gtest_target_type)',
       'dependencies': [
         'chromecast.gyp:cast_base',
+        '../base/base.gyp:run_all_unittests',
         '../testing/gtest.gyp:gtest',
-        '../testing/gtest.gyp:gtest_main',
       ],
       'sources': [
         'base/serializers_unittest.cc',
diff --git a/chromecast/media/cdm/browser_cdm_cast.cc b/chromecast/media/cdm/browser_cdm_cast.cc
index 07c3c3e..b62df02 100644
--- a/chromecast/media/cdm/browser_cdm_cast.cc
+++ b/chromecast/media/cdm/browser_cdm_cast.cc
@@ -39,6 +39,8 @@
   legacy_session_error_cb_ = legacy_session_error_cb;
   session_keys_change_cb_ = session_keys_change_cb;
   session_expiration_update_cb_ = session_expiration_update_cb;
+
+  InitializeInternal();
 }
 
 int BrowserCdmCast::RegisterPlayer(const base::Closure& new_key_cb,
@@ -198,5 +200,10 @@
   return nullptr;
 }
 
+// A default empty implementation for subclasses that don't need to provide
+// any key system specific initialization.
+void BrowserCdmCast::InitializeInternal() {
+}
+
 }  // namespace media
 }  // namespace chromecast
diff --git a/chromecast/media/cdm/browser_cdm_cast.h b/chromecast/media/cdm/browser_cdm_cast.h
index 1f2d8e7..7a83a08d 100644
--- a/chromecast/media/cdm/browser_cdm_cast.h
+++ b/chromecast/media/cdm/browser_cdm_cast.h
@@ -77,6 +77,10 @@
  private:
   friend class BrowserCdmCastUi;
 
+  // Allow subclasses to override to provide key sysytem specific
+  // initialization.
+  virtual void InitializeInternal();
+
   ::media::SessionMessageCB session_message_cb_;
   ::media::SessionClosedCB session_closed_cb_;
   ::media::LegacySessionErrorCB legacy_session_error_cb_;
diff --git a/chromecast/media/cma/backend/audio_video_pipeline_device_unittest.cc b/chromecast/media/cma/backend/audio_video_pipeline_device_unittest.cc
index 7374261e..972d20a 100644
--- a/chromecast/media/cma/backend/audio_video_pipeline_device_unittest.cc
+++ b/chromecast/media/cma/backend/audio_video_pipeline_device_unittest.cc
@@ -6,6 +6,7 @@
 
 #include "base/basictypes.h"
 #include "base/bind.h"
+#include "base/command_line.h"
 #include "base/files/file_path.h"
 #include "base/files/memory_mapped_file.h"
 #include "base/logging.h"
@@ -28,6 +29,7 @@
 #include "chromecast/media/cma/base/decoder_config_adapter.h"
 #include "chromecast/media/cma/test/frame_segmenter_for_test.h"
 #include "chromecast/media/cma/test/media_component_device_feeder_for_test.h"
+#include "chromecast/public/cast_media_shlib.h"
 #include "chromecast/public/media/decoder_config.h"
 #include "media/base/audio_decoder_config.h"
 #include "media/base/buffers.h"
@@ -71,6 +73,15 @@
   AudioVideoPipelineDeviceTest();
   ~AudioVideoPipelineDeviceTest() override;
 
+  void SetUp() override {
+    CastMediaShlib::Initialize(
+        base::CommandLine::ForCurrentProcess()->argv());
+  }
+
+  void TearDown() override {
+    CastMediaShlib::Finalize();
+  }
+
   void ConfigureForFile(std::string filename);
   void ConfigureForAudioOnly(std::string filename);
   void ConfigureForVideoOnly(std::string filename, bool raw_h264);
diff --git a/chromecast/public/cast_media_shlib.h b/chromecast/public/cast_media_shlib.h
index 8429ca1..6f2d60d 100644
--- a/chromecast/public/cast_media_shlib.h
+++ b/chromecast/public/cast_media_shlib.h
@@ -13,15 +13,24 @@
 namespace chromecast {
 namespace media {
 
+// Provides access to platform-specific media systems and hardware resources.
+// In cast_shell, all usage is from the browser process.  An implementation is
+// assumed to be in an uninitialized state initially.  When uninitialized, no
+// API calls will be made except for Initialize, which brings the implementation
+// into an initialized state.  A call to Finalize returns the implementation to
+// its uninitialized state.  The implementation must support multiple
+// transitions between these states, to support resource grant/revoke events and
+// also to allow multiple unit tests to bring up the media systems in isolation
+// from other tests.
 class CHROMECAST_EXPORT CastMediaShlib {
  public:
-  // Performs platform-specific one-time initialization for media systems and
-  // hardware resources. Called at startup in browser process before main
-  // message loop begins.
+  // Initializes platform-specific media systems.  Only called when in an
+  // uninitialized state.
   static void Initialize(const std::vector<std::string>& argv);
 
-  // Performs platform-specific one-time teardown of media systems and hardware
-  // resources. Called at browser process exit.
+  // Tears down platform-specific media systems and returns to the uninitialized
+  // state.  The implementation must release all media-related hardware
+  // resources.
   static void Finalize();
 };
 
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index 0cd395f..615513f 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-7068.0.0
\ No newline at end of file
+7072.0.0
\ No newline at end of file
diff --git a/chromeos/dbus/shill_client_unittest_base.cc b/chromeos/dbus/shill_client_unittest_base.cc
index 184851a..de82bf0 100644
--- a/chromeos/dbus/shill_client_unittest_base.cc
+++ b/chromeos/dbus/shill_client_unittest_base.cc
@@ -54,7 +54,7 @@
 
 void ValueMatcher::DescribeTo(::std::ostream* os) const {
   std::string expected_value_str;
-  base::JSONWriter::WriteWithOptions(expected_value_.get(),
+  base::JSONWriter::WriteWithOptions(*expected_value_,
                                      base::JSONWriter::OPTIONS_PRETTY_PRINT,
                                      &expected_value_str);
   *os << "value equals " << expected_value_str;
@@ -62,7 +62,7 @@
 
 void ValueMatcher::DescribeNegationTo(::std::ostream* os) const {
   std::string expected_value_str;
-  base::JSONWriter::WriteWithOptions(expected_value_.get(),
+  base::JSONWriter::WriteWithOptions(*expected_value_,
                                      base::JSONWriter::OPTIONS_PRETTY_PRINT,
                                      &expected_value_str);
   *os << "value does not equal " << expected_value_str;
@@ -393,9 +393,9 @@
     const base::DictionaryValue* expected_result,
     const base::DictionaryValue& result) {
   std::string expected_result_string;
-  base::JSONWriter::Write(expected_result, &expected_result_string);
+  base::JSONWriter::Write(*expected_result, &expected_result_string);
   std::string result_string;
-  base::JSONWriter::Write(&result, &result_string);
+  base::JSONWriter::Write(result, &result_string);
   EXPECT_EQ(expected_result_string, result_string);
 }
 
diff --git a/chromeos/login/auth/user_context.cc b/chromeos/login/auth/user_context.cc
index 4f51b34..e5b3fe0 100644
--- a/chromeos/login/auth/user_context.cc
+++ b/chromeos/login/auth/user_context.cc
@@ -25,7 +25,8 @@
       auth_flow_(other.auth_flow_),
       user_type_(other.user_type_),
       public_session_locale_(other.public_session_locale_),
-      public_session_input_method_(other.public_session_input_method_) {
+      public_session_input_method_(other.public_session_input_method_),
+      device_id_(other.device_id_) {
 }
 
 UserContext::UserContext(const std::string& user_id)
diff --git a/chromeos/network/network_configuration_handler.cc b/chromeos/network/network_configuration_handler.cc
index d095e57..ac7ea8b 100644
--- a/chromeos/network/network_configuration_handler.cc
+++ b/chromeos/network/network_configuration_handler.cc
@@ -65,7 +65,7 @@
        iter.Advance()) {
     std::string v = "******";
     if (shill_property_util::IsLoggableShillProperty(iter.key()))
-      base::JSONWriter::Write(&iter.value(), &v);
+      base::JSONWriter::Write(iter.value(), &v);
     NET_LOG(USER) << desc << ": " << path + "." + iter.key() + "=" + v;
   }
 }
diff --git a/chromeos/network/network_configuration_handler_unittest.cc b/chromeos/network/network_configuration_handler_unittest.cc
index 2772fc9..2b79c4c 100644
--- a/chromeos/network/network_configuration_handler_unittest.cc
+++ b/chromeos/network/network_configuration_handler_unittest.cc
@@ -46,7 +46,7 @@
 static std::string PrettyJson(const base::DictionaryValue& value) {
   std::string pretty;
   base::JSONWriter::WriteWithOptions(
-      &value, base::JSONWriter::OPTIONS_PRETTY_PRINT, &pretty);
+      value, base::JSONWriter::OPTIONS_PRETTY_PRINT, &pretty);
   return pretty;
 }
 
diff --git a/chromeos/network/network_state_handler.cc b/chromeos/network/network_state_handler.cc
index a8a9ebf9..e7ddbcf 100644
--- a/chromeos/network/network_state_handler.cc
+++ b/chromeos/network/network_state_handler.cc
@@ -56,7 +56,7 @@
 std::string ValueAsString(const base::Value& value) {
   std::string vstr;
   base::JSONWriter::WriteWithOptions(
-      &value, base::JSONWriter::OPTIONS_OMIT_BINARY_VALUES, &vstr);
+      value, base::JSONWriter::OPTIONS_OMIT_BINARY_VALUES, &vstr);
   return vstr.empty() ? "''" : vstr;
 }
 
diff --git a/chromeos/network/onc/onc_translator_onc_to_shill.cc b/chromeos/network/onc/onc_translator_onc_to_shill.cc
index 9cea033..33b9e8d5 100644
--- a/chromeos/network/onc/onc_translator_onc_to_shill.cc
+++ b/chromeos/network/onc/onc_translator_onc_to_shill.cc
@@ -31,7 +31,7 @@
 scoped_ptr<base::StringValue> ConvertValueToString(const base::Value& value) {
   std::string str;
   if (!value.GetAsString(&str))
-    base::JSONWriter::Write(&value, &str);
+    base::JSONWriter::Write(value, &str);
   return make_scoped_ptr(new base::StringValue(str));
 }
 
diff --git a/chromeos/network/shill_property_util.cc b/chromeos/network/shill_property_util.cc
index a53487b..30a6925 100644
--- a/chromeos/network/shill_property_util.cc
+++ b/chromeos/network/shill_property_util.cc
@@ -221,7 +221,7 @@
   base::DictionaryValue ui_data_dict;
   ui_data.FillDictionary(&ui_data_dict);
   std::string ui_data_blob;
-  base::JSONWriter::Write(&ui_data_dict, &ui_data_blob);
+  base::JSONWriter::Write(ui_data_dict, &ui_data_blob);
   shill_dictionary->SetStringWithoutPathExpansion(shill::kUIDataProperty,
                                                   ui_data_blob);
 }
diff --git a/cloud_print/gcp20/prototype/cloud_print_requester.cc b/cloud_print/gcp20/prototype/cloud_print_requester.cc
index d46fdf4..cbfdae44 100644
--- a/cloud_print/gcp20/prototype/cloud_print_requester.cc
+++ b/cloud_print/gcp20/prototype/cloud_print_requester.cc
@@ -86,10 +86,10 @@
   current->SetBoolean("printer/local_printing_enabled",
                          settings.local_printing_enabled);
   current->SetInteger("xmpp_timeout_value", settings.xmpp_timeout_value);
-  dictionary.Set("current", current.release());
+  dictionary.Set("current", current.Pass());
 
   std::string local_settings;
-  base::JSONWriter::Write(&dictionary, &local_settings);
+  base::JSONWriter::Write(dictionary, &local_settings);
   return local_settings;
 }
 
diff --git a/cloud_print/gcp20/prototype/printer.cc b/cloud_print/gcp20/prototype/printer.cc
index 9820ace..4309002 100644
--- a/cloud_print/gcp20/prototype/printer.cc
+++ b/cloud_print/gcp20/prototype/printer.cc
@@ -193,7 +193,7 @@
 
 std::string Printer::GetRawCdd() {
   std::string json_str;
-  base::JSONWriter::WriteWithOptions(&GetCapabilities(),
+  base::JSONWriter::WriteWithOptions(GetCapabilities(),
                                      base::JSONWriter::OPTIONS_PRETTY_PRINT,
                                      &json_str);
   return json_str;
diff --git a/cloud_print/gcp20/prototype/printer_state.cc b/cloud_print/gcp20/prototype/printer_state.cc
index 9dedf1d..0d8fead 100644
--- a/cloud_print/gcp20/prototype/printer_state.cc
+++ b/cloud_print/gcp20/prototype/printer_state.cc
@@ -71,7 +71,7 @@
     json.Set(kCdd, state.cdd->DeepCopy());
 
   std::string json_str;
-  base::JSONWriter::WriteWithOptions(&json,
+  base::JSONWriter::WriteWithOptions(json,
                                      base::JSONWriter::OPTIONS_PRETTY_PRINT,
                                      &json_str);
   int size = base::checked_cast<int>(json_str.size());
diff --git a/cloud_print/gcp20/prototype/privet_http_server.cc b/cloud_print/gcp20/prototype/privet_http_server.cc
index c0334395..90b45a8 100644
--- a/cloud_print/gcp20/prototype/privet_http_server.cc
+++ b/cloud_print/gcp20/prototype/privet_http_server.cc
@@ -234,7 +234,7 @@
     return status_code;
   }
 
-  base::JSONWriter::WriteWithOptions(json_response.get(),
+  base::JSONWriter::WriteWithOptions(*json_response,
                                      base::JSONWriter::OPTIONS_PRETTY_PRINT,
                                      response);
   return status_code;
diff --git a/cloud_print/service/service_state.cc b/cloud_print/service/service_state.cc
index f98c513..789d229 100644
--- a/cloud_print/service/service_state.cc
+++ b/cloud_print/service/service_state.cc
@@ -134,8 +134,6 @@
 }
 
 std::string ServiceState::ToString() {
-  scoped_ptr<base::DictionaryValue> services(new base::DictionaryValue());
-
   scoped_ptr<base::DictionaryValue> cloud_print(new base::DictionaryValue());
   cloud_print->SetBoolean(kEnabledOptionName, true);
 
@@ -147,12 +145,12 @@
   SetNotEmptyJsonString(cloud_print.get(), kXmppAuthTokenOptionName,
                         xmpp_auth_token_);
 
-  services->Set(kCloudPrintJsonName, cloud_print.release());
+  base::DictionaryValue services;
+  services.Set(kCloudPrintJsonName, cloud_print.Pass());
 
   std::string json;
-  base::JSONWriter::WriteWithOptions(services.get(),
-                                     base::JSONWriter::OPTIONS_PRETTY_PRINT,
-                                     &json);
+  base::JSONWriter::WriteWithOptions(
+      services, base::JSONWriter::OPTIONS_PRETTY_PRINT, &json);
   return json;
 }
 
diff --git a/cloud_print/service/win/chrome_launcher.cc b/cloud_print/service/win/chrome_launcher.cc
index adf9c24..e9bcee1 100644
--- a/cloud_print/service/win/chrome_launcher.cc
+++ b/cloud_print/service/win/chrome_launcher.cc
@@ -133,7 +133,7 @@
   if (!proxy_id.empty())  // Reuse proxy id if we already had one.
     dictionary->SetString(prefs::kCloudPrintProxyId, proxy_id);
   std::string result;
-  base::JSONWriter::WriteWithOptions(dictionary,
+  base::JSONWriter::WriteWithOptions(*dictionary,
                                      base::JSONWriter::OPTIONS_PRETTY_PRINT,
                                      &result);
   return result;
@@ -276,7 +276,7 @@
   base::ListValue printer_list;
   printer_list.AppendStrings(printers);
   std::string printers_json;
-  base::JSONWriter::Write(&printer_list, &printers_json);
+  base::JSONWriter::Write(printer_list, &printers_json);
   size_t written = base::WriteFile(printers_file,
                                    printers_json.c_str(),
                                    printers_json.size());
diff --git a/cloud_print/service/win/service_listener.cc b/cloud_print/service/win/service_listener.cc
index f4af6ddc..497aff76 100644
--- a/cloud_print/service/win/service_listener.cc
+++ b/cloud_print/service/win/service_listener.cc
@@ -49,7 +49,7 @@
   }
 
   std::string result;
-  base::JSONWriter::Write(&environment, &result);
+  base::JSONWriter::Write(environment, &result);
   return result;
 }
 
diff --git a/components/OWNERS b/components/OWNERS
index 6ed83b5..4f7ba090 100644
--- a/components/OWNERS
+++ b/components/OWNERS
@@ -63,9 +63,6 @@
 per-file data_reduction_proxy*=sclittle@chromium.org
 per-file data_reduction_proxy*=jeremyim@chromium.org
 
-per-file devtools_bridge.gyp=mnaganov@chromium.org
-per-file devtools_bridge.gyp=serya@chromium.org
-
 per-file devtools_discovery.gyp*=dgozman@chromium.org
 per-file devtools_discovery.gyp*=pfeldman@chromium.org
 
diff --git a/components/autofill/content/browser/wallet/wallet_client.cc b/components/autofill/content/browser/wallet/wallet_client.cc
index b5cd15e..e599b2e 100644
--- a/components/autofill/content/browser/wallet/wallet_client.cc
+++ b/components/autofill/content/browser/wallet/wallet_client.cc
@@ -295,7 +295,7 @@
   request_dict.SetString(kInstrumentIdKey, instrument_id);
 
   std::string json_payload;
-  base::JSONWriter::Write(&request_dict, &json_payload);
+  base::JSONWriter::Write(request_dict, &json_payload);
 
   std::string escaped_card_verification_number = net::EscapeUrlEncodedData(
       card_verification_number, true);
@@ -339,7 +339,7 @@
   request_dict.Set(kRiskCapabilitiesKey, risk_capabilities_list.release());
 
   std::string json_payload;
-  base::JSONWriter::Write(&request_dict, &json_payload);
+  base::JSONWriter::Write(request_dict, &json_payload);
 
   crypto::RandBytes(&(one_time_pad_[0]), one_time_pad_.size());
 
@@ -431,7 +431,7 @@
   }
 
   std::string json_payload;
-  base::JSONWriter::Write(&request_dict, &json_payload);
+  base::JSONWriter::Write(request_dict, &json_payload);
 
   if (!card_verification_number.empty()) {
     std::string post_body;
@@ -476,7 +476,7 @@
     request_dict.SetString(kTransactionCurrencyKey, currency);
 
   std::string post_body;
-  base::JSONWriter::Write(&request_dict, &post_body);
+  base::JSONWriter::Write(request_dict, &post_body);
 
   MakeWalletRequest(GetGetWalletItemsUrl(user_index_),
                     post_body,
@@ -515,7 +515,7 @@
   request_dict.Set(kAcceptedLegalDocumentKey, docs_list.release());
 
   std::string post_body;
-  base::JSONWriter::Write(&request_dict, &post_body);
+  base::JSONWriter::Write(request_dict, &post_body);
 
   MakeWalletRequest(GetAcceptLegalDocumentsUrl(user_index_),
                     post_body,
diff --git a/components/autofill/content/browser/wallet/wallet_client_unittest.cc b/components/autofill/content/browser/wallet/wallet_client_unittest.cc
index 230776f6..a57bbf5 100644
--- a/components/autofill/content/browser/wallet/wallet_client_unittest.cc
+++ b/components/autofill/content/browser/wallet/wallet_client_unittest.cc
@@ -876,7 +876,7 @@
         static_cast<base::DictionaryValue*>(root.get());
     dict->Remove("api_key", NULL);
     std::string clean_upload_data;
-    base::JSONWriter::Write(dict, &clean_upload_data);
+    base::JSONWriter::Write(*dict, &clean_upload_data);
     return clean_upload_data;
   }
 
diff --git a/components/autofill/content/renderer/autofill_agent.cc b/components/autofill/content/renderer/autofill_agent.cc
index b994e4d..bf1f54a 100644
--- a/components/autofill/content/renderer/autofill_agent.cc
+++ b/components/autofill/content/renderer/autofill_agent.cc
@@ -388,7 +388,7 @@
   if (ignore_text_changes_)
     return;
 
-  if (!WebUserGestureIndicator::isProcessingUserGesture())
+  if (!IsUserGesture())
     return;
 
   // We post a task for doing the Autofill as the caret position is not set
@@ -752,6 +752,10 @@
   Send(new AutofillHostMsg_HidePopup(routing_id()));
 }
 
+bool AutofillAgent::IsUserGesture() const {
+  return WebUserGestureIndicator::isProcessingUserGesture();
+}
+
 void AutofillAgent::didAssociateFormControls(const WebVector<WebNode>& nodes) {
   for (size_t i = 0; i < nodes.size(); ++i) {
     WebLocalFrame* frame = nodes[i].document().frame();
diff --git a/components/autofill/content/renderer/autofill_agent.h b/components/autofill/content/renderer/autofill_agent.h
index 39d6573..c75d5d6 100644
--- a/components/autofill/content/renderer/autofill_agent.h
+++ b/components/autofill/content/renderer/autofill_agent.h
@@ -221,6 +221,10 @@
   // Hides any currently showing Autofill popup.
   void HidePopup();
 
+  // Returns true if the text field change is due to a user gesture. Can be
+  // overriden in tests.
+  virtual bool IsUserGesture() const;
+
   // Formerly cached forms for all frames, now only caches forms for the current
   // frame.
   FormCache form_cache_;
diff --git a/components/autofill/content/renderer/password_form_conversion_utils.cc b/components/autofill/content/renderer/password_form_conversion_utils.cc
index 44fc323..b737f1a 100644
--- a/components/autofill/content/renderer/password_form_conversion_utils.cc
+++ b/components/autofill/content/renderer/password_form_conversion_utils.cc
@@ -8,6 +8,7 @@
 
 #include "base/lazy_instance.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/metrics/histogram_macros.h"
 #include "base/strings/string_util.h"
 #include "components/autofill/content/renderer/form_autofill_util.h"
 #include "components/autofill/core/common/form_data_predictions.h"
@@ -404,6 +405,14 @@
       password_form->new_password_marked_by_site = true;
   }
 
+  if (username_element.isNull()) {
+    // To get a better idea on how password forms without a username field
+    // look like, report the total number of text and password fields.
+    UMA_HISTOGRAM_COUNTS_100(
+        "PasswordManager.EmptyUsernames.TextAndPasswordFieldCount",
+        layout_sequence.size());
+  }
+
   password_form->scheme = PasswordForm::SCHEME_HTML;
   password_form->ssl_valid = false;
   password_form->preferred = false;
diff --git a/components/autofill/core/browser/wallet/real_pan_wallet_client.cc b/components/autofill/core/browser/wallet/real_pan_wallet_client.cc
index 9d41ab4..ec7adb5c 100644
--- a/components/autofill/core/browser/wallet/real_pan_wallet_client.cc
+++ b/components/autofill/core/browser/wallet/real_pan_wallet_client.cc
@@ -244,7 +244,7 @@
     request_dict.SetInteger("expiration_year", value);
 
   std::string json_request;
-  base::JSONWriter::Write(&request_dict, &json_request);
+  base::JSONWriter::Write(request_dict, &json_request);
   std::string post_body =
       base::StringPrintf(kUnmaskCardRequestFormat,
                          net::EscapeUrlEncodedData(json_request, true).c_str(),
diff --git a/components/autofill/core/common/password_form.cc b/components/autofill/core/common/password_form.cc
index 41ca1fc..e5edaca9 100644
--- a/components/autofill/core/common/password_form.cc
+++ b/components/autofill/core/common/password_form.cc
@@ -160,7 +160,7 @@
 
   std::string form_as_string;
   base::JSONWriter::WriteWithOptions(
-      &form_json, base::JSONWriter::OPTIONS_PRETTY_PRINT, &form_as_string);
+      form_json, base::JSONWriter::OPTIONS_PRETTY_PRINT, &form_as_string);
   base::TrimWhitespaceASCII(form_as_string, base::TRIM_ALL, &form_as_string);
   return os << "PasswordForm(" << form_as_string << ")";
 }
diff --git a/components/autofill/core/common/save_password_progress_logger.cc b/components/autofill/core/common/save_password_progress_logger.cc
index 2fe68c9..f6da10c 100644
--- a/components/autofill/core/common/save_password_progress_logger.cc
+++ b/components/autofill/core/common/save_password_progress_logger.cc
@@ -143,7 +143,7 @@
 void SavePasswordProgressLogger::LogValue(StringID label, const Value& log) {
   std::string log_string;
   bool conversion_to_string_successful = base::JSONWriter::WriteWithOptions(
-      &log, base::JSONWriter::OPTIONS_PRETTY_PRINT, &log_string);
+      log, base::JSONWriter::OPTIONS_PRETTY_PRINT, &log_string);
   DCHECK(conversion_to_string_successful);
   SendLog(GetStringFromID(label) + ": " + log_string);
 }
diff --git a/components/bookmarks/browser/bookmark_model_unittest.cc b/components/bookmarks/browser/bookmark_model_unittest.cc
index 1f71f01..bf4f917 100644
--- a/components/bookmarks/browser/bookmark_model_unittest.cc
+++ b/components/bookmarks/browser/bookmark_model_unittest.cc
@@ -103,6 +103,110 @@
   n2->set_date_added(tmp);
 }
 
+// See comment in PopulateNodeFromString.
+using TestNode = ui::TreeNodeWithValue<BookmarkNode::Type>;
+
+// Does the work of PopulateNodeFromString. index gives the index of the current
+// element in description to process.
+void PopulateNodeImpl(const std::vector<std::string>& description,
+                      size_t* index,
+                      TestNode* parent) {
+  while (*index < description.size()) {
+    const std::string& element = description[*index];
+    (*index)++;
+    if (element == "[") {
+      // Create a new folder and recurse to add all the children.
+      // Folders are given a unique named by way of an ever increasing integer
+      // value. The folders need not have a name, but one is assigned to help
+      // in debugging.
+      static int next_folder_id = 1;
+      TestNode* new_node = new TestNode(base::IntToString16(next_folder_id++),
+                                        BookmarkNode::FOLDER);
+      parent->Add(new_node, parent->child_count());
+      PopulateNodeImpl(description, index, new_node);
+    } else if (element == "]") {
+      // End the current folder.
+      return;
+    } else {
+      // Add a new URL.
+
+      // All tokens must be space separated. If there is a [ or ] in the name it
+      // likely means a space was forgotten.
+      DCHECK(element.find('[') == std::string::npos);
+      DCHECK(element.find(']') == std::string::npos);
+      parent->Add(new TestNode(base::UTF8ToUTF16(element), BookmarkNode::URL),
+                  parent->child_count());
+    }
+  }
+}
+
+// Creates and adds nodes to parent based on description. description consists
+// of the following tokens (all space separated):
+//   [ : creates a new USER_FOLDER node. All elements following the [ until the
+//       next balanced ] is encountered are added as children to the node.
+//   ] : closes the last folder created by [ so that any further nodes are added
+//       to the current folders parent.
+//   text: creates a new URL node.
+// For example, "a [b] c" creates the following nodes:
+//   a 1 c
+//     |
+//     b
+// In words: a node of type URL with the title a, followed by a folder node with
+// the title 1 having the single child of type url with name b, followed by
+// the url node with the title c.
+//
+// NOTE: each name must be unique, and folders are assigned a unique title by
+// way of an increasing integer.
+void PopulateNodeFromString(const std::string& description, TestNode* parent) {
+  std::vector<std::string> elements;
+  base::SplitStringAlongWhitespace(description, &elements);
+  size_t index = 0;
+  PopulateNodeImpl(elements, &index, parent);
+}
+
+// Populates the BookmarkNode with the children of parent.
+void PopulateBookmarkNode(TestNode* parent,
+                          BookmarkModel* model,
+                          const BookmarkNode* bb_node) {
+  for (int i = 0; i < parent->child_count(); ++i) {
+    TestNode* child = parent->GetChild(i);
+    if (child->value == BookmarkNode::FOLDER) {
+      const BookmarkNode* new_bb_node =
+          model->AddFolder(bb_node, i, child->GetTitle());
+      PopulateBookmarkNode(child, model, new_bb_node);
+    } else {
+      model->AddURL(bb_node, i, child->GetTitle(),
+                    GURL("http://" + base::UTF16ToASCII(child->GetTitle())));
+    }
+  }
+}
+
+// Verifies the contents of the bookmark bar node match the contents of the
+// TestNode.
+void VerifyModelMatchesNode(TestNode* expected, const BookmarkNode* actual) {
+  ASSERT_EQ(expected->child_count(), actual->child_count());
+  for (int i = 0; i < expected->child_count(); ++i) {
+    TestNode* expected_child = expected->GetChild(i);
+    const BookmarkNode* actual_child = actual->GetChild(i);
+    ASSERT_EQ(expected_child->GetTitle(), actual_child->GetTitle());
+    if (expected_child->value == BookmarkNode::FOLDER) {
+      ASSERT_TRUE(actual_child->type() == BookmarkNode::FOLDER);
+      // Recurse throught children.
+      VerifyModelMatchesNode(expected_child, actual_child);
+    } else {
+      // No need to check the URL, just the title is enough.
+      ASSERT_TRUE(actual_child->is_url());
+    }
+  }
+}
+
+void VerifyNoDuplicateIDs(BookmarkModel* model) {
+  ui::TreeNodeIterator<const BookmarkNode> it(model->root_node());
+  base::hash_set<int64> ids;
+  while (it.has_next())
+    ASSERT_TRUE(ids.insert(it.Next()->id()).second);
+}
+
 class BookmarkModelTest : public testing::Test,
                           public BookmarkModelObserver {
  public:
@@ -826,165 +930,6 @@
   EXPECT_TRUE(model_->HasBookmarks());
 }
 
-// See comment in PopulateNodeFromString.
-typedef ui::TreeNodeWithValue<BookmarkNode::Type> TestNode;
-
-// Does the work of PopulateNodeFromString. index gives the index of the current
-// element in description to process.
-void PopulateNodeImpl(const std::vector<std::string>& description,
-                      size_t* index,
-                      TestNode* parent) {
-  while (*index < description.size()) {
-    const std::string& element = description[*index];
-    (*index)++;
-    if (element == "[") {
-      // Create a new folder and recurse to add all the children.
-      // Folders are given a unique named by way of an ever increasing integer
-      // value. The folders need not have a name, but one is assigned to help
-      // in debugging.
-      static int next_folder_id = 1;
-      TestNode* new_node =
-          new TestNode(base::IntToString16(next_folder_id++),
-                       BookmarkNode::FOLDER);
-      parent->Add(new_node, parent->child_count());
-      PopulateNodeImpl(description, index, new_node);
-    } else if (element == "]") {
-      // End the current folder.
-      return;
-    } else {
-      // Add a new URL.
-
-      // All tokens must be space separated. If there is a [ or ] in the name it
-      // likely means a space was forgotten.
-      DCHECK(element.find('[') == std::string::npos);
-      DCHECK(element.find(']') == std::string::npos);
-      parent->Add(new TestNode(base::UTF8ToUTF16(element), BookmarkNode::URL),
-                  parent->child_count());
-    }
-  }
-}
-
-// Creates and adds nodes to parent based on description. description consists
-// of the following tokens (all space separated):
-//   [ : creates a new USER_FOLDER node. All elements following the [ until the
-//       next balanced ] is encountered are added as children to the node.
-//   ] : closes the last folder created by [ so that any further nodes are added
-//       to the current folders parent.
-//   text: creates a new URL node.
-// For example, "a [b] c" creates the following nodes:
-//   a 1 c
-//     |
-//     b
-// In words: a node of type URL with the title a, followed by a folder node with
-// the title 1 having the single child of type url with name b, followed by
-// the url node with the title c.
-//
-// NOTE: each name must be unique, and folders are assigned a unique title by
-// way of an increasing integer.
-void PopulateNodeFromString(const std::string& description, TestNode* parent) {
-  std::vector<std::string> elements;
-  base::SplitStringAlongWhitespace(description, &elements);
-  size_t index = 0;
-  PopulateNodeImpl(elements, &index, parent);
-}
-
-// Populates the BookmarkNode with the children of parent.
-void PopulateBookmarkNode(TestNode* parent,
-                          BookmarkModel* model,
-                          const BookmarkNode* bb_node) {
-  for (int i = 0; i < parent->child_count(); ++i) {
-    TestNode* child = parent->GetChild(i);
-    if (child->value == BookmarkNode::FOLDER) {
-      const BookmarkNode* new_bb_node =
-          model->AddFolder(bb_node, i, child->GetTitle());
-      PopulateBookmarkNode(child, model, new_bb_node);
-    } else {
-      model->AddURL(bb_node, i, child->GetTitle(),
-          GURL("http://" + base::UTF16ToASCII(child->GetTitle())));
-    }
-  }
-}
-
-// Test class that creates a BookmarkModel with a real history backend.
-class BookmarkModelTestWithProfile : public testing::Test {
- public:
-  BookmarkModelTestWithProfile() {}
-
- protected:
-  // Verifies the contents of the bookmark bar node match the contents of the
-  // TestNode.
-  void VerifyModelMatchesNode(TestNode* expected, const BookmarkNode* actual) {
-    ASSERT_EQ(expected->child_count(), actual->child_count());
-    for (int i = 0; i < expected->child_count(); ++i) {
-      TestNode* expected_child = expected->GetChild(i);
-      const BookmarkNode* actual_child = actual->GetChild(i);
-      ASSERT_EQ(expected_child->GetTitle(), actual_child->GetTitle());
-      if (expected_child->value == BookmarkNode::FOLDER) {
-        ASSERT_TRUE(actual_child->type() == BookmarkNode::FOLDER);
-        // Recurse throught children.
-        VerifyModelMatchesNode(expected_child, actual_child);
-        if (HasFatalFailure())
-          return;
-      } else {
-        // No need to check the URL, just the title is enough.
-        ASSERT_TRUE(actual_child->is_url());
-      }
-    }
-  }
-
-  void VerifyNoDuplicateIDs(BookmarkModel* model) {
-    ui::TreeNodeIterator<const BookmarkNode> it(model->root_node());
-    base::hash_set<int64> ids;
-    while (it.has_next())
-      ASSERT_TRUE(ids.insert(it.Next()->id()).second);
-  }
-
-  TestBookmarkClient client_;
-  scoped_ptr<BookmarkModel> model_;
-};
-
-// Creates a set of nodes in the bookmark bar model, then recreates the
-// bookmark bar model which triggers loading from the db and checks the loaded
-// structure to make sure it is what we first created.
-TEST_F(BookmarkModelTestWithProfile, CreateAndRestore) {
-  struct TestData {
-    // Structure of the children of the bookmark bar model node.
-    const std::string bbn_contents;
-    // Structure of the children of the other node.
-    const std::string other_contents;
-    // Structure of the children of the synced node.
-    const std::string mobile_contents;
-  } data[] = {
-    // See PopulateNodeFromString for a description of these strings.
-    { "", "" },
-    { "a", "b" },
-    { "a [ b ]", "" },
-    { "", "[ b ] a [ c [ d e [ f ] ] ]" },
-    { "a [ b ]", "" },
-    { "a b c [ d e [ f ] ]", "g h i [ j k [ l ] ]"},
-  };
-  for (size_t i = 0; i < arraysize(data); ++i) {
-    model_ = client_.CreateModel();
-
-    TestNode bbn;
-    PopulateNodeFromString(data[i].bbn_contents, &bbn);
-    PopulateBookmarkNode(&bbn, model_.get(), model_->bookmark_bar_node());
-
-    TestNode other;
-    PopulateNodeFromString(data[i].other_contents, &other);
-    PopulateBookmarkNode(&other, model_.get(), model_->other_node());
-
-    TestNode mobile;
-    PopulateNodeFromString(data[i].mobile_contents, &mobile);
-    PopulateBookmarkNode(&mobile, model_.get(), model_->mobile_node());
-
-    VerifyModelMatchesNode(&bbn, model_->bookmark_bar_node());
-    VerifyModelMatchesNode(&other, model_->other_node());
-    VerifyModelMatchesNode(&mobile, model_->mobile_node());
-    VerifyNoDuplicateIDs(model_.get());
-  }
-}
-
 // http://crbug.com/450464
 TEST_F(BookmarkModelTest, DISABLED_Sort) {
   // Populate the bookmark bar node with nodes for 'B', 'a', 'd' and 'C'.
@@ -1193,5 +1138,48 @@
   EXPECT_FALSE(node.GetMetaInfoMap());
 }
 
+// Creates a set of nodes in the bookmark model, and checks that the loaded
+// structure is what we first created.
+TEST(BookmarkModelTest2, CreateAndRestore) {
+  struct TestData {
+    // Structure of the children of the bookmark model node.
+    const std::string bbn_contents;
+    // Structure of the children of the other node.
+    const std::string other_contents;
+    // Structure of the children of the synced node.
+    const std::string mobile_contents;
+  } data[] = {
+    // See PopulateNodeFromString for a description of these strings.
+    { "", "" },
+    { "a", "b" },
+    { "a [ b ]", "" },
+    { "", "[ b ] a [ c [ d e [ f ] ] ]" },
+    { "a [ b ]", "" },
+    { "a b c [ d e [ f ] ]", "g h i [ j k [ l ] ]"},
+  };
+  TestBookmarkClient client;
+  scoped_ptr<BookmarkModel> model;
+  for (size_t i = 0; i < arraysize(data); ++i) {
+    model = client.CreateModel();
+
+    TestNode bbn;
+    PopulateNodeFromString(data[i].bbn_contents, &bbn);
+    PopulateBookmarkNode(&bbn, model.get(), model->bookmark_bar_node());
+
+    TestNode other;
+    PopulateNodeFromString(data[i].other_contents, &other);
+    PopulateBookmarkNode(&other, model.get(), model->other_node());
+
+    TestNode mobile;
+    PopulateNodeFromString(data[i].mobile_contents, &mobile);
+    PopulateBookmarkNode(&mobile, model.get(), model->mobile_node());
+
+    VerifyModelMatchesNode(&bbn, model->bookmark_bar_node());
+    VerifyModelMatchesNode(&other, model->other_node());
+    VerifyModelMatchesNode(&mobile, model->mobile_node());
+    VerifyNoDuplicateIDs(model.get());
+  }
+}
+
 }  // namespace
 }  // namespace bookmarks
diff --git a/components/chrome_apps/webstore_widget/app/main.js b/components/chrome_apps/webstore_widget/app/main.js
index aca72b3d..2495c5e 100644
--- a/components/chrome_apps/webstore_widget/app/main.js
+++ b/components/chrome_apps/webstore_widget/app/main.js
@@ -40,7 +40,8 @@
   'LINK_TO_WEBSTORE': '[LOCALIZE ME] Learn more...',
   'INSTALLATION_FAILED_MESSAGE': '[LOCALIZE ME] Installation failed!',
   'OK_BUTTON': '[LOCALIZE ME] OK',
-  'TITLE_PRINTER_PROVIDERS': '[LOCALIZE ME] Select app for your printer'
+  'TITLE_PRINTER_PROVIDERS': '[LOCALIZE ME] Select app for your printer',
+  'DEFAULT_ERROR_MESSAGE': '[LOCALIZE ME] Failure'
 };
 
 /**
@@ -121,7 +122,7 @@
 function initializeTopbarButtons() {
   $('close-button').addEventListener('click', function(e) {
     e.preventDefault();
-    chrome.app.window.current().close();
+    closeAppWindow();
   });
 
   $('close-button').addEventListener('mousedown', function(e) {
@@ -138,6 +139,27 @@
   });
 }
 
+/**
+ * @param {!CWSWidgetContainer.Result} result The result reported by the widget.
+ */
+function showWidgetResult(result) {
+  // TODO(tbarzic): Add some UI to show on success.
+  if (result != CWSWidgetContainer.Result.FAILED) {
+    closeAppWindow();
+    return;
+  }
+
+  var dialog = new CWSWidgetContainerErrorDialog($('widget-container-root'));
+  dialog.show(getString('DEFAULT_ERROR_MESSAGE'),
+              closeAppWindow,
+              closeAppWindow);
+}
+
+/** Closes the current app window. */
+function closeAppWindow() {
+  chrome.app.window.current().close();
+}
+
 window.addEventListener('DOMContentLoaded', function() {
   initializeTopbarButtons();
 
@@ -176,12 +198,15 @@
         })
         /** @param {!CWSWidgetContainer.ResolveReason} reason */
         .then(function(reason) {
-          chrome.app.window.current().close();
+          if (reason != CWSWidgetContainer.ResolveReason.DONE)
+            return;
+
+          var result = widgetContainer.finalizeAndGetResult();
+          showWidgetResult(result.result);
         })
         /** @param {*} error */
         .catch(function(error) {
-          // TODO(tbarzic): Add error UI.
-          console.error(error);
+          showWidgetResult(CWSWidgetContainer.Result.FAILED);
         });
   });
 });
diff --git a/components/chrome_apps/webstore_widget/cws_widget/cws_widget_container.js b/components/chrome_apps/webstore_widget/cws_widget/cws_widget_container.js
index 7cffe7a..55640997 100644
--- a/components/chrome_apps/webstore_widget/cws_widget/cws_widget_container.js
+++ b/components/chrome_apps/webstore_widget/cws_widget/cws_widget_container.js
@@ -369,6 +369,8 @@
       return;
     }
 
+    this.spinnerLayerController_.setVisible(true);
+
     this.metricsRecorder_.recordShowDialog();
     this.metricsRecorder_.startLoad();
 
@@ -379,6 +381,7 @@
       this.accessToken_ = accessToken;
       resolve();
     }.bind(this), function(error) {
+      this.spinnerLayerController_.setVisible(false);
       this.state_ = CWSWidgetContainer.State.UNINITIALIZED;
       reject('Failed to get Web Store access token: ' + error);
     }.bind(this));
@@ -823,8 +826,7 @@
   this.visible_ = visible;
 
   // Spinner should be shown during transition.
-  if (!this.spinnerLayer_.classList.contains('cws-widget-show-spinner'))
-    this.spinnerLayer_.classList.add('cws-widget-show-spinner');
+  this.spinnerLayer_.classList.toggle('cws-widget-show-spinner', true);
 
   if (this.visible_) {
     this.spinnerLayer_.focus();
diff --git a/components/cloud_devices/common/cloud_device_description.cc b/components/cloud_devices/common/cloud_device_description.cc
index d1cb5041..ba29908 100644
--- a/components/cloud_devices/common/cloud_device_description.cc
+++ b/components/cloud_devices/common/cloud_device_description.cc
@@ -47,7 +47,7 @@
 std::string CloudDeviceDescription::ToString() const {
   std::string json;
   base::JSONWriter::WriteWithOptions(
-      root_.get(), base::JSONWriter::OPTIONS_PRETTY_PRINT, &json);
+      *root_, base::JSONWriter::OPTIONS_PRETTY_PRINT, &json);
   return json;
 }
 
diff --git a/components/cloud_devices/common/printer_description_unittest.cc b/components/cloud_devices/common/printer_description_unittest.cc
index c1fb455..5c8b182f 100644
--- a/components/cloud_devices/common/printer_description_unittest.cc
+++ b/components/cloud_devices/common/printer_description_unittest.cc
@@ -22,7 +22,7 @@
   base::ReplaceChars(result, "'", "\"", &result);
   scoped_ptr<base::Value> value(base::JSONReader::Read(result));
   DCHECK(value);
-  base::JSONWriter::Write(value.get(), &result);
+  base::JSONWriter::Write(*value, &result);
   return result;
 }
 
diff --git a/components/components_tests.gyp b/components/components_tests.gyp
index 1578e704..c5ca9d30 100644
--- a/components/components_tests.gyp
+++ b/components/components_tests.gyp
@@ -110,9 +110,11 @@
       'data_reduction_proxy/core/browser/data_reduction_proxy_bypass_protocol_unittest.cc',
       'data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats_unittest.cc',
       'data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats_unittest.cc',
+      'data_reduction_proxy/core/browser/data_reduction_proxy_config_retrieval_params_unittest.cc',
       'data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_unittest.cc',
       'data_reduction_proxy/core/browser/data_reduction_proxy_config_unittest.cc',
       'data_reduction_proxy/core/browser/data_reduction_proxy_configurator_unittest.cc',
+      'data_reduction_proxy/core/browser/data_reduction_proxy_experiments_stats_unittest.cc',
       'data_reduction_proxy/core/browser/data_reduction_proxy_interceptor_unittest.cc',
       'data_reduction_proxy/core/browser/data_reduction_proxy_io_data_unittest.cc',
       'data_reduction_proxy/core/browser/data_reduction_proxy_metrics_unittest.cc',
diff --git a/components/cronet/android/cronet_data_reduction_proxy.cc b/components/cronet/android/cronet_data_reduction_proxy.cc
index 1a052346d..f6f47ef3 100644
--- a/components/cronet/android/cronet_data_reduction_proxy.cc
+++ b/components/cronet/android/cronet_data_reduction_proxy.cc
@@ -116,7 +116,7 @@
   scoped_ptr<data_reduction_proxy::DataReductionProxyService>
       data_reduction_proxy_service(
           new data_reduction_proxy::DataReductionProxyService(
-              compression_stats.Pass(), settings_.get(),
+              compression_stats.Pass(), settings_.get(), prefs_.get(),
               url_request_context_getter_.get(), task_runner_));
   io_data_->SetDataReductionProxyService(
       data_reduction_proxy_service->GetWeakPtr());
diff --git a/components/cronet/android/java/src/org/chromium/net/ChromiumUrlRequest.java b/components/cronet/android/java/src/org/chromium/net/ChromiumUrlRequest.java
index afccf84..f369e06 100644
--- a/components/cronet/android/java/src/org/chromium/net/ChromiumUrlRequest.java
+++ b/components/cronet/android/java/src/org/chromium/net/ChromiumUrlRequest.java
@@ -6,13 +6,13 @@
 
 import android.util.Log;
 
-import org.apache.http.conn.ConnectTimeoutException;
 import org.chromium.base.CalledByNative;
 import org.chromium.base.JNINamespace;
 import org.chromium.base.annotations.SuppressFBWarnings;
 
 import java.io.IOException;
 import java.net.MalformedURLException;
+import java.net.SocketTimeoutException;
 import java.net.URL;
 import java.net.UnknownHostException;
 import java.nio.ByteBuffer;
@@ -186,7 +186,7 @@
             case ChromiumUrlRequestError.MALFORMED_URL:
                 return new MalformedURLException("Malformed URL: " + mUrl);
             case ChromiumUrlRequestError.CONNECTION_TIMED_OUT:
-                return new ConnectTimeoutException("Connection timed out");
+                return new SocketTimeoutException("Connection timed out");
             case ChromiumUrlRequestError.UNKNOWN_HOST:
                 String host;
                 try {
diff --git a/components/cronet/android/java/src/org/chromium/net/HttpUrlConnectionUrlRequest.java b/components/cronet/android/java/src/org/chromium/net/HttpUrlConnectionUrlRequest.java
index 88e97ea3..21a2e35 100644
--- a/components/cronet/android/java/src/org/chromium/net/HttpUrlConnectionUrlRequest.java
+++ b/components/cronet/android/java/src/org/chromium/net/HttpUrlConnectionUrlRequest.java
@@ -7,8 +7,6 @@
 import android.content.Context;
 import android.text.TextUtils;
 
-import org.apache.http.HttpStatus;
-
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
@@ -283,7 +281,7 @@
 
             if (mOffset != 0) {
                 // The server may ignore the request for a byte range.
-                if (mHttpStatusCode == HttpStatus.SC_OK) {
+                if (mHttpStatusCode == HttpURLConnection.HTTP_OK) {
                     if (mContentLength != -1) {
                         mContentLength -= mOffset;
                     }
@@ -447,8 +445,8 @@
         // the status code will be 206, not 200. Since the rest of the
         // application is
         // expecting 200 to indicate success, we need to fake it.
-        if (httpStatusCode == HttpStatus.SC_PARTIAL_CONTENT) {
-            httpStatusCode = HttpStatus.SC_OK;
+        if (httpStatusCode == HttpURLConnection.HTTP_PARTIAL) {
+            httpStatusCode = HttpURLConnection.HTTP_OK;
         }
         return httpStatusCode;
     }
diff --git a/components/data_reduction_proxy.gypi b/components/data_reduction_proxy.gypi
index 2fa94c2..4742760e 100644
--- a/components/data_reduction_proxy.gypi
+++ b/components/data_reduction_proxy.gypi
@@ -17,12 +17,16 @@
         'data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.h',
         'data_reduction_proxy/core/browser/data_reduction_proxy_config.cc',
         'data_reduction_proxy/core/browser/data_reduction_proxy_config.h',
+        'data_reduction_proxy/core/browser/data_reduction_proxy_config_retrieval_params.cc',
+        'data_reduction_proxy/core/browser/data_reduction_proxy_config_retrieval_params.h',
         'data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.cc',
         'data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.h',
         'data_reduction_proxy/core/browser/data_reduction_proxy_configurator.cc',
         'data_reduction_proxy/core/browser/data_reduction_proxy_configurator.h',
         'data_reduction_proxy/core/browser/data_reduction_proxy_delegate.cc',
         'data_reduction_proxy/core/browser/data_reduction_proxy_delegate.h',
+        'data_reduction_proxy/core/browser/data_reduction_proxy_experiments_stats.cc',
+        'data_reduction_proxy/core/browser/data_reduction_proxy_experiments_stats.h',
         'data_reduction_proxy/core/browser/data_reduction_proxy_interceptor.cc',
         'data_reduction_proxy/core/browser/data_reduction_proxy_interceptor.h',
         'data_reduction_proxy/core/browser/data_reduction_proxy_io_data.cc',
diff --git a/components/data_reduction_proxy/DEPS b/components/data_reduction_proxy/DEPS
index 54740c7b..596361d 100644
--- a/components/data_reduction_proxy/DEPS
+++ b/components/data_reduction_proxy/DEPS
@@ -1,5 +1,6 @@
 include_rules = [
   "+components/pref_registry",
+  "+components/variations",
   "+crypto",
   "+google_apis",
   "+net",
diff --git a/components/data_reduction_proxy/core/browser/BUILD.gn b/components/data_reduction_proxy/core/browser/BUILD.gn
index a292f6b..22e939a 100644
--- a/components/data_reduction_proxy/core/browser/BUILD.gn
+++ b/components/data_reduction_proxy/core/browser/BUILD.gn
@@ -12,6 +12,8 @@
     "data_reduction_proxy_compression_stats.h",
     "data_reduction_proxy_config.cc",
     "data_reduction_proxy_config.h",
+    "data_reduction_proxy_config_retrieval_params.cc",
+    "data_reduction_proxy_config_retrieval_params.h",
     "data_reduction_proxy_config_service_client.cc",
     "data_reduction_proxy_config_service_client.h",
     "data_reduction_proxy_configurator.cc",
@@ -19,6 +21,8 @@
     "data_reduction_proxy_debug_ui_service.h",
     "data_reduction_proxy_delegate.cc",
     "data_reduction_proxy_delegate.h",
+    "data_reduction_proxy_experiments_stats.cc",
+    "data_reduction_proxy_experiments_stats.h",
     "data_reduction_proxy_interceptor.cc",
     "data_reduction_proxy_interceptor.h",
     "data_reduction_proxy_io_data.cc",
@@ -93,9 +97,11 @@
     "data_reduction_proxy_bypass_protocol_unittest.cc",
     "data_reduction_proxy_bypass_stats_unittest.cc",
     "data_reduction_proxy_compression_stats_unittest.cc",
+    "data_reduction_proxy_config_retrieval_params_unittest.cc",
     "data_reduction_proxy_config_service_client_unittest.cc",
     "data_reduction_proxy_config_unittest.cc",
     "data_reduction_proxy_configurator_unittest.cc",
+    "data_reduction_proxy_experiments_stats_unittest.cc",
     "data_reduction_proxy_interceptor_unittest.cc",
     "data_reduction_proxy_io_data_unittest.cc",
     "data_reduction_proxy_metrics_unittest.cc",
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats.cc
index d1796571..1664cc1 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats.cc
@@ -223,6 +223,21 @@
   }
 }
 
+void DataReductionProxyBypassStats::ClearRequestCounts() {
+  successful_requests_through_proxy_count_ = 0;
+  proxy_net_errors_count_ = 0;
+}
+
+void DataReductionProxyBypassStats::NotifyUnavailabilityIfChanged() {
+  bool prev_unavailable = unavailable_;
+  unavailable_ =
+      (proxy_net_errors_count_ >= kMinFailedRequestsWhenUnavailable &&
+       successful_requests_through_proxy_count_ <=
+           kMaxSuccessfulRequestsWhenUnavailable);
+  if (prev_unavailable != unavailable_)
+    unreachable_callback_.Run(unavailable_);
+}
+
 void DataReductionProxyBypassStats::RecordBypassedBytesHistograms(
     const net::URLRequest& request,
     bool data_reduction_proxy_enabled,
@@ -365,21 +380,6 @@
   ClearRequestCounts();
 }
 
-void DataReductionProxyBypassStats::ClearRequestCounts() {
-  successful_requests_through_proxy_count_ = 0;
-  proxy_net_errors_count_ = 0;
-}
-
-void DataReductionProxyBypassStats::NotifyUnavailabilityIfChanged() {
-  bool prev_unavailable = unavailable_;
-  unavailable_ =
-      (proxy_net_errors_count_ >= kMinFailedRequestsWhenUnavailable &&
-       successful_requests_through_proxy_count_ <=
-           kMaxSuccessfulRequestsWhenUnavailable);
-  if (prev_unavailable != unavailable_)
-    unreachable_callback_.Run(unavailable_);
-}
-
 void DataReductionProxyBypassStats::RecordBypassedBytes(
     DataReductionProxyBypassType bypass_type,
     DataReductionProxyBypassStats::BypassedBytesType bypassed_bytes_type,
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats.h
index dcec95e..b13dc949 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats.h
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats.h
@@ -80,6 +80,14 @@
   void OnConnectComplete(const net::HostPortPair& proxy_server,
                          int net_error);
 
+  // Unconditionally clears counts of successful requests and net errors when
+  // using the Data Reduction Proxy.
+  void ClearRequestCounts();
+
+  // Checks if the availability status of the Data Reduction Proxy has changed,
+  // and calls |unreachable_callback_| if so.
+  void NotifyUnavailabilityIfChanged();
+
  private:
   friend class DataReductionProxyBypassStatsTest;
   FRIEND_TEST_ALL_PREFIXES(DataReductionProxyBypassStatsTest,
@@ -115,17 +123,6 @@
   void OnNetworkChanged(
       net::NetworkChangeNotifier::ConnectionType type) override;
 
-  // Clears request counts unconditionally.
-  void ClearRequestCounts();
-
-  // Checks if the availability status of the data reduction proxy has changed,
-  // and notifies the UIThread via NotifyUnavailabilityOnUIThread if so. The
-  // data reduction proxy is considered unavailable if and only if no requests
-  // went through the proxy but some eligible requests were service by other
-  // routes.
-  void NotifyUnavailabilityIfChanged();
-  void NotifyUnavailabilityOnUIThread(bool unavailable);
-
   void RecordBypassedBytes(
       DataReductionProxyBypassType bypass_type,
       BypassedBytesType bypassed_bytes_type,
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_retrieval_params.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_retrieval_params.cc
new file mode 100644
index 0000000..9379f67
--- /dev/null
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_retrieval_params.cc
@@ -0,0 +1,270 @@
+// 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 "components/data_reduction_proxy/core/browser/data_reduction_proxy_config_retrieval_params.h"
+
+#include "base/metrics/field_trial.h"
+#include "base/metrics/histogram.h"
+#include "base/prefs/pref_service.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_piece.h"
+#include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h"
+#include "components/variations/variations_associated_data.h"
+
+namespace {
+
+// The trial group prefix for which an experiment is considered enabled.
+const char kEnabled[] = "Enabled";
+
+// The minimum interval (in seconds) at which the config retrieval can occur.
+const int kConfigFetchMinimumIntervalSeconds = 300;
+
+// The default latency base for retrieving the config.
+const int kConfigFetchDefaultRoundtripMillisecondsBase = 100;
+
+// The default latency base for retrieving the config.
+const double kConfigFetchDefaultRoundtripMultiplier = 1.0;
+
+// The default latency base for retrieving the config.
+const int kConfigFetchDefaultRoundtripMillisecondsIncrement = 100;
+
+// The minimum Data Reduction Proxy configuration expiration.
+const int kConfigFetchMinimumExpirationSeconds = 5 * 60;
+
+// The default Data Reduction Proxy configuration expiration.
+const int kConfigFetchDefaultExpirationSeconds = 24 * 60 * 60;
+
+// Based on a histogram prefix |histogram| and |suffix|, retrieves the
+// histogram for the expanded histogram name. The histogram is identical to
+// the used in UMA_HISTOGRAM_COUNTS.
+base::HistogramBase* GetHistogramWithSuffix(const char* histogram, int suffix) {
+  std::string full_histogram_name = histogram + base::IntToString(suffix);
+  return base::Histogram::FactoryGet(
+      full_histogram_name, 1, 1000000, 50,
+      base::HistogramBase::kUmaTargetedHistogramFlag);
+}
+
+// Retrieves the boolean stored in |variation| from the field trial group
+// |group|. If the value is not present or cannot be parsed, returns
+// |default_value|.
+bool GetVariationBoolWithDefault(const char* group,
+                                 const char* variation,
+                                 bool default_value) {
+  std::string variation_value =
+      variations::GetVariationParamValue(group, variation);
+  int64 variation_numeric;
+  if (variation_value.empty() ||
+      !base::StringToInt64(variation_value, &variation_numeric)) {
+    return default_value;
+  }
+
+  return variation_numeric != 0;
+}
+
+// Retrieves the int64 stored in |variation| from the field trial group
+// |group|. If the value is not present, cannot be parsed, or is less than
+// |min_value|, returns |default_value|.
+int64 GetVariationInt64WithDefault(const char* group,
+                                   const char* variation,
+                                   int64 default_value,
+                                   int64 min_value) {
+  DCHECK(default_value >= min_value);
+  std::string variation_value =
+      variations::GetVariationParamValue(group, variation);
+  int64 variation_numeric;
+  if (variation_value.empty() ||
+      !base::StringToInt64(variation_value, &variation_numeric) ||
+      variation_numeric < min_value) {
+    return default_value;
+  }
+
+  return variation_numeric;
+}
+
+// Retrieves the double stored in |variation| from the field trial group
+// |group|. If the value is not present, cannot be parsed, or is less than
+// |min_value|, returns |default_value|.
+double GetVariationDoubleWithDefault(const char* group,
+                                     const char* variation,
+                                     double default_value,
+                                     double min_value) {
+  DCHECK(default_value >= min_value);
+  std::string variation_value =
+      variations::GetVariationParamValue(group, variation);
+  double variation_numeric;
+  if (variation_value.empty() ||
+      !base::StringToDouble(variation_value, &variation_numeric) ||
+      variation_numeric < min_value) {
+    return default_value;
+  }
+
+  return variation_numeric;
+}
+
+}  // namespace
+
+namespace data_reduction_proxy {
+
+const int kConfigFetchGroups = 10;
+
+const char kConfigFetchTrialGroup[] = "DataReductionProxyConfigFetchBytes";
+
+const char kConfigRoundtripMillisecondsBaseParam[] =
+    "config_roundtrip_milliseconds_base";
+
+const char kConfigRoundtripMultiplierParam[] = "config_roundtrip_multiplier";
+
+const char kConfigRoundtripMillisecondsIncrementParam[] =
+    "config_roundtrip_milliseconds_increment";
+
+const char kConfigExpirationSecondsParam[] = "config_expiration_seconds";
+
+const char kConfigAlwaysStaleParam[] = "always_stale";
+
+const int kConfigFetchBufferSeconds = 300;
+
+// static
+scoped_ptr<DataReductionProxyConfigRetrievalParams>
+DataReductionProxyConfigRetrievalParams::Create(PrefService* pref_service) {
+  std::string group_value =
+      base::FieldTrialList::FindFullName(kConfigFetchTrialGroup);
+  base::StringPiece group = group_value;
+  if (!group.starts_with(kEnabled))
+    return scoped_ptr<DataReductionProxyConfigRetrievalParams>();
+
+  base::Time now = base::Time::Now();
+  base::Time config_retrieve;
+  bool config_always_stale = GetVariationBoolWithDefault(
+      kConfigFetchTrialGroup, kConfigAlwaysStaleParam, false);
+  if (config_always_stale) {
+    config_retrieve = base::Time();
+  } else {
+    int64 config_retrieve_value =
+        pref_service->GetInt64(prefs::kSimulatedConfigRetrieveTime);
+    config_retrieve = base::Time::FromInternalValue(config_retrieve_value);
+    if (config_retrieve > now)
+      config_retrieve = base::Time();
+  }
+
+  int64 config_expiration_interval_seconds = GetVariationInt64WithDefault(
+      kConfigFetchTrialGroup, kConfigExpirationSecondsParam,
+      kConfigFetchDefaultExpirationSeconds,
+      kConfigFetchMinimumExpirationSeconds);
+  base::TimeDelta config_expiration_interval =
+      base::TimeDelta::FromSeconds(config_expiration_interval_seconds);
+  base::Time config_expiration = config_retrieve + config_expiration_interval;
+  std::vector<Variation> variations;
+  bool expired_config = (now > config_expiration);
+  if (expired_config) {
+    config_expiration = now + config_expiration_interval;
+
+    int64 config_roundtrip_milliseconds = GetVariationInt64WithDefault(
+        kConfigFetchTrialGroup, kConfigRoundtripMillisecondsBaseParam,
+        kConfigFetchDefaultRoundtripMillisecondsBase, 0);
+    double config_roundtrip_multiplier = GetVariationDoubleWithDefault(
+        kConfigFetchTrialGroup, kConfigRoundtripMultiplierParam,
+        kConfigFetchDefaultRoundtripMultiplier, 1.0);
+    int64 roundtrip_milliseconds_increment = GetVariationInt64WithDefault(
+        kConfigFetchTrialGroup, kConfigRoundtripMillisecondsIncrementParam,
+        kConfigFetchDefaultRoundtripMillisecondsIncrement, 0);
+
+    for (int params_index = 0; params_index < kConfigFetchGroups;
+         ++params_index) {
+      base::Time config_retrieved = now + base::TimeDelta::FromMilliseconds(
+                                              config_roundtrip_milliseconds);
+      variations.push_back(Variation(params_index, config_retrieved));
+      config_roundtrip_milliseconds *= config_roundtrip_multiplier;
+      config_roundtrip_milliseconds += roundtrip_milliseconds_increment;
+    }
+  }
+
+  return scoped_ptr<DataReductionProxyConfigRetrievalParams>(
+      new DataReductionProxyConfigRetrievalParams(expired_config, variations,
+                                                  config_expiration,
+                                                  config_expiration_interval));
+}
+
+DataReductionProxyConfigRetrievalParams::Variation::Variation(
+    int index,
+    const base::Time& simulated_config_retrieved)
+    : simulated_config_retrieved_(simulated_config_retrieved) {
+  lost_bytes_ocl_ = GetHistogramWithSuffix(
+      "DataReductionProxy.ConfigFetchLostBytesOCL_", index);
+  lost_bytes_rcl_ = GetHistogramWithSuffix(
+      "DataReductionProxy.ConfigFetchLostBytesCL_", index);
+  lost_bytes_diff_ = GetHistogramWithSuffix(
+      "DataReductionProxy.ConfigFetchLostBytesDiff_", index);
+}
+
+DataReductionProxyConfigRetrievalParams::ConfigState
+DataReductionProxyConfigRetrievalParams::Variation::GetState(
+    const base::Time& request_time,
+    const base::Time& config_expiration) const {
+  if (!simulated_config_retrieved_.is_null() &&
+      request_time < simulated_config_retrieved_) {
+    return DataReductionProxyConfigRetrievalParams::RETRIEVING;
+  } else if (request_time < config_expiration) {
+    return DataReductionProxyConfigRetrievalParams::VALID;
+  }
+
+  return DataReductionProxyConfigRetrievalParams::EXPIRED;
+}
+
+void DataReductionProxyConfigRetrievalParams::Variation::RecordStats(
+    int64 received_content_length,
+    int64 original_content_length) const {
+  lost_bytes_rcl_->Add(received_content_length);
+  lost_bytes_ocl_->Add(original_content_length);
+  int64 content_length_diff = original_content_length - received_content_length;
+  if (content_length_diff > 0)
+    lost_bytes_diff_->Add(content_length_diff);
+}
+
+DataReductionProxyConfigRetrievalParams::
+    DataReductionProxyConfigRetrievalParams(
+        bool loaded_expired_config,
+        const std::vector<Variation>& variations,
+        const base::Time& config_expiration,
+        const base::TimeDelta& config_expiration_interval)
+    : loaded_expired_config_(loaded_expired_config),
+      config_expiration_(config_expiration),
+      config_expiration_interval_(config_expiration_interval),
+      variations_(variations) {
+  config_refresh_interval_ =
+      config_expiration_interval_ -
+      base::TimeDelta::FromSeconds(kConfigFetchBufferSeconds);
+  if (config_refresh_interval_.InSeconds() <
+      kConfigFetchMinimumIntervalSeconds) {
+    config_refresh_interval_ =
+        base::TimeDelta::FromSeconds(kConfigFetchMinimumIntervalSeconds);
+  }
+}
+
+DataReductionProxyConfigRetrievalParams::
+    ~DataReductionProxyConfigRetrievalParams() {
+}
+
+void DataReductionProxyConfigRetrievalParams::RecordStats(
+    const base::Time& request_time,
+    int64 received_content_length,
+    int64 original_content_length) const {
+  for (const auto& variation : variations_) {
+    switch (variation.GetState(request_time, config_expiration_)) {
+      case VALID:
+        break;
+      case RETRIEVING:
+      case EXPIRED:
+        variation.RecordStats(received_content_length, original_content_length);
+        break;
+      default:
+        NOTREACHED();
+    }
+  }
+}
+
+void DataReductionProxyConfigRetrievalParams::RefreshConfig() {
+  config_expiration_ = base::Time::Now() + config_expiration_interval_;
+}
+
+}  // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_retrieval_params.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_retrieval_params.h
new file mode 100644
index 0000000..53aa10a
--- /dev/null
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_retrieval_params.h
@@ -0,0 +1,154 @@
+// 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 COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DATA_REDUCTION_PROXY_CONFIG_RETRIEVAL_PARAMS_H_
+#define COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DATA_REDUCTION_PROXY_CONFIG_RETRIEVAL_PARAMS_H_
+
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/time/time.h"
+
+class PrefService;
+
+namespace base {
+class HistogramBase;
+}
+
+namespace data_reduction_proxy {
+
+// The number of config fetch variations supported. Must match the number of
+// suffixes in histograms.xml.
+extern const int kConfigFetchGroups;
+
+// The name of the trial group for measuring lost bytes during fetching the
+// configuration.
+extern const char kConfigFetchTrialGroup[];
+
+// The config retrieval round trip time is calculated as:
+// (previous base) * (multiplier) + increment.
+// Multipler is >= 1. Increment is >= 0.
+// The name of the param prefix for determining the base round trip time in
+// milliseconds for simulating a configuration fetch.
+extern const char kConfigRoundtripMillisecondsBaseParam[];
+
+// The name of the param prefix for determining the base round trip time in
+// milliseconds for simulating a configuration fetch.
+extern const char kConfigRoundtripMultiplierParam[];
+
+// The name of the param prefix for determining the base round trip time in
+// milliseconds for simulating a configuration fetch.
+extern const char kConfigRoundtripMillisecondsIncrementParam[];
+
+// The name of the param for determining the expiration interval of the
+// configuration in seconds.
+extern const char kConfigExpirationSecondsParam[];
+
+// The name of the param for determining if the config should be considered
+// stale on startup (regardless of whether it is stale or not).
+extern const char kConfigAlwaysStaleParam[];
+
+// The number of seconds by which the expiration interval exceeds the refresh
+// interval so that we maintain a valid configuration.
+extern const int kConfigFetchBufferSeconds;
+
+// Parameters for setting up an experiment to measure potentially uncompressed
+// bytes during the retrieval of the Data Reduction Proxy configuration.
+class DataReductionProxyConfigRetrievalParams {
+ public:
+  enum ConfigState {
+    VALID = 0,
+    RETRIEVING = 1,
+    EXPIRED = 2,
+  };
+
+  // A variation of the simulated configuration retrieval time, permitting the
+  // experiment to measure multiple values.
+  class Variation {
+   public:
+    Variation(int index, const base::Time& simulated_config_retrieved);
+
+    // Returns the current state of the Data Reduction Proxy configuration.
+    // Virtual for testing.
+    virtual ConfigState GetState(const base::Time& request_time,
+                                 const base::Time& config_expiration) const;
+
+    // Records content length statistics if potentially uncompressed bytes have
+    // been detected for this variation.
+    void RecordStats(int64 received_content_length,
+                     int64 original_content_length) const;
+
+    // Visible for testing.
+    const base::Time& simulated_config_retrieved() const {
+      return simulated_config_retrieved_;
+    }
+
+   private:
+    // The time at which the simulated Data Reduction Proxy configuration is
+    // considered to have been received.
+    base::Time simulated_config_retrieved_;
+
+    // Histograms for recording stats.
+    base::HistogramBase* lost_bytes_ocl_;
+    base::HistogramBase* lost_bytes_rcl_;
+    base::HistogramBase* lost_bytes_diff_;
+  };
+
+  static scoped_ptr<DataReductionProxyConfigRetrievalParams> Create(
+      PrefService* pref_service);
+
+  virtual ~DataReductionProxyConfigRetrievalParams();
+
+  // Records content length statistics against any variations for which
+  // potentially uncompressed bytes have been detected.
+  void RecordStats(const base::Time& request_time,
+                   int64 received_content_length,
+                   int64 original_content_length) const;
+
+  // Simulates retrieving a new configuration.
+  void RefreshConfig();
+
+  bool loaded_expired_config() const { return loaded_expired_config_; }
+
+  // Returns the expiration time of the current configuration.
+  const base::Time& config_expiration() const { return config_expiration_; }
+
+  // Returns how often the configuration should be retrieved.
+  const base::TimeDelta& refresh_interval() const {
+    return config_refresh_interval_;
+  }
+
+  // Visible for testing.
+  const std::vector<Variation>& variations() const { return variations_; }
+
+ private:
+  DataReductionProxyConfigRetrievalParams(
+      bool loaded_expired_config,
+      const std::vector<Variation>& variations,
+      const base::Time& config_expiration,
+      const base::TimeDelta& config_refresh_interval);
+
+  // Indicates that the Data Reduction Proxy configuration when loaded has
+  // expired.
+  bool loaded_expired_config_;
+
+  // The time at which the simulated Data Reduction Proxy configuration
+  // expires.
+  base::Time config_expiration_;
+
+  // The duration for which a Data Reduction Proxy configuration is considered
+  // valid.
+  base::TimeDelta config_expiration_interval_;
+
+  // The duration after which a simulated retrieval of a new Data Reduction
+  // Proxy configuration should be performed.
+  base::TimeDelta config_refresh_interval_;
+
+  // The different variations on roundtrip time that can take place.
+  std::vector<Variation> variations_;
+};
+
+}  // namespace data_reduction_proxy
+#endif  // COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DATA_REDUCTION_PROXY_CONFIG_RETRIEVAL_PARAMS_H_
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_retrieval_params_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_retrieval_params_unittest.cc
new file mode 100644
index 0000000..02f82cb
--- /dev/null
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_retrieval_params_unittest.cc
@@ -0,0 +1,228 @@
+// 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 "components/data_reduction_proxy/core/browser/data_reduction_proxy_config_retrieval_params.h"
+
+#include <map>
+
+#include "base/message_loop/message_loop.h"
+#include "base/prefs/pref_service.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/time/time.h"
+#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h"
+#include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h"
+#include "components/variations/variations_associated_data.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+// Test value for how long a Data Reduction Proxy configuration should be valid.
+const int64 kConfigExpirationSeconds = 60 * 60 * 24;
+
+// Checks that |actual| falls in the range of |min| + |delta| and
+// |max| + |delta|.
+void ExpectInTimeRange(const base::Time& min,
+                       const base::Time& max,
+                       const base::TimeDelta& delta,
+                       const base::Time& actual) {
+  EXPECT_GE(actual, min + delta);
+  EXPECT_LE(actual, max + delta);
+}
+
+}  // namespace
+
+namespace data_reduction_proxy {
+
+class DataReductionProxyConfigRetrievalParamsTest : public testing::Test {
+ protected:
+  void SetUp() override {
+    test_context_ = DataReductionProxyTestContext::Builder().Build();
+  }
+
+  void SetConfigExperimentValues(
+      bool enabled,
+      const base::TimeDelta& retrieve_offset_from_now,
+      int64 roundtrip_milliseconds_base,
+      double roundtrip_multiplier,
+      int64 roundtrip_milliseconds_increment,
+      int64 expiration_seconds,
+      bool always_stale) {
+    variations::testing::ClearAllVariationParams();
+    std::map<std::string, std::string> variation_params;
+    variation_params[kConfigRoundtripMillisecondsBaseParam] =
+        base::Int64ToString(roundtrip_milliseconds_base);
+    variation_params[kConfigRoundtripMultiplierParam] =
+        base::DoubleToString(roundtrip_multiplier);
+    variation_params[kConfigRoundtripMillisecondsIncrementParam] =
+        base::Int64ToString(roundtrip_milliseconds_increment);
+    variation_params[kConfigExpirationSecondsParam] =
+        base::Int64ToString(expiration_seconds);
+    variation_params[kConfigAlwaysStaleParam] = always_stale ? "1" : "0:";
+    if (enabled) {
+      ASSERT_TRUE(variations::AssociateVariationParams(
+          kConfigFetchTrialGroup, "Enabled", variation_params));
+    }
+    pref_service()->SetInt64(
+        prefs::kSimulatedConfigRetrieveTime,
+        (base::Time::Now() + retrieve_offset_from_now).ToInternalValue());
+  }
+
+  PrefService* pref_service() { return test_context_->pref_service(); }
+
+ private:
+  base::MessageLoopForIO message_loop_;
+  scoped_ptr<DataReductionProxyTestContext> test_context_;
+};
+
+TEST_F(DataReductionProxyConfigRetrievalParamsTest, ExpectedVariations) {
+  struct {
+    bool experiment_enabled;
+    base::TimeDelta retrieve_offset_from_now;
+    int64 expiration_seconds;
+    int64 roundtrip_milliseconds_base;
+    double roundtrip_multiplier;
+    int64 roundtrip_milliseconds_increment;
+    bool always_stale;
+    bool expected_has_variations;
+    base::TimeDelta expected_config_expiration_from_now;
+    base::TimeDelta expected_delta_0;
+    base::TimeDelta expected_delta_2;
+    base::TimeDelta expected_delta_5;
+  } test_cases[] = {
+      // Experiment is disabled.
+      {false,
+       base::TimeDelta::FromHours(-2),
+       kConfigExpirationSeconds,
+       100,
+       2.0,
+       100,
+       false,
+       false,
+       base::TimeDelta(),
+       base::TimeDelta(),
+       base::TimeDelta(),
+       base::TimeDelta()},
+      // Experiment is enabled, but not marked always stale and the last
+      // retrieval is such that the configuration is still valid.
+      {true,
+       base::TimeDelta::FromHours(-2),
+       kConfigExpirationSeconds,
+       100,
+       2.0,
+       100,
+       false,
+       false,
+       base::TimeDelta::FromHours(22),
+       base::TimeDelta(),
+       base::TimeDelta(),
+       base::TimeDelta()},
+      // Experiment is enabled, but not marked always stale with a retrieval
+      // time sufficiently in the past such that the configuration is expired.
+      {
+       true,
+       base::TimeDelta::FromHours(-26),
+       kConfigExpirationSeconds,
+       100,
+       2.0,
+       100,
+       true,
+       true,
+       base::TimeDelta::FromSeconds(kConfigExpirationSeconds),
+       base::TimeDelta::FromMilliseconds(100),
+       base::TimeDelta::FromMilliseconds(700),
+       base::TimeDelta::FromMilliseconds(6300),
+      },
+      // Experiment is enabled, marked always stale and the retrieval time is
+      // recent enough that a configuration would be still valid.
+      {
+       true,
+       base::TimeDelta::FromHours(-2),
+       kConfigExpirationSeconds,
+       100,
+       2.0,
+       100,
+       true,
+       true,
+       base::TimeDelta::FromSeconds(kConfigExpirationSeconds),
+       base::TimeDelta::FromMilliseconds(100),
+       base::TimeDelta::FromMilliseconds(700),
+       base::TimeDelta::FromMilliseconds(6300),
+      },
+      // Experiment is enabled but values are invalid.
+      {
+       true,
+       base::TimeDelta::FromHours(-2),
+       -400,
+       -500,
+       0.5,
+       -300,
+       true,
+       true,
+       base::TimeDelta::FromSeconds(kConfigExpirationSeconds),
+       base::TimeDelta::FromMilliseconds(100),
+       base::TimeDelta::FromMilliseconds(300),
+       base::TimeDelta::FromMilliseconds(600),
+      },
+      // Experiment is enabled, but the last config retrieval time is in the
+      // future and thus ignored.
+      {
+       true,
+       base::TimeDelta::FromHours(26),
+       kConfigExpirationSeconds,
+       100,
+       2.0,
+       100,
+       true,
+       true,
+       base::TimeDelta::FromSeconds(kConfigExpirationSeconds),
+       base::TimeDelta::FromMilliseconds(100),
+       base::TimeDelta::FromMilliseconds(700),
+       base::TimeDelta::FromMilliseconds(6300),
+      },
+  };
+
+  for (const auto& test_case : test_cases) {
+    base::FieldTrialList field_trial_list(nullptr);
+    base::FieldTrialList::CreateFieldTrial(
+        kConfigFetchTrialGroup,
+        test_case.experiment_enabled ? "Enabled" : "Disabled");
+    base::Time min_now = base::Time::Now();
+    SetConfigExperimentValues(
+        test_case.experiment_enabled, test_case.retrieve_offset_from_now,
+        test_case.roundtrip_milliseconds_base, test_case.roundtrip_multiplier,
+        test_case.roundtrip_milliseconds_increment, kConfigExpirationSeconds,
+        test_case.always_stale);
+    scoped_ptr<DataReductionProxyConfigRetrievalParams> config_params =
+        DataReductionProxyConfigRetrievalParams::Create(pref_service());
+    base::Time max_now = base::Time::Now();
+    if (!test_case.experiment_enabled) {
+      EXPECT_EQ(nullptr, config_params.get());
+      continue;
+    }
+
+    EXPECT_NE(nullptr, config_params.get());
+    ExpectInTimeRange(min_now, max_now,
+                      test_case.expected_config_expiration_from_now,
+                      config_params->config_expiration());
+    EXPECT_EQ(config_params->refresh_interval(),
+              base::TimeDelta::FromSeconds(kConfigExpirationSeconds) -
+                  base::TimeDelta::FromSeconds(kConfigFetchBufferSeconds));
+    if (test_case.expected_has_variations) {
+      EXPECT_EQ(kConfigFetchGroups, (int)config_params->variations().size());
+      ExpectInTimeRange(
+          min_now, max_now, test_case.expected_delta_0,
+          config_params->variations()[0].simulated_config_retrieved());
+      ExpectInTimeRange(
+          min_now, max_now, test_case.expected_delta_2,
+          config_params->variations()[2].simulated_config_retrieved());
+      ExpectInTimeRange(
+          min_now, max_now, test_case.expected_delta_5,
+          config_params->variations()[5].simulated_config_retrieved());
+    } else {
+      EXPECT_EQ(0u, config_params->variations().size());
+    }
+  }
+}
+
+}  // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.cc
index d6895cd7..b805682 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.cc
@@ -198,7 +198,7 @@
   scoped_ptr<base::DictionaryValue> values(new base::DictionaryValue());
   params_->PopulateConfigResponse(values.get());
   request_options_->PopulateConfigResponse(values.get());
-  base::JSONWriter::Write(values.get(), &response);
+  base::JSONWriter::Write(*values, &response);
 
   return response;
 }
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_experiments_stats.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_experiments_stats.cc
new file mode 100644
index 0000000..ddf3de1
--- /dev/null
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_experiments_stats.cc
@@ -0,0 +1,67 @@
+// 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 "components/data_reduction_proxy/core/browser/data_reduction_proxy_experiments_stats.h"
+
+#include "base/logging.h"
+#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config_retrieval_params.h"
+#include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h"
+
+namespace data_reduction_proxy {
+
+DataReductionProxyExperimentsStats::DataReductionProxyExperimentsStats(
+    const Int64ValueSetter& value_setter)
+    : value_setter_(value_setter), initialized_(false) {
+  // Constructed on the UI thread, but should be checked on the IO thread.
+  thread_checker_.DetachFromThread();
+}
+
+DataReductionProxyExperimentsStats::~DataReductionProxyExperimentsStats() {
+}
+
+void DataReductionProxyExperimentsStats::InitializeOnUIThread(scoped_ptr<
+    DataReductionProxyConfigRetrievalParams> config_retrieval_params) {
+  DCHECK(!initialized_);
+  config_retrieval_params_ = config_retrieval_params.Pass();
+
+  // This method may be called from the UI thread, but should be checked on the
+  // IO thread.
+  thread_checker_.DetachFromThread();
+}
+
+void DataReductionProxyExperimentsStats::InitializeOnIOThread() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK(!initialized_);
+  initialized_ = true;
+  if (config_retrieval_params_) {
+    if (config_retrieval_params_->loaded_expired_config())
+      UpdateSimulatedConfig();
+    config_refresh_time_.Start(
+        FROM_HERE, config_retrieval_params_->refresh_interval(), this,
+        &DataReductionProxyExperimentsStats::UpdateSimulatedConfig);
+  }
+}
+
+void DataReductionProxyExperimentsStats::RecordBytes(
+    const base::Time& request_time,
+    DataReductionProxyRequestType request_type,
+    int64 received_content_length,
+    int64 original_content_length) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  if (config_retrieval_params_) {
+    // Only measure requests which flowed through the Data Reduction Proxy.
+    if (request_type == VIA_DATA_REDUCTION_PROXY) {
+      config_retrieval_params_->RecordStats(
+          request_time, received_content_length, original_content_length);
+    }
+  }
+}
+
+void DataReductionProxyExperimentsStats::UpdateSimulatedConfig() {
+  DCHECK(config_retrieval_params_);
+  value_setter_.Run(prefs::kSimulatedConfigRetrieveTime,
+                    base::Time::Now().ToInternalValue());
+}
+
+}  // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_experiments_stats.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_experiments_stats.h
new file mode 100644
index 0000000..1806d51
--- /dev/null
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_experiments_stats.h
@@ -0,0 +1,80 @@
+// 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 COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DATA_REDUCTION_PROXY_EXPERIMENTS_STATS_H_
+#define COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DATA_REDUCTION_PROXY_EXPERIMENTS_STATS_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/threading/thread_checker.h"
+#include "base/timer/timer.h"
+#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_metrics.h"
+
+namespace base {
+class Time;
+}
+
+namespace data_reduction_proxy {
+
+class DataReductionProxyConfigRetrievalParams;
+
+typedef base::Callback<void(const std::string&, int64)> Int64ValueSetter;
+
+// Collects statistics specific to experiments of which a client may be part.
+// Any calls into this class should be as lightweight as possible such that if
+// no experiments are being performed, there should be minimal code being
+// executed.
+// Currently supported experiments are:
+// - Measuring potentially uncompressed bytes during simulated config retrieval.
+class DataReductionProxyExperimentsStats {
+ public:
+  DataReductionProxyExperimentsStats(const Int64ValueSetter& value_setter);
+  virtual ~DataReductionProxyExperimentsStats();
+
+  // Initializes |this| on the UI thread. If called, must be called prior to
+  // InitializeOnIOThread.
+  void InitializeOnUIThread(scoped_ptr<DataReductionProxyConfigRetrievalParams>
+                                config_retrieval_params);
+
+  // Initializes |this| on the IO thread.
+  void InitializeOnIOThread();
+
+  // Collect received bytes for the experiment.
+  void RecordBytes(const base::Time& request_time,
+                   DataReductionProxyRequestType request_type,
+                   int64 received_content_length,
+                   int64 original_content_length);
+
+ private:
+  // Updates the simulated expiration of the Data Reduction Proxy configuration
+  // if |config_retrieval_| is set.
+  void UpdateSimulatedConfig();
+
+  // Allows an experiment to persist data to preferences.
+  Int64ValueSetter value_setter_;
+
+  // Enables measuring of potentially uncompressed bytes during a simulated Data
+  // Reduction Proxy configuration retrieval.
+  scoped_ptr<DataReductionProxyConfigRetrievalParams> config_retrieval_params_;
+
+  // If set, periodically updates the simulated expiration of the Data Reduction
+  // Proxy configuration.
+  base::RepeatingTimer<DataReductionProxyExperimentsStats> config_refresh_time_;
+
+  // Enforce initialization order.
+  bool initialized_;
+
+  // Enforce usage on the IO thread.
+  base::ThreadChecker thread_checker_;
+
+  DISALLOW_COPY_AND_ASSIGN(DataReductionProxyExperimentsStats);
+};
+
+}  // namespace data_reduction_proxy
+
+#endif  // COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DATA_REDUCTION_PROXY_EXPERIMENTS_STATS_H_
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_experiments_stats_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_experiments_stats_unittest.cc
new file mode 100644
index 0000000..6b1d2d3
--- /dev/null
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_experiments_stats_unittest.cc
@@ -0,0 +1,163 @@
+// 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 "components/data_reduction_proxy/core/browser/data_reduction_proxy_experiments_stats.h"
+
+#include <map>
+
+#include "base/metrics/field_trial.h"
+#include "base/prefs/pref_service.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/test/histogram_tester.h"
+#include "base/time/time.h"
+#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config_retrieval_params.h"
+#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h"
+#include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h"
+#include "components/variations/variations_associated_data.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+// Test value for how long a Data Reduction Proxy configuration should be valid.
+const int64 kConfigExpirationSeconds = 60 * 60 * 24;
+
+}  // namespace
+
+namespace data_reduction_proxy {
+
+class DataReductionProxyExperimentsStatsTest : public testing::Test {
+ public:
+  void SetPrefValue(const std::string& path, int64 value) {}
+
+ protected:
+  void SetUp() override {
+    test_context_ = DataReductionProxyTestContext::Builder().Build();
+  }
+
+  void SetConfigExperimentValues(
+      bool enabled,
+      const base::TimeDelta& retrieve_offset_from_now,
+      int64 roundtrip_milliseconds_base,
+      double roundtrip_multiplier,
+      int64 roundtrip_milliseconds_increment,
+      int64 expiration_seconds,
+      bool always_stale) {
+    variations::testing::ClearAllVariationParams();
+    std::map<std::string, std::string> variation_params;
+    variation_params[kConfigRoundtripMillisecondsBaseParam] =
+        base::Int64ToString(roundtrip_milliseconds_base);
+    variation_params[kConfigRoundtripMultiplierParam] =
+        base::DoubleToString(roundtrip_multiplier);
+    variation_params[kConfigRoundtripMillisecondsIncrementParam] =
+        base::Int64ToString(roundtrip_milliseconds_increment);
+    variation_params[kConfigExpirationSecondsParam] =
+        base::Int64ToString(expiration_seconds);
+    variation_params[kConfigAlwaysStaleParam] = always_stale ? "1" : "0:";
+    if (enabled) {
+      ASSERT_TRUE(variations::AssociateVariationParams(
+          kConfigFetchTrialGroup, "Enabled", variation_params));
+    }
+    pref_service()->SetInt64(
+        prefs::kSimulatedConfigRetrieveTime,
+        (base::Time::Now() + retrieve_offset_from_now).ToInternalValue());
+  }
+
+  PrefService* pref_service() { return test_context_->pref_service(); }
+
+ private:
+  base::MessageLoopForIO message_loop_;
+  scoped_ptr<DataReductionProxyTestContext> test_context_;
+};
+
+TEST_F(DataReductionProxyExperimentsStatsTest, CheckHistogramsNoExperiments) {
+  scoped_ptr<DataReductionProxyExperimentsStats> experiments_stats(
+      new DataReductionProxyExperimentsStats(
+          base::Bind(&DataReductionProxyExperimentsStatsTest::SetPrefValue,
+                     base::Unretained(this))));
+  experiments_stats->InitializeOnUIThread(
+      scoped_ptr<DataReductionProxyConfigRetrievalParams>());
+  base::HistogramTester histogram_tester;
+  experiments_stats->RecordBytes(base::Time::Now(), VIA_DATA_REDUCTION_PROXY,
+                                 500, 1000);
+  histogram_tester.ExpectTotalCount(
+      "DataReductionProxy.ConfigFetchLostBytesOCL_0", 0);
+  histogram_tester.ExpectTotalCount(
+      "DataReductionProxy.ConfigFetchLostBytesCL_0", 0);
+  histogram_tester.ExpectTotalCount(
+      "DataReductionProxy.ConfigFetchLostBytesDiff_0", 0);
+}
+
+TEST_F(DataReductionProxyExperimentsStatsTest, CheckConfigHistograms) {
+  struct {
+    DataReductionProxyRequestType request_type;
+    base::Time request_time;
+    int64 received_content_length;
+    int64 original_content_length;
+    int64 expected_received_content_length;
+    int64 expected_original_content_length;
+    int64 expected_diff;
+  } test_cases[] = {
+      {
+       VIA_DATA_REDUCTION_PROXY,
+       base::Time::Now() + base::TimeDelta::FromMinutes(5),
+       500,
+       1000,
+       -1,
+       -1,
+       -1,
+      },
+      {
+       VIA_DATA_REDUCTION_PROXY, base::Time::Now(), 500, 1000, 500, 1000, 500,
+      },
+      {
+       HTTPS, base::Time::Now(), 500, 1000, -1, -1, -1,
+      },
+  };
+
+  base::FieldTrialList field_trial_list(nullptr);
+  base::FieldTrialList::CreateFieldTrial(kConfigFetchTrialGroup, "Enabled");
+  SetConfigExperimentValues(true, base::TimeDelta::FromHours(-2), 100, 2.0,
+                            1000, kConfigExpirationSeconds, true);
+  scoped_ptr<DataReductionProxyConfigRetrievalParams> config_params =
+      DataReductionProxyConfigRetrievalParams::Create(pref_service());
+  scoped_ptr<DataReductionProxyExperimentsStats> experiments_stats(
+      new DataReductionProxyExperimentsStats(
+          base::Bind(&DataReductionProxyExperimentsStatsTest::SetPrefValue,
+                     base::Unretained(this))));
+  experiments_stats->InitializeOnUIThread(config_params.Pass());
+  for (const auto& test_case : test_cases) {
+    base::HistogramTester histogram_tester;
+    experiments_stats->RecordBytes(
+        test_case.request_time, test_case.request_type,
+        test_case.received_content_length, test_case.original_content_length);
+    if (test_case.expected_received_content_length == -1) {
+      histogram_tester.ExpectTotalCount(
+          "DataReductionProxy.ConfigFetchLostBytesCL_0", 0);
+    } else {
+      histogram_tester.ExpectUniqueSample(
+          "DataReductionProxy.ConfigFetchLostBytesCL_0",
+          test_case.expected_received_content_length, 1);
+    }
+
+    if (test_case.expected_original_content_length == -1) {
+      histogram_tester.ExpectTotalCount(
+          "DataReductionProxy.ConfigFetchLostBytesOCL_0", 0);
+    } else {
+      histogram_tester.ExpectUniqueSample(
+          "DataReductionProxy.ConfigFetchLostBytesOCL_0",
+          test_case.expected_original_content_length, 1);
+    }
+
+    if (test_case.expected_diff == -1) {
+      histogram_tester.ExpectTotalCount(
+          "DataReductionProxy.ConfigFetchLostBytesDiff_0", 0);
+    } else {
+      histogram_tester.ExpectUniqueSample(
+          "DataReductionProxy.ConfigFetchLostBytesDiff_0",
+          test_case.expected_diff, 1);
+    }
+  }
+}
+
+}  // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.cc
index 50a303c..9c12d24 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.cc
@@ -14,6 +14,7 @@
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_configurator.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.h"
+#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_experiments_stats.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_interceptor.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.h"
@@ -142,6 +143,11 @@
 
   proxy_delegate_.reset(
       new DataReductionProxyDelegate(request_options_.get(), config_.get()));
+  // It is safe to use base::Unretained here, since it gets executed
+  // synchronously on the IO thread, and |this| outlives the caller (since the
+  // caller is owned by |this|.
+  experiments_stats_.reset(new DataReductionProxyExperimentsStats(base::Bind(
+      &DataReductionProxyIOData::SetInt64Pref, base::Unretained(this))));
  }
 
  DataReductionProxyIOData::DataReductionProxyIOData()
@@ -177,6 +183,7 @@
   config_->InitializeOnIOThread(basic_url_request_context_getter_.get());
   if (config_client_.get())
     config_client_->InitializeOnIOThread(url_request_context_getter_);
+  experiments_stats_->InitializeOnIOThread();
   ui_task_runner_->PostTask(
       FROM_HERE,
       base::Bind(&DataReductionProxyService::SetIOData,
@@ -209,18 +216,31 @@
   scoped_ptr<DataReductionProxyNetworkDelegate> network_delegate(
       new DataReductionProxyNetworkDelegate(
           wrapped_network_delegate.Pass(), config_.get(),
-          request_options_.get(), configurator_.get()));
+          request_options_.get(), configurator_.get(),
+          experiments_stats_.get()));
   if (track_proxy_bypass_statistics)
     network_delegate->InitIODataAndUMA(this, bypass_stats_.get());
   return network_delegate.Pass();
 }
 
+// TODO(kundaji): Rename this method to something more descriptive.
+// Bug http://crbug/488190.
 void DataReductionProxyIOData::SetProxyPrefs(bool enabled,
                                              bool alternative_enabled,
                                              bool at_startup) {
   DCHECK(io_task_runner_->BelongsToCurrentThread());
+  DCHECK(url_request_context_getter_->GetURLRequestContext()->proxy_service());
   enabled_ = enabled;
   config_->SetProxyConfig(enabled, alternative_enabled, at_startup);
+
+  // If Data Saver is disabled, reset data reduction proxy state.
+  if (!enabled) {
+    net::ProxyService* proxy_service =
+        url_request_context_getter_->GetURLRequestContext()->proxy_service();
+    proxy_service->ClearBadProxiesCache();
+    bypass_stats_->ClearRequestCounts();
+    bypass_stats_->NotifyUnavailabilityIfChanged();
+  }
 }
 
 void DataReductionProxyIOData::UpdateContentLengths(
@@ -279,4 +299,12 @@
                  service_, unreachable));
 }
 
+void DataReductionProxyIOData::SetInt64Pref(const std::string& pref_path,
+                                            int64 value) {
+  DCHECK(io_task_runner_->BelongsToCurrentThread());
+  ui_task_runner_->PostTask(
+      FROM_HERE, base::Bind(&DataReductionProxyService::SetInt64Pref, service_,
+                            pref_path, value));
+}
+
 }  // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.h
index d68001f6..73a2840 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.h
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.h
@@ -34,6 +34,7 @@
 class DataReductionProxyConfigServiceClient;
 class DataReductionProxyConfigurator;
 class DataReductionProxyEventCreator;
+class DataReductionProxyExperimentsStats;
 class DataReductionProxyService;
 
 // Contains and initializes all Data Reduction Proxy objects that operate on
@@ -60,7 +61,8 @@
   void ShutdownOnUIThread();
 
   // Sets the Data Reduction Proxy service after it has been created.
-  void SetDataReductionProxyService(
+  // Virtual for testing.
+  virtual void SetDataReductionProxyService(
       base::WeakPtr<DataReductionProxyService> data_reduction_proxy_service);
 
   void RetrieveConfig();
@@ -81,9 +83,7 @@
   // configuration should be set. Use the alternative configuration only if
   // |enabled| and |alternative_enabled| are true. |at_startup| is true only
   // when DataReductionProxySettings is initialized.
-  void SetProxyPrefs(bool enabled,
-                     bool alternative_enabled,
-                     bool at_startup);
+  void SetProxyPrefs(bool enabled, bool alternative_enabled, bool at_startup);
 
   // Bridge methods to safely call to the UI thread objects.
   void UpdateContentLengths(int64 received_content_length,
@@ -124,6 +124,10 @@
     return config_client_.get();
   }
 
+  DataReductionProxyExperimentsStats* experiments_stats() const {
+    return experiments_stats_.get();
+  }
+
   net::ProxyDelegate* proxy_delegate() const {
     return proxy_delegate_.get();
   }
@@ -153,6 +157,8 @@
  private:
   friend class TestDataReductionProxyIOData;
   FRIEND_TEST_ALL_PREFIXES(DataReductionProxyIODataTest, TestConstruction);
+  FRIEND_TEST_ALL_PREFIXES(DataReductionProxyIODataTest,
+                           TestResetBadProxyListOnDisableDataSaver);
 
   // Used for testing.
   DataReductionProxyIOData();
@@ -165,6 +171,9 @@
   // Records that the data reduction proxy is unreachable or not.
   void SetUnreachable(bool unreachable);
 
+  // Stores an int64 value in preferences storage.
+  void SetInt64Pref(const std::string& pref_path, int64 value);
+
   // The type of Data Reduction Proxy client.
   Client client_;
 
@@ -197,6 +206,9 @@
   // Requests new Data Reduction Proxy configurations from a remote service.
   scoped_ptr<DataReductionProxyConfigServiceClient> config_client_;
 
+  // Used to track stats for experiments.
+  scoped_ptr<DataReductionProxyExperimentsStats> experiments_stats_;
+
   // A net log.
   net::NetLog* net_log_;
 
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data_unittest.cc
index 24fc634a..80a255b 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data_unittest.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data_unittest.cc
@@ -8,14 +8,21 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_loop.h"
 #include "base/message_loop/message_loop_proxy.h"
+#include "base/prefs/pref_service.h"
 #include "base/prefs/testing_pref_service.h"
+#include "base/run_loop.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/time/time.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_prefs.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.h"
+#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h"
+#include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h"
+
 #include "net/http/http_network_session.h"
 #include "net/log/net_log.h"
+#include "net/proxy/proxy_info.h"
+#include "net/proxy/proxy_service.h"
 #include "net/socket/next_proto.h"
 #include "net/url_request/url_request_context.h"
 #include "net/url_request/url_request_context_getter.h"
@@ -144,4 +151,48 @@
   io_data->ShutdownOnUIThread();
 }
 
+TEST_F(DataReductionProxyIODataTest, TestResetBadProxyListOnDisableDataSaver) {
+  net::TestURLRequestContext context(false);
+  scoped_ptr<DataReductionProxyTestContext> drp_test_context =
+      DataReductionProxyTestContext::Builder()
+          .WithParamsFlags(DataReductionProxyParams::kAllowed |
+                           DataReductionProxyParams::kFallbackAllowed |
+                           DataReductionProxyParams::kPromoAllowed)
+          .WithURLRequestContext(&context)
+          .WithTestConfigurator()
+          .SkipSettingsInitialization()
+          .Build();
+
+  drp_test_context->pref_service()->SetBoolean(
+      prefs::kDataReductionProxyEnabled, true);
+  drp_test_context->InitSettings();
+  DataReductionProxyIOData* io_data = drp_test_context->io_data();
+  std::vector<net::ProxyServer> proxies;
+  proxies.push_back(net::ProxyServer::FromURI("http://foo1.com",
+                                              net::ProxyServer::SCHEME_HTTP));
+  net::ProxyService* proxy_service =
+      io_data->url_request_context_getter_->GetURLRequestContext()
+          ->proxy_service();
+  net::ProxyInfo proxy_info;
+  proxy_info.UseNamedProxy("http://foo2.com");
+  net::BoundNetLog bound_net_log;
+  const net::ProxyRetryInfoMap& bad_proxy_list =
+      proxy_service->proxy_retry_info();
+
+  // Simulate network error to add proxies to the bad proxy list.
+  proxy_service->MarkProxiesAsBadUntil(proxy_info, base::TimeDelta::FromDays(1),
+                                       proxies, bound_net_log);
+  base::RunLoop().RunUntilIdle();
+
+  // Verify that there are 2 proxies in the bad proxies list.
+  EXPECT_EQ(2UL, bad_proxy_list.size());
+
+  // Turn Data Saver off.
+  drp_test_context->settings()->SetDataReductionProxyEnabled(false);
+  base::RunLoop().RunUntilIdle();
+
+  // Verify that bad proxy list is empty.
+  EXPECT_EQ(0UL, bad_proxy_list.size());
+}
+
 }  // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc
index 9a66acdf..706f1729 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc
@@ -12,6 +12,7 @@
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_configurator.h"
+#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_experiments_stats.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h"
@@ -76,7 +77,8 @@
     scoped_ptr<net::NetworkDelegate> network_delegate,
     DataReductionProxyConfig* config,
     DataReductionProxyRequestOptions* request_options,
-    const DataReductionProxyConfigurator* configurator)
+    const DataReductionProxyConfigurator* configurator,
+    DataReductionProxyExperimentsStats* experiments_stats)
     : LayeredNetworkDelegate(network_delegate.Pass()),
       received_content_length_(0),
       original_content_length_(0),
@@ -84,9 +86,11 @@
       data_reduction_proxy_bypass_stats_(nullptr),
       data_reduction_proxy_request_options_(request_options),
       data_reduction_proxy_io_data_(nullptr),
-      configurator_(configurator) {
+      configurator_(configurator),
+      experiments_stats_(experiments_stats) {
   DCHECK(data_reduction_proxy_config_);
   DCHECK(data_reduction_proxy_request_options_);
+  DCHECK(experiments_stats_);
 }
 
 DataReductionProxyNetworkDelegate::~DataReductionProxyNetworkDelegate() {
@@ -185,6 +189,9 @@
     RecordContentLengthHistograms(received_content_length,
                                   original_content_length,
                                   freshness_lifetime);
+    experiments_stats_->RecordBytes(request->request_time(), request_type,
+                                    received_content_length,
+                                    original_content_length);
 
     if (data_reduction_proxy_io_data_ && data_reduction_proxy_bypass_stats_) {
       data_reduction_proxy_bypass_stats_->RecordBytesHistograms(
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.h
index 0290d6e..da13b28 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.h
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.h
@@ -31,6 +31,7 @@
 class DataReductionProxyBypassStats;
 class DataReductionProxyConfig;
 class DataReductionProxyConfigurator;
+class DataReductionProxyExperimentsStats;
 class DataReductionProxyIOData;
 class DataReductionProxyRequestOptions;
 
@@ -52,7 +53,8 @@
       scoped_ptr<net::NetworkDelegate> network_delegate,
       DataReductionProxyConfig* config,
       DataReductionProxyRequestOptions* handler,
-      const DataReductionProxyConfigurator* configurator);
+      const DataReductionProxyConfigurator* configurator,
+      DataReductionProxyExperimentsStats* experiments_stats);
   ~DataReductionProxyNetworkDelegate() override;
 
   // Initializes member variables to record data reduction proxy prefs and
@@ -122,6 +124,8 @@
 
   const DataReductionProxyConfigurator* configurator_;
 
+  DataReductionProxyExperimentsStats* experiments_stats_;
+
   DISALLOW_COPY_AND_ASSIGN(DataReductionProxyNetworkDelegate);
 };
 
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc
index b7402b0..897162c1 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc
@@ -82,7 +82,8 @@
         new DataReductionProxyNetworkDelegate(
             scoped_ptr<net::NetworkDelegate>(new TestNetworkDelegate()),
             config(), test_context_->io_data()->request_options(),
-            test_context_->configurator()));
+            test_context_->configurator(),
+            test_context_->io_data()->experiments_stats()));
   }
 
   const net::ProxyConfig& GetProxyConfig() const {
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_prefs.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_prefs.cc
index 2b59e3a..ac95358 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_prefs.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_prefs.cc
@@ -59,6 +59,7 @@
       prefs::kDailyOriginalContentLengthViaDataReductionProxy);
   registry->RegisterListPref(prefs::kDailyContentLengthViaDataReductionProxy);
   registry->RegisterInt64Pref(prefs::kDailyHttpContentLengthLastUpdateDate, 0L);
+  registry->RegisterInt64Pref(prefs::kSimulatedConfigRetrieveTime, 0L);
 }
 
 void RegisterSimpleProfilePrefs(PrefRegistrySimple* registry) {
@@ -105,6 +106,7 @@
       prefs::kDailyContentLengthViaDataReductionProxy);
   registry->RegisterInt64Pref(
       prefs::kDailyHttpContentLengthLastUpdateDate, 0L);
+  registry->RegisterInt64Pref(prefs::kSimulatedConfigRetrieveTime, 0L);
 }
 
 void MigrateStatisticsPrefs(PrefService* local_state_prefs,
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.cc
index 12b67856..f418c98 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.cc
@@ -25,6 +25,7 @@
 #include "components/data_reduction_proxy/core/common/version.h"
 #include "crypto/random.h"
 #include "net/base/host_port_pair.h"
+#include "net/base/load_flags.h"
 #include "net/proxy/proxy_server.h"
 #include "net/url_request/url_request.h"
 
@@ -33,12 +34,19 @@
 #endif
 
 namespace data_reduction_proxy {
-
 namespace {
+
 std::string FormatOption(const std::string& name, const std::string& value) {
   return name + "=" + value;
 }
-}  //namespace
+
+bool ShouldForceDisableLoFi(const net::URLRequest* request) {
+  if (!request)
+    return false;
+  return (request->load_flags() & net::LOAD_BYPASS_CACHE) != 0;
+}
+
+}  // namespace
 
 const char kSessionHeaderOption[] = "ps";
 const char kCredentialsHeaderOption[] = "sid";
@@ -126,7 +134,7 @@
 void DataReductionProxyRequestOptions::Init() {
   key_ = GetDefaultKey(),
   UpdateCredentials();
-  UpdateLoFi();
+  UpdateLoFi(false);
   UpdateVersion();
   UpdateExperiments();
 }
@@ -156,10 +164,16 @@
   RegenerateRequestHeaderValue();
 }
 
-void DataReductionProxyRequestOptions::UpdateLoFi() {
+void DataReductionProxyRequestOptions::UpdateLoFi(bool force_disable_lo_fi) {
+  if (force_disable_lo_fi) {
+    if (lofi_.empty())
+      return;
+    lofi_ = std::string();
+    RegenerateRequestHeaderValue();
+    return;
+  }
   // LoFi was not enabled, but now is. Add the header option.
-  if (lofi_.empty() &&
-      DataReductionProxyParams::IsLoFiEnabled()) {
+  if (lofi_.empty() && DataReductionProxyParams::IsLoFiEnabled()) {
     lofi_ = "low";
     RegenerateRequestHeaderValue();
     return;
@@ -216,25 +230,25 @@
     return;
   if (proxy_server.is_direct())
     return;
-  MaybeAddRequestHeaderImpl(proxy_server.host_port_pair(),
-                            false,
-                            request_headers);
+  MaybeAddRequestHeaderImpl(proxy_server.host_port_pair(), false,
+                            request_headers, ShouldForceDisableLoFi(request));
 }
 
 void DataReductionProxyRequestOptions::MaybeAddProxyTunnelRequestHandler(
     const net::HostPortPair& proxy_server,
     net::HttpRequestHeaders* request_headers) {
   DCHECK(thread_checker_.CalledOnValidThread());
-  MaybeAddRequestHeaderImpl(proxy_server, true, request_headers);
+  MaybeAddRequestHeaderImpl(proxy_server, true, request_headers, false);
 }
 
 void DataReductionProxyRequestOptions::SetHeader(
-    net::HttpRequestHeaders* headers) {
+    net::HttpRequestHeaders* headers,
+    bool force_disable_lo_fi) {
   base::Time now = Now();
   // Authorization credentials must be regenerated if they are expired.
   if (!use_assigned_credentials_ && (now > credentials_expiration_time_))
     UpdateCredentials();
-  UpdateLoFi();
+  UpdateLoFi(force_disable_lo_fi);
   const char kChromeProxyHeader[] = "Chrome-Proxy";
   std::string header_value;
   if (headers->HasHeader(kChromeProxyHeader)) {
@@ -349,14 +363,15 @@
 void DataReductionProxyRequestOptions::MaybeAddRequestHeaderImpl(
     const net::HostPortPair& proxy_server,
     bool expect_ssl,
-    net::HttpRequestHeaders* request_headers) {
+    net::HttpRequestHeaders* request_headers,
+    bool force_disable_lo_fi) {
   if (proxy_server.IsEmpty())
     return;
   if (data_reduction_proxy_config_ &&
       data_reduction_proxy_config_->IsDataReductionProxy(proxy_server, NULL) &&
       data_reduction_proxy_config_->UsingHTTPTunnel(proxy_server) ==
           expect_ssl) {
-    SetHeader(request_headers);
+    SetHeader(request_headers, force_disable_lo_fi);
   }
 }
 
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.h
index 82cdf1e..7316ef62 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.h
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.h
@@ -132,7 +132,7 @@
   void SetSecureSession(const std::string& secure_session);
 
  protected:
-  void SetHeader(net::HttpRequestHeaders* headers);
+  void SetHeader(net::HttpRequestHeaders* headers, bool force_disable_lo_fi);
 
   // Returns a UTF16 string that's the hash of the configured authentication
   // |key| and |salt|. Returns an empty UTF16 string if no key is configured or
@@ -170,8 +170,9 @@
   // Updates client type, build, and patch.
   void UpdateVersion();
 
-  // Updates the value of LoFi and regenerates the header if necessary.
-  void UpdateLoFi();
+  // Updates the value of LoFi and regenerates the header if necessary. The LoFi
+  // header is not added if the request bypasses the cache.
+  void UpdateLoFi(bool force_disable_lo_fi);
 
   // Update the value of the experiments to be run and regenerate the header if
   // necessary.
@@ -192,7 +193,8 @@
   // reduction proxy for HTTP traffic.
   void MaybeAddRequestHeaderImpl(const net::HostPortPair& proxy_server,
                                  bool expect_ssl,
-                                 net::HttpRequestHeaders* request_headers);
+                                 net::HttpRequestHeaders* request_headers,
+                                 bool force_disable_lo_fi);
 
   // Regenerates the |header_value_| string which is concatenated to the
   // Chrome-proxy header.
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options_unittest.cc
index 53741a9..ab271aa2 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options_unittest.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options_unittest.cc
@@ -4,6 +4,9 @@
 
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.h"
 
+#include <string>
+#include <vector>
+
 #include "base/command_line.h"
 #include "base/md5.h"
 #include "base/memory/scoped_ptr.h"
@@ -16,9 +19,13 @@
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h"
 #include "net/base/auth.h"
 #include "net/base/host_port_pair.h"
+#include "net/base/load_flags.h"
 #include "net/proxy/proxy_server.h"
+#include "net/url_request/url_request.h"
+#include "net/url_request/url_request_context.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
 
 namespace {
 const char kChromeProxyHeader[] = "chrome-proxy";
@@ -138,6 +145,13 @@
     request_options_->Init();
   }
 
+  void CreateRequest(int load_flags) {
+    net::URLRequestContext* context =
+        test_context_->request_context_getter()->GetURLRequestContext();
+    request_ = context->CreateRequest(GURL(), net::DEFAULT_PRIORITY, nullptr);
+    request_->SetLoadFlags(load_flags);
+  }
+
   TestDataReductionProxyParams* params() {
     return test_context_->config()->test_params();
   }
@@ -151,9 +165,10 @@
     test_context_->RunUntilIdle();
     net::HttpRequestHeaders headers;
     request_options_->MaybeAddRequestHeader(
-        NULL,
-        proxy_uri.empty() ? net::ProxyServer() :
-            net::ProxyServer::FromURI(proxy_uri, net::ProxyServer::SCHEME_HTTP),
+        request_.get(),
+        proxy_uri.empty() ? net::ProxyServer()
+                          : net::ProxyServer::FromURI(
+                                proxy_uri, net::ProxyServer::SCHEME_HTTP),
         &headers);
     if (expected_header.empty()) {
       EXPECT_FALSE(headers.HasHeader(kChromeProxyHeader));
@@ -168,6 +183,7 @@
   base::MessageLoopForIO message_loop_;
   scoped_ptr<TestDataReductionProxyRequestOptions> request_options_;
   scoped_ptr<DataReductionProxyTestContext> test_context_;
+  scoped_ptr<net::URLRequest> request_;
 };
 
 TEST_F(DataReductionProxyRequestOptionsTest, AuthHashForSalt) {
@@ -287,6 +303,30 @@
   VerifyExpectedHeader(params()->DefaultOrigin(), expected_header);
 }
 
+TEST_F(DataReductionProxyRequestOptionsTest, LoFiReloadSingleImage) {
+  // Add the LoFi command line switch.
+  base::CommandLine::ForCurrentProcess()->AppendSwitch(
+      data_reduction_proxy::switches::kEnableDataReductionProxyLoFi);
+
+  std::string expected_header;
+  SetHeaderExpectations(kExpectedSession, kExpectedCredentials, std::string(),
+                        kClientStr, std::string(), std::string(), std::string(),
+                        std::vector<std::string>(), &expected_header);
+
+  CreateRequest(net::LOAD_BYPASS_CACHE);
+  CreateRequestOptions(kBogusVersion);
+  VerifyExpectedHeader(params()->DefaultOrigin(), expected_header);
+
+  // Check that LoFi turns back on.
+  SetHeaderExpectations(kExpectedSession, kExpectedCredentials, std::string(),
+                        kClientStr, std::string(), std::string(), "low",
+                        std::vector<std::string>(), &expected_header);
+
+  CreateRequest(net::LOAD_NORMAL);
+  CreateRequestOptions(kBogusVersion);
+  VerifyExpectedHeader(params()->DefaultOrigin(), expected_header);
+}
+
 TEST_F(DataReductionProxyRequestOptionsTest, SecureSession) {
   std::string expected_header;
   SetHeaderExpectations(std::string(), std::string(), kSecureSession,
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.cc
index 374489e..9f6b4b0e 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.cc
@@ -6,6 +6,7 @@
 
 #include "base/bind.h"
 #include "base/location.h"
+#include "base/prefs/pref_service.h"
 #include "base/sequenced_task_runner.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.h"
@@ -18,10 +19,12 @@
 DataReductionProxyService::DataReductionProxyService(
     scoped_ptr<DataReductionProxyCompressionStats> compression_stats,
     DataReductionProxySettings* settings,
+    PrefService* prefs,
     net::URLRequestContextGetter* request_context_getter,
     scoped_refptr<base::SingleThreadTaskRunner> io_task_runner)
     : url_request_context_getter_(request_context_getter),
       settings_(settings),
+      prefs_(prefs),
       io_task_runner_(io_task_runner),
       initialized_(false),
       weak_factory_(this) {
@@ -53,8 +56,10 @@
     const base::TimeDelta& commit_delay) {
   DCHECK(CalledOnValidThread());
   DCHECK(!compression_stats_);
+  DCHECK(!prefs_);
+  prefs_ = prefs;
   compression_stats_.reset(new DataReductionProxyCompressionStats(
-      prefs, ui_task_runner, commit_delay));
+      prefs_, ui_task_runner, commit_delay));
 }
 
 void DataReductionProxyService::UpdateContentLengths(
@@ -100,6 +105,12 @@
   settings_->SetUnreachable(unreachable);
 }
 
+void DataReductionProxyService::SetInt64Pref(const std::string& pref_path,
+                                             int64 value) {
+  if (prefs_)
+    prefs_->SetInt64(pref_path, value);
+}
+
 void DataReductionProxyService::SetProxyPrefs(bool enabled,
                                               bool alternative_enabled,
                                               bool at_startup) {
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.h
index 2fbc18d..df2b38b 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.h
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.h
@@ -43,14 +43,16 @@
     : public base::NonThreadSafe,
       public DataReductionProxyEventStorageDelegate {
  public:
-  // The caller must ensure that |settings| and |request_context| remain alive
-  // for the lifetime of the |DataReductionProxyService| instance. This instance
+  // The caller must ensure that |settings|, |prefs|, |request_context|, and
+  // |io_task_runner| remain alive for the lifetime of the
+  // |DataReductionProxyService| instance. |prefs| may be null. This instance
   // will take ownership of |compression_stats|.
   // TODO(jeremyim): DataReductionProxyService should own
   // DataReductionProxySettings and not vice versa.
   DataReductionProxyService(
       scoped_ptr<DataReductionProxyCompressionStats> compression_stats,
       DataReductionProxySettings* settings,
+      PrefService* prefs,
       net::URLRequestContextGetter* request_context_getter,
       scoped_refptr<base::SingleThreadTaskRunner> io_task_runner);
 
@@ -89,6 +91,9 @@
   // Records whether the Data Reduction Proxy is unreachable or not.
   void SetUnreachable(bool unreachable);
 
+  // Stores an int64 value in |prefs_|.
+  void SetInt64Pref(const std::string& pref_path, int64 value);
+
   // Bridge methods to safely call to the UI thread objects.
   // Virtual for testing.
   virtual void SetProxyPrefs(bool enabled,
@@ -129,6 +134,9 @@
 
   DataReductionProxySettings* settings_;
 
+  // A prefs service for storing data.
+  PrefService* prefs_;
+
   // Used to post tasks to |io_data_|.
   scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
 
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.cc
index a9d620d..706648f3d 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.cc
@@ -9,6 +9,7 @@
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_configurator_test_utils.h"
+#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_experiments_stats.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_interceptor.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.h"
@@ -166,10 +167,14 @@
 MockDataReductionProxyService::MockDataReductionProxyService(
     scoped_ptr<DataReductionProxyCompressionStats> compression_stats,
     DataReductionProxySettings* settings,
+    PrefService* prefs,
     net::URLRequestContextGetter* request_context,
     scoped_refptr<base::SingleThreadTaskRunner> io_task_runner)
-    : DataReductionProxyService(
-        compression_stats.Pass(), settings, request_context, io_task_runner) {
+    : DataReductionProxyService(compression_stats.Pass(),
+                                settings,
+                                prefs,
+                                request_context,
+                                io_task_runner) {
 }
 
 MockDataReductionProxyService::~MockDataReductionProxyService() {
@@ -182,8 +187,9 @@
     scoped_ptr<DataReductionProxyRequestOptions> request_options,
     scoped_ptr<DataReductionProxyConfigurator> configurator,
     scoped_ptr<DataReductionProxyConfigServiceClient> config_client,
+    scoped_ptr<DataReductionProxyExperimentsStats> experiments_stats,
     bool enabled)
-    : DataReductionProxyIOData() {
+    : DataReductionProxyIOData(), service_set_(false) {
   io_task_runner_ = task_runner;
   ui_task_runner_ = task_runner;
   config_ = config.Pass();
@@ -191,6 +197,7 @@
   request_options_ = request_options.Pass();
   configurator_ = configurator.Pass();
   config_client_ = config_client.Pass();
+  experiments_stats_ = experiments_stats.Pass();
   bypass_stats_.reset(new DataReductionProxyBypassStats(
       config_.get(), base::Bind(&DataReductionProxyIOData::SetUnreachable,
                                 base::Unretained(this))));
@@ -202,6 +209,15 @@
 TestDataReductionProxyIOData::~TestDataReductionProxyIOData() {
 }
 
+void TestDataReductionProxyIOData::SetDataReductionProxyService(
+    base::WeakPtr<DataReductionProxyService> data_reduction_proxy_service) {
+  if (!service_set_)
+    DataReductionProxyIOData::SetDataReductionProxyService(
+        data_reduction_proxy_service);
+
+  service_set_ = true;
+}
+
 DataReductionProxyTestContext::Builder::Builder()
     : params_flags_(DataReductionProxyParams::kAllowed |
                     DataReductionProxyParams::kFallbackAllowed |
@@ -391,11 +407,14 @@
 
   RegisterSimpleProfilePrefs(pref_service->registry());
 
+  scoped_ptr<DataReductionProxyExperimentsStats> experiments_stats(
+      new DataReductionProxyExperimentsStats(base::Bind(
+          &PrefService::SetInt64, base::Unretained(pref_service.get()))));
   scoped_ptr<TestDataReductionProxyIOData> io_data(
       new TestDataReductionProxyIOData(
           task_runner, config.Pass(), event_creator.Pass(),
           request_options.Pass(), configurator.Pass(), config_client.Pass(),
-          true /* enabled */));
+          experiments_stats.Pass(), true /* enabled */));
   io_data->SetSimpleURLRequestContextGetter(request_context_getter);
 
   scoped_ptr<DataReductionProxyTestContext> test_context(
@@ -476,11 +495,11 @@
 
   if (test_context_flags_ & DataReductionProxyTestContext::USE_MOCK_SERVICE) {
     return make_scoped_ptr(new MockDataReductionProxyService(
-        compression_stats.Pass(), settings_.get(),
+        compression_stats.Pass(), settings_.get(), simple_pref_service_.get(),
         request_context_getter_.get(), task_runner_));
   } else {
     return make_scoped_ptr(new DataReductionProxyService(
-        compression_stats.Pass(), settings_.get(),
+        compression_stats.Pass(), settings_.get(), simple_pref_service_.get(),
         request_context_getter_.get(), task_runner_));
   }
 }
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h
index 004a3a5..5898569 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h
@@ -43,6 +43,7 @@
 
 class DataReductionProxyConfigurator;
 class DataReductionProxyEventCreator;
+class DataReductionProxyExperimentsStats;
 class DataReductionProxyMutableConfigValues;
 class DataReductionProxyRequestOptions;
 class DataReductionProxySettings;
@@ -150,6 +151,7 @@
   MockDataReductionProxyService(
       scoped_ptr<DataReductionProxyCompressionStats> compression_stats,
       DataReductionProxySettings* settings,
+      PrefService* prefs,
       net::URLRequestContextGetter* request_context,
       scoped_refptr<base::SingleThreadTaskRunner> io_task_runner);
   ~MockDataReductionProxyService() override;
@@ -170,9 +172,13 @@
       scoped_ptr<DataReductionProxyRequestOptions> request_options,
       scoped_ptr<DataReductionProxyConfigurator> configurator,
       scoped_ptr<DataReductionProxyConfigServiceClient> config_client,
+      scoped_ptr<DataReductionProxyExperimentsStats> experiments_stats,
       bool enabled);
   ~TestDataReductionProxyIOData() override;
 
+  void SetDataReductionProxyService(base::WeakPtr<DataReductionProxyService>
+                                        data_reduction_proxy_service) override;
+
   DataReductionProxyConfigurator* configurator() const {
     return configurator_.get();
   }
@@ -189,6 +195,10 @@
   base::WeakPtr<DataReductionProxyIOData> GetWeakPtr() {
     return weak_factory_.GetWeakPtr();
   }
+
+ private:
+  // Allowed SetDataReductionProxyService to be re-entrant.
+  bool service_set_;
 };
 
 // Builds a test version of the Data Reduction Proxy stack for use in tests.
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.cc b/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.cc
index 50c5e963..35c93f51 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.cc
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.cc
@@ -22,8 +22,11 @@
 namespace {
 
 const char kChromeProxyHeader[] = "chrome-proxy";
+
 const char kActionValueDelimiter = '=';
 
+const char kChromeProxyLoFiDirective[] = "q=low";
+
 const char kChromeProxyActionBlockOnce[] = "block-once";
 const char kChromeProxyActionBlock[] = "block";
 const char kChromeProxyActionBypass[] = "bypass";
@@ -49,6 +52,14 @@
 
 namespace data_reduction_proxy {
 
+const char* chrome_proxy_header() {
+  return kChromeProxyHeader;
+}
+
+const char* chrome_proxy_lo_fi_directive() {
+  return kChromeProxyLoFiDirective;
+}
+
 bool GetDataReductionProxyActionValue(
     const net::HttpResponseHeaders* headers,
     const std::string& action_prefix,
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h b/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h
index ab94b0f..4505d58 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h
@@ -64,6 +64,13 @@
   DataReductionProxyBypassAction bypass_action;
 };
 
+// Gets the header used for data reduction proxy requests and responses.
+const char* chrome_proxy_header();
+
+// Gets the Chrome-Proxy directive used by data reduction proxy Lo-Fi requests
+// and responses.
+const char* chrome_proxy_lo_fi_directive();
+
 // Returns true if the Chrome-Proxy header is present and contains a bypass
 // delay. Sets |proxy_info->bypass_duration| to the specified delay if greater
 // than 0, and to 0 otherwise to indicate that the default proxy delay
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_params.cc b/components/data_reduction_proxy/core/common/data_reduction_proxy_params.cc
index c47a06d56..3951d09 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_params.cc
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_params.cc
@@ -148,6 +148,10 @@
               kDataReductionProxyStartSecureDisabled))
     return false;
 
+  if (FieldTrialList::FindFullName("DataReductionProxySecureProxyAfterCheck") ==
+      kEnabled)
+    return false;
+
   return true;
 }
 
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_params_unittest.cc b/components/data_reduction_proxy/core/common/data_reduction_proxy_params_unittest.cc
index aa507412..77c9e4ee 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_params_unittest.cc
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_params_unittest.cc
@@ -7,6 +7,7 @@
 #include <map>
 
 #include "base/command_line.h"
+#include "base/metrics/field_trial.h"
 #include "base/values.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_params_test_utils.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h"
@@ -767,6 +768,57 @@
       "google/hammerhead/hammerhead:5.0/LRX210/1570415:user/release-keys"));
 }
 
+TEST_F(DataReductionProxyParamsTest, SecureProxyCheckDefault) {
+  struct {
+    bool command_line_set;
+    bool experiment_enabled;
+    bool in_trial_group;
+    bool expected_use_by_default;
+  } test_cases[]{
+      {
+       false, false, false, true,
+      },
+      {
+       true, false, false, false,
+      },
+      {
+       true, true, false, false,
+      },
+      {
+       true, true, true, false,
+      },
+      {
+       false, true, true, false,
+      },
+      {
+       false, true, false, true,
+      },
+  };
+
+  int test_index = 0;
+  for (const auto& test_case : test_cases) {
+    // Reset all flags.
+    base::CommandLine::ForCurrentProcess()->InitFromArgv(0, NULL);
+
+    base::FieldTrialList trial_list(nullptr);
+    if (test_case.command_line_set) {
+      base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+          switches::kDataReductionProxyStartSecureDisabled, "");
+    }
+
+    if (test_case.experiment_enabled) {
+      base::FieldTrialList::CreateFieldTrial(
+          "DataReductionProxySecureProxyAfterCheck",
+          test_case.in_trial_group ? "Enabled" : "Disabled");
+    }
+
+    EXPECT_EQ(test_case.expected_use_by_default,
+              DataReductionProxyParams::ShouldUseSecureProxyByDefault())
+        << test_index;
+    test_index++;
+  }
+}
+
 TEST_F(DataReductionProxyParamsTest, PopulateConfigResponse) {
   DataReductionProxyParams params(
       DataReductionProxyParams::kAllowed |
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.cc b/components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.cc
index a086117..9979f38 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.cc
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.cc
@@ -88,6 +88,13 @@
 // received over the network.
 const char kHttpOriginalContentLength[] = "http_original_content_length";
 
+// Pref to store the retrieval time of the last simulated Data Reduction Proxy
+// configuration. This is part of an experiment to see how many bytes are lost
+// if the Data Reduction Proxy is not used due to configuration being expired
+// or not available.
+const char kSimulatedConfigRetrieveTime[] =
+    "data_reduction.simulated_config_retrieve_time";
+
 // A boolean specifying whether the data reduction proxy statistics preferences
 // have migrated from local state to the profile.
 const char kStatisticsPrefsMigrated[] =
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h b/components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h
index 9a9b36a..17660463 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h
@@ -28,6 +28,7 @@
 extern const char kDataReductionProxyWasEnabledBefore[];
 extern const char kHttpOriginalContentLength[];
 extern const char kHttpReceivedContentLength[];
+extern const char kSimulatedConfigRetrieveTime[];
 extern const char kStatisticsPrefsMigrated[];
 extern const char kUpdateDailyReceivedContentLengths[];
 
diff --git a/components/devtools_bridge.gyp b/components/devtools_bridge.gyp
deleted file mode 100644
index 37c5fce5..0000000
--- a/components/devtools_bridge.gyp
+++ /dev/null
@@ -1,98 +0,0 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-{
-  'targets': [
-    {
-      'target_name': 'devtools_bridge_jni_headers',
-      'type': 'none',
-      'sources': [
-        'devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/SessionDependencyFactoryNative.java',
-        'devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/apiary/ApiaryClientFactory.java',
-      ],
-      'variables': {
-        'jni_gen_package': 'devtools_bridge',
-      },
-      'includes': [ '../build/jni_generator.gypi' ],
-    },
-    {
-      'target_name': 'devtools_bridge',
-      'type': 'static_library',
-      'sources': [
-        'devtools_bridge/android/apiary_client_factory.cc',
-        'devtools_bridge/android/apiary_client_factory.h',
-        'devtools_bridge/android/session_dependency_factory_android.cc',
-        'devtools_bridge/android/session_dependency_factory_android.h',
-        'devtools_bridge/session_dependency_factory.cc',
-        'devtools_bridge/session_dependency_factory.h',
-        'devtools_bridge/socket_tunnel_connection.cc',
-        'devtools_bridge/socket_tunnel_connection.h',
-        'devtools_bridge/socket_tunnel_packet_handler.cc',
-        'devtools_bridge/socket_tunnel_packet_handler.h',
-        'devtools_bridge/socket_tunnel_server.cc',
-        'devtools_bridge/socket_tunnel_server.h',
-      ],
-      'dependencies': [
-        '../base/base.gyp:base',
-        '../google_apis/google_apis.gyp:google_apis',
-        '../third_party/libjingle/libjingle.gyp:libjingle_webrtc',
-        '../third_party/libjingle/libjingle.gyp:libpeerconnection',
-        '../third_party/webrtc/base/base.gyp:rtc_base',
-        'devtools_bridge_jni_headers',
-      ],
-    },
-    {
-      'target_name': 'devtools_bridge_javalib',
-      'type': 'none',
-      'variables': {
-        'java_in_dir': 'devtools_bridge/android/java',
-      },
-      'includes': [ '../build/java.gypi' ],
-      'dependencies': [
-        '../base/base.gyp:base_java',
-        '../sync/sync.gyp:sync_java',
-        '../third_party/android_tools/android_tools.gyp:android_support_v13_javalib',
-      ],
-    },
-    {
-      'target_name': 'libdevtools_bridge_natives_so',
-      'type': 'shared_library',
-      'sources': [
-        'devtools_bridge/test/android/javatests/jni/jni_onload.cc',
-      ],
-      'dependencies': [
-        '../base/base.gyp:base',
-        'devtools_bridge',
-      ],
-    },
-    {
-      'target_name': 'devtools_bridge_testutils',
-      'type': 'none',
-      'variables': {
-        'java_in_dir': 'devtools_bridge/test/android/javatests',
-      },
-      'includes': [ '../build/java.gypi' ],
-      'dependencies': [
-        'devtools_bridge_javalib',
-      ],
-    },
-    {
-      'target_name': 'devtools_bridge_tests_apk',
-      'type': 'none',
-      'dependencies': [
-        'devtools_bridge_javalib',
-        'devtools_bridge_testutils',
-        'libdevtools_bridge_natives_so',
-      ],
-      'variables': {
-        'apk_name': 'DevToolsBridgeTest',
-        'test_suite_name': 'devtools_bridge_tests',
-        'java_in_dir': 'devtools_bridge/android/javatests',
-        'native_lib_target': 'libdevtools_bridge_natives_so',
-        'is_test_apk': 1,
-      },
-      'includes': [ '../build/java_apk.gypi' ],
-    },
-  ],
-}
diff --git a/components/devtools_bridge/DEPS b/components/devtools_bridge/DEPS
deleted file mode 100644
index 7112bb2f..0000000
--- a/components/devtools_bridge/DEPS
+++ /dev/null
@@ -1,8 +0,0 @@
-include_rules = [
-  "+google_apis",
-  "+net",
-  "+third_party/libjingle",
-  "+third_party/webrtc",
-  "-chrome",
-  "-content",
-]
diff --git a/components/devtools_bridge/OWNERS b/components/devtools_bridge/OWNERS
deleted file mode 100644
index 1b209e2d..0000000
--- a/components/devtools_bridge/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-mnaganov@chromium.org
-serya@chromium.org
diff --git a/components/devtools_bridge/README b/components/devtools_bridge/README
deleted file mode 100644
index 40077c9b..0000000
--- a/components/devtools_bridge/README
+++ /dev/null
@@ -1,2 +0,0 @@
-The devtools_bridge component contains code for tunneling DevTools connection
-over P2P data channel for remote debugging android devices.
diff --git a/components/devtools_bridge/abstract_data_channel.h b/components/devtools_bridge/abstract_data_channel.h
deleted file mode 100644
index 473774e..0000000
--- a/components/devtools_bridge/abstract_data_channel.h
+++ /dev/null
@@ -1,77 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_DEVTOOLS_BRIDGE_ABSTRACT_DATA_CHANNEL_H_
-#define COMPONENTS_DEVTOOLS_BRIDGE_ABSTRACT_DATA_CHANNEL_H_
-
-#include <string>
-
-#include "base/callback.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
-
-namespace devtools_bridge {
-
-/**
- * WebRTC DataChannel adapter for DevTools bridge. Not thread safe.
- */
-class AbstractDataChannel {
- public:
-  AbstractDataChannel() {}
-  virtual ~AbstractDataChannel() {}
-
-  /**
-   * Called on WebRTC signaling thread.
-   */
-  class Observer {
-   public:
-    Observer() {}
-    virtual ~Observer() {}
-
-    virtual void OnOpen() = 0;
-    virtual void OnClose() = 0;
-
-    virtual void OnMessage(const void* data, size_t length) = 0;
-
-   private:
-    DISALLOW_COPY_AND_ASSIGN(Observer);
-  };
-
-  /**
-   * Proxy for accessing data channel from a different thread.
-   * May outlive data channel (methods will have no effect if DataChannel
-   * destroyed).
-   */
-  class Proxy : public base::RefCountedThreadSafe<Proxy> {
-   public:
-    virtual void SendBinaryMessage(const void* data, size_t length) = 0;
-    virtual void Close() = 0;
-
-   protected:
-    Proxy() {}
-    virtual ~Proxy() {}
-
-   private:
-    friend class base::RefCountedThreadSafe<Proxy>;
-
-    DISALLOW_COPY_AND_ASSIGN(Proxy);
-  };
-
-  virtual void RegisterObserver(scoped_ptr<Observer> observer) = 0;
-  virtual void UnregisterObserver() = 0;
-
-  virtual void SendBinaryMessage(void* data, size_t length) = 0;
-  virtual void SendTextMessage(void* data, size_t length) = 0;
-
-  virtual void Close() = 0;
-
-  virtual scoped_refptr<Proxy> proxy() = 0;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(AbstractDataChannel);
-};
-
-}  // namespace devtools_bridge
-
-#endif  // COMPONENTS_DEVTOOLS_BRIDGE_ABSTRACT_DATA_CHANNEL_H_
diff --git a/components/devtools_bridge/abstract_peer_connection.h b/components/devtools_bridge/abstract_peer_connection.h
deleted file mode 100644
index 9fd04a8..0000000
--- a/components/devtools_bridge/abstract_peer_connection.h
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_DEVTOOLS_BRIDGE_ABSTRACT_PEER_CONNECTION_H_
-#define COMPONENTS_DEVTOOLS_BRIDGE_ABSTRACT_PEER_CONNECTION_H_
-
-#include <string>
-
-#include "base/memory/scoped_ptr.h"
-
-namespace devtools_bridge {
-
-class AbstractDataChannel;
-
-/**
- * WebRTC PeerConnection adapter for DevTools bridge.
- */
-class AbstractPeerConnection {
- public:
-  /**
-   * Delegate is called on signaling thread.
-   */
-  class Delegate {
-   public:
-    Delegate() {}
-    virtual ~Delegate() {}
-
-    virtual void OnIceConnectionChange(bool connected) = 0;
-    virtual void OnIceCandidate(
-        const std::string& sdp_mid,
-        int sdp_mline_index,
-        const std::string& sdp) = 0;
-    virtual void OnLocalOfferCreatedAndSetSet(
-        const std::string& description) = 0;
-    virtual void OnLocalAnswerCreatedAndSetSet(
-        const std::string& description) = 0;
-    virtual void OnRemoteDescriptionSet() = 0;
-    virtual void OnFailure(const std::string& description) = 0;
-
-   private:
-    DISALLOW_COPY_AND_ASSIGN(Delegate);
-  };
-
-  AbstractPeerConnection() {}
-  virtual ~AbstractPeerConnection() {}
-
-  virtual void CreateAndSetLocalOffer() = 0;
-  virtual void CreateAndSetLocalAnswer() = 0;
-  virtual void SetRemoteOffer(const std::string& description) = 0;
-  virtual void SetRemoteAnswer(const std::string& description) = 0;
-  virtual void AddIceCandidate(
-      const std::string& sdp_mid,
-      int sdp_mline_index,
-      const std::string& sdp) = 0;
-
-  virtual scoped_ptr<AbstractDataChannel> CreateDataChannel(int channelId) = 0;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(AbstractPeerConnection);
-};
-
-}  // namespace devtools_bridge
-
-#endif  // COMPONENTS_DEVTOOLS_BRIDGE_ABSTRACT_PEER_CONNECTION_H_
diff --git a/components/devtools_bridge/android/DEPS b/components/devtools_bridge/android/DEPS
deleted file mode 100644
index c80012b5..0000000
--- a/components/devtools_bridge/android/DEPS
+++ /dev/null
@@ -1,3 +0,0 @@
-include_rules = [
-  "+jni",
-]
diff --git a/components/devtools_bridge/android/apiary_client_factory.cc b/components/devtools_bridge/android/apiary_client_factory.cc
deleted file mode 100644
index 2224643f..0000000
--- a/components/devtools_bridge/android/apiary_client_factory.cc
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/devtools_bridge/android/apiary_client_factory.h"
-
-#include "base/android/jni_string.h"
-#include "google_apis/google_api_keys.h"
-#include "jni/ApiaryClientFactory_jni.h"
-
-using base::android::ConvertUTF8ToJavaString;
-
-namespace devtools_bridge {
-namespace android {
-
-// static
-bool ApiaryClientFactory::RegisterNatives(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
-// static
-jstring GetAPIKey(JNIEnv* env, jobject jcaller) {
-  return ConvertUTF8ToJavaString(env, google_apis::GetAPIKey()).Release();
-}
-
-// static
-jstring GetOAuthClientId(JNIEnv* env, jobject jcaller) {
-  return ConvertUTF8ToJavaString(
-             env, google_apis::GetOAuth2ClientID(
-                      google_apis::OAuth2Client::CLIENT_MAIN)).Release();
-}
-
-// static
-jstring GetOAuthClientSecret(JNIEnv* env, jobject jcaller) {
-  return ConvertUTF8ToJavaString(
-             env, google_apis::GetOAuth2ClientSecret(
-                      google_apis::OAuth2Client::CLIENT_MAIN)).Release();
-}
-
-}  // namespace android
-}  // namespace devtools_bridge
diff --git a/components/devtools_bridge/android/apiary_client_factory.h b/components/devtools_bridge/android/apiary_client_factory.h
deleted file mode 100644
index d44909c..0000000
--- a/components/devtools_bridge/android/apiary_client_factory.h
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_DEVTOOLS_BRIDGE_ANDROID_APIARY_CLIENT_FACTORY_H_
-#define COMPONENTS_DEVTOOLS_BRIDGE_ANDROID_APIARY_CLIENT_FACTORY_H_
-
-#include <jni.h>
-
-namespace devtools_bridge {
-namespace android {
-
-/**
- * Native counterpart of Java |ApiaryClientFactory| in DevTools Bridge.
- * Provides access to API keys and OAuth credentials needed for GCD
- * robotic account.
- */
-class ApiaryClientFactory {
- public:
-  static bool RegisterNatives(JNIEnv* env);
-};
-
-}  // namespace android
-}  // namespace devtools_bridge
-
-#endif  // COMPONENTS_DEVTOOLS_BRIDGE_ANDROID_APIARY_CLIENT_FACTORY_H_
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/AbstractDataChannel.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/AbstractDataChannel.java
deleted file mode 100644
index e92c6db..0000000
--- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/AbstractDataChannel.java
+++ /dev/null
@@ -1,77 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge;
-
-import java.nio.ByteBuffer;
-
-/**
- * Limited view on org.webrtc.DataChannel. Abstraction layer helps with:
- * 1. Mocking in tests. There is no need to emulate full set of features of the DataChannel.
- * 2. Allows both native and Java API implementation for WebRTC data channel.
- * 3. Hides unused features.
- * Only SCTP data channels supported.
- * Data channel is thread safe (except the dispose method).
- */
-public abstract class AbstractDataChannel {
-    /**
-     *  Observer's callbacks are called on WebRTC signaling thread (or it's equivalent in tests).
-     */
-    public interface Observer {
-        void onStateChange(State state);
-
-        /**
-         * TEXT and BINARY messages should be handled equally. Size of the message is
-         * |message|.remaining(). |message| may reference to a native buffer on stack so
-         * the reference to the buffer must not outlive the invocation.
-         */
-        void onMessage(ByteBuffer message);
-    }
-
-    /**
-     * Type is only significant for JavaScript-based counterpart. TEXT messages will
-     * be observed as strings, BINARY as ByteArray's.
-     */
-    public enum MessageType {
-        TEXT, BINARY
-    }
-
-    /**
-     * State of the data channel.
-     * Only 2 states of channel are important here: OPEN and everything else.
-     */
-    public enum State {
-        OPEN, CLOSED
-    }
-
-    /**
-     * Registers an observer.
-     */
-    public abstract void registerObserver(Observer observer);
-
-    /**
-     * Unregisters the previously registered observer.
-     * Observer unregistration synchronized with signaling thread. If some data modified
-     * in observer callbacks without additional synchronization it's safe to access
-     * this data on the current thread after calling this method.
-     */
-    public abstract void unregisterObserver();
-
-    /**
-     * Sending message to the data channel.
-     * Message size is |message|.remaining().
-     */
-    public abstract void send(ByteBuffer message, MessageType type);
-
-    /**
-     * Closing data channel. Both channels in the pair will change state to CLOSED.
-     */
-    public abstract void close();
-
-    /**
-     * Releases native objects (if any). Closes data channel. No other methods are allowed after it
-     * (in multithread scenario needs synchronization with access to the data channel).
-     */
-    public abstract void dispose();
-}
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/AbstractPeerConnection.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/AbstractPeerConnection.java
deleted file mode 100644
index 3e1fb6a..0000000
--- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/AbstractPeerConnection.java
+++ /dev/null
@@ -1,106 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge;
-
-/**
- * Limited view on org.webrtc.PeerConnection. Abstraction layer helps with:
- * 1. Allows both native and Java API implementation.
- * 2. Hides unused features.
- * Should be accessed on a single thread.
- */
-public abstract class AbstractPeerConnection {
-    /**
-     * All methods are callen on WebRTC signaling thread.
-     */
-    public interface Observer {
-        /**
-         * Called when createAndSetLocalDescription or setRemoteDescription failed.
-         */
-        void onFailure(String description);
-
-        /**
-         * Called when createAndSetLocalDescription succeeded.
-         */
-        void onLocalDescriptionCreatedAndSet(SessionDescriptionType type, String description);
-
-        /**
-         * Called when setRemoteDescription succeeded.
-         */
-        void onRemoteDescriptionSet();
-
-        /**
-         * New ICE candidate available. String representation defined in the IceCandidate class.
-         * To be sent to the remote peer connection.
-         */
-        void onIceCandidate(String iceCandidate);
-
-        /**
-         * Called when connected or disconnected. In disconnected state recovery procedure
-         * should only rely on signaling channel.
-         */
-        void onIceConnectionChange(boolean connected);
-    }
-
-    /**
-     * Type of session description.
-     */
-    public enum SessionDescriptionType {
-        OFFER, ANSWER
-    }
-
-    /**
-     * The result of this method will be invocation onLocalDescriptionCreatedAndSet
-     * or onFailure on the observer. Should not be called when waiting result of
-     * setRemoteDescription.
-     */
-    public abstract void createAndSetLocalDescription(SessionDescriptionType type);
-
-    /**
-     * Result of this method will be invocation onRemoteDescriptionSet or onFailure on the observer.
-     */
-    public abstract void setRemoteDescription(SessionDescriptionType type, String description);
-
-    /**
-     * Adds a remote ICE candidate.
-     */
-    public abstract void addIceCandidate(String candidate);
-
-    /**
-     * Destroys native objects. Synchronized with the signaling thread
-     * (no observer method called when the connection disposed)
-     */
-    public abstract void dispose();
-
-    /**
-     * Creates prenegotiated SCTP data channel.
-     */
-    public abstract AbstractDataChannel createDataChannel(int channelId);
-
-    /**
-     * Helper class which enforces string representation of an ICE candidate.
-     */
-    static class IceCandidate {
-        public final String sdpMid;
-        public final int sdpMLineIndex;
-        public final String sdp;
-
-        public IceCandidate(String sdpMid, int sdpMLineIndex, String sdp) {
-            this.sdpMid = sdpMid;
-            this.sdpMLineIndex = sdpMLineIndex;
-            this.sdp = sdp;
-        }
-
-        public String toString() {
-            return sdpMid + ":" + sdpMLineIndex + ":" + sdp;
-        }
-
-        public static IceCandidate fromString(String candidate) throws IllegalArgumentException {
-            String[] parts = candidate.split(":", 3);
-            if (parts.length != 3)
-                throw new IllegalArgumentException("Expected column separated list.");
-            return new IceCandidate(parts[0], Integer.parseInt(parts[1]), parts[2]);
-        }
-    }
-}
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/DevToolsBridgeServer.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/DevToolsBridgeServer.java
deleted file mode 100644
index 076fe50..0000000
--- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/DevToolsBridgeServer.java
+++ /dev/null
@@ -1,181 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge;
-
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-
-import org.chromium.components.devtools_bridge.util.LooperExecutor;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Responsibility of DevToolsBridgeServer consists of handling commands and managing sessions.
- * It designed to live in DevToolsBridgeServiceBase but also may live separately (in tests).
- */
-public class DevToolsBridgeServer implements SignalingReceiver {
-    private final LooperExecutor mExecutor;
-    private final SessionDependencyFactory mFactory = SessionDependencyFactory.newInstance();
-    private final Map<String, ServerSession> mSessions = new HashMap<String, ServerSession>();
-    private final GCDNotificationHandler mHandler;
-    private final Delegate mDelegate;
-
-    /**
-     * Callback for finding DevTools socket asynchronously. Needed in multiprocess
-     * scenario when socket name is variable. May be called synchronously.
-     */
-    public interface QuerySocketCallback {
-        void onSuccess(String socketName);
-        void onFailure();
-    }
-
-    /**
-     * Delegate abstracts Server from service lifetime management and UI.
-     */
-    public interface Delegate {
-        Context getContext();
-
-        // When runs in a service this service should not die when |sessionCount| > 0.
-        void onSessionCountChange(int sessionCount);
-
-        // Lets query a socket name when starting a new session. Result may change
-        // (in multiprocess scenario: when browser process stops and then starts again).
-        void querySocketName(QuerySocketCallback callback);
-    }
-
-    public DevToolsBridgeServer(Delegate delegate) {
-        assert delegate != null;
-
-        mExecutor = LooperExecutor.newInstanceForMainLooper(delegate.getContext());
-        mHandler = new GCDNotificationHandler(this);
-        mDelegate = delegate;
-    }
-
-    private void checkCalledOnHostServiceThread() {
-        assert mExecutor.isCalledOnSessionThread();
-    }
-
-    public Context getContext() {
-        return mDelegate.getContext();
-    }
-
-    public SharedPreferences getPreferences() {
-        return getPreferences(getContext());
-    }
-
-    public static SharedPreferences getPreferences(Context context) {
-        return context.getSharedPreferences(
-                DevToolsBridgeServer.class.getName(), Context.MODE_PRIVATE);
-    }
-
-    public void handleCloudMessage(Intent cloudMessage, Runnable completionHandler) {
-        if (mHandler.isNotification(cloudMessage)) {
-            mHandler.onNotification(cloudMessage, completionHandler);
-        } else {
-            completionHandler.run();
-        }
-    }
-
-    public void updateCloudMessagesId(String channelId, Runnable completionHandler) {
-        mHandler.updateCloudMessagesId(channelId, completionHandler);
-    }
-
-    /**
-     * Should be called in service's onDestroy.
-     */
-    public void dispose() {
-        checkCalledOnHostServiceThread();
-
-        for (ServerSession session : mSessions.values()) {
-            session.dispose();
-        }
-        mFactory.dispose();
-        mHandler.dispose();
-    }
-
-    @Override
-    public void startSession(
-            final String sessionId,
-            final RTCConfiguration config,
-            final String offer,
-            final SessionBase.NegotiationCallback callback) {
-        checkCalledOnHostServiceThread();
-        if (mSessions.containsKey(sessionId)) {
-            callback.onFailure("Session " + sessionId + " already exists");
-            return;
-        }
-
-        mDelegate.querySocketName(new QuerySocketCallback() {
-            @Override
-            public void onSuccess(String socketName) {
-                ServerSession session = new ServerSession(mFactory, mExecutor, socketName);
-                session.setEventListener(new SessionEventListener(sessionId));
-                mSessions.put(sessionId, session);
-                session.startSession(config, offer, callback);
-                mDelegate.onSessionCountChange(mSessions.size());
-            }
-
-            @Override
-            public void onFailure() {
-                callback.onFailure("Socket not available");
-            }
-        });
-    }
-
-    @Override
-    public void renegotiate(
-            String sessionId,
-            String offer,
-            SessionBase.NegotiationCallback callback) {
-        checkCalledOnHostServiceThread();
-        if (!mSessions.containsKey(sessionId)) {
-            callback.onFailure("Session does not exist");
-            return;
-        }
-        ServerSession session = mSessions.get(sessionId);
-        session.renegotiate(offer, callback);
-    }
-
-    @Override
-    public void iceExchange(
-            String sessionId,
-            List<String> clientCandidates,
-            SessionBase.IceExchangeCallback callback) {
-        checkCalledOnHostServiceThread();
-        if (!mSessions.containsKey(sessionId)) {
-            callback.onFailure("Session does not exist");
-            return;
-        }
-        ServerSession session = mSessions.get(sessionId);
-        session.iceExchange(clientCandidates, callback);
-    }
-
-    private class SessionEventListener implements SessionBase.EventListener {
-        private final String mSessionId;
-
-        public SessionEventListener(String sessionId) {
-            mSessionId = sessionId;
-        }
-
-        public void onCloseSelf() {
-            checkCalledOnHostServiceThread();
-
-            mSessions.remove(mSessionId);
-            mDelegate.onSessionCountChange(mSessions.size());
-        }
-    }
-
-    public void closeAllSessions() {
-        if (mSessions.isEmpty()) return;
-        for (ServerSession session : mSessions.values()) {
-            session.stop();
-        }
-        mSessions.clear();
-        mDelegate.onSessionCountChange(mSessions.size());
-    }
-}
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/DevToolsBridgeServiceBase.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/DevToolsBridgeServiceBase.java
deleted file mode 100644
index f893592..0000000
--- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/DevToolsBridgeServiceBase.java
+++ /dev/null
@@ -1,151 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge;
-
-import android.app.Service;
-import android.content.Context;
-import android.content.Intent;
-import android.os.IBinder;
-import android.os.Looper;
-import android.support.v4.content.WakefulBroadcastReceiver;
-
-import com.google.ipc.invalidation.external.client.contrib.MultiplexingGcmListener;
-
-/**
- * Base class for a service which hosts DevToolsBridgeServer. It relies on Cloud Messages
- * intents rebroadcasted via MultiplexingGcmListener. It intentionally doesn't inherit from
- * MultiplexingGcmListener.AbstractListener because this service may not be IntentService
- * due to lifetime management restrictions of it.
- *
- * Service lives while any intent being processed or any client connected.
- * TODO(serya): Service lifetime management code should be moved here from DevToolsBridgeServer.
- */
-public abstract class DevToolsBridgeServiceBase extends Service {
-    private static final String WAKELOCK_KEY = "DevToolsBridgeService.WAKELOCK";
-
-    /**
-     * Delivers intents from MultiplexingGcmListener to the service making sure
-     * wakelock is kept during the process.
-     */
-    protected abstract static class ReceiverBase extends WakefulBroadcastReceiver {
-        private final Class<? extends DevToolsBridgeServiceBase> mConcreteServiceClass;
-
-        protected ReceiverBase(Class<? extends DevToolsBridgeServiceBase> concreteServiceClass) {
-            mConcreteServiceClass = concreteServiceClass;
-        }
-
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            // Pass all intent extras to the service.
-            Intent startIntent = new Intent(context, mConcreteServiceClass);
-            startIntent.setAction(intent.getAction());
-            if (intent.getExtras() != null) startIntent.putExtras(intent.getExtras());
-            startWakefulService(context, startIntent);
-        }
-    }
-
-    private DevToolsBridgeServer mServer;
-    private ServiceLifetimeManager mLifetimeManager;
-
-    private Runnable mSessionHandlingTask;
-
-    @Override
-    public IBinder onBind(Intent intent) {
-        return null;
-    }
-
-    @Override
-    public void onCreate() {
-        super.onCreate();
-        mServer = new DevToolsBridgeServer(new ServerDelegate());
-        mLifetimeManager = new ServiceLifetimeManager(this, WAKELOCK_KEY);
-    }
-
-    @Override
-    public void onDestroy() {
-        mServer.dispose();
-
-        super.onDestroy();
-    }
-
-    @Override
-    public final int onStartCommand(Intent intent, int flags, int startId) {
-        Runnable intentHandlingTask = mLifetimeManager.startTask(startId);
-        if (MultiplexingGcmListener.Intents.ACTION.equals(intent.getAction())) {
-            handleGCMIntent(intent);
-        } else {
-            onHandleIntent(intent);
-        }
-        ReceiverBase.completeWakefulIntent(intent);
-        intentHandlingTask.run(); // Stops self if no other task started.
-        return START_NOT_STICKY;
-    }
-
-    private void handleGCMIntent(Intent intent) {
-        if (intent.getBooleanExtra(MultiplexingGcmListener.Intents.EXTRA_OP_MESSAGE, false)) {
-            mServer.handleCloudMessage(intent, mLifetimeManager.startTask());
-        } else if (intent.getBooleanExtra(
-                MultiplexingGcmListener.Intents.EXTRA_OP_REGISTERED, false)) {
-            mServer.updateCloudMessagesId(
-                    intent.getStringExtra(MultiplexingGcmListener.Intents.EXTRA_DATA_REG_ID),
-                    startTask());
-        } else if (intent.getBooleanExtra(
-                MultiplexingGcmListener.Intents.EXTRA_OP_UNREGISTERED, false)) {
-            mServer.updateCloudMessagesId("", startTask());
-        }
-    }
-
-    /**
-     * Unlike similar method in IntentService this one runs on service thread.
-     * Cloud Messages intents are handled separately.
-     */
-    protected void onHandleIntent(Intent intent) {
-        assert calledOnServiceThread();
-    }
-
-    protected abstract void querySocketName(DevToolsBridgeServer.QuerySocketCallback callback);
-    protected abstract void onFirstSessionStarted();
-    protected abstract void onLastSessionStopped();
-    protected void onSessionCountChange(int sessionCount) {}
-
-    protected DevToolsBridgeServer server() {
-        return mServer;
-    }
-
-    protected Runnable startTask() {
-        return mLifetimeManager.startTask();
-    }
-
-    protected boolean calledOnServiceThread() {
-        return Looper.myLooper() == getMainLooper();
-    }
-
-    private class ServerDelegate implements DevToolsBridgeServer.Delegate {
-        @Override
-        public Context getContext() {
-            return DevToolsBridgeServiceBase.this;
-        }
-
-        @Override
-        public void onSessionCountChange(int sessionCount) {
-            assert calledOnServiceThread();
-            if (sessionCount > 0 && mSessionHandlingTask == null) {
-                mSessionHandlingTask = startTask();
-                DevToolsBridgeServiceBase.this.onFirstSessionStarted();
-            } else if (sessionCount == 0 && mSessionHandlingTask != null) {
-                mSessionHandlingTask.run();
-                mSessionHandlingTask = null;
-                DevToolsBridgeServiceBase.this.onLastSessionStopped();
-            } else {
-                DevToolsBridgeServiceBase.this.onSessionCountChange(sessionCount);
-            }
-        }
-
-        @Override
-        public void querySocketName(DevToolsBridgeServer.QuerySocketCallback callback) {
-            DevToolsBridgeServiceBase.this.querySocketName(callback);
-        }
-    }
-}
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/GCDNotificationHandler.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/GCDNotificationHandler.java
deleted file mode 100644
index fdf5de9b..0000000
--- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/GCDNotificationHandler.java
+++ /dev/null
@@ -1,177 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge;
-
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.util.Log;
-
-import org.chromium.components.devtools_bridge.apiary.ApiaryClientFactory;
-import org.chromium.components.devtools_bridge.apiary.OAuthResult;
-import org.chromium.components.devtools_bridge.commands.Command;
-import org.chromium.components.devtools_bridge.commands.CommandReceiver;
-import org.chromium.components.devtools_bridge.gcd.InstanceCredential;
-import org.chromium.components.devtools_bridge.gcd.Notification;
-
-import java.io.IOException;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-
-/**
- * Handles notifications from GCD. For command notification it delegates work to
- * DevToolsBridgeServer and updates command state when it finish. for unregistration
- * notification it updates preferences.
- */
-public class GCDNotificationHandler {
-    private static final String TAG = "GCDNotificationHandler";
-
-    private static final String EXTRA_FROM = "from";
-    private static final String EXTRA_NOTIFICATION = "notification";
-    private static final String EXPECTED_SENDER =
-            "clouddevices-gcm@clouddevices.google.com";
-
-    private final DevToolsBridgeServer mServer;
-    private final ApiaryClientFactory mClientFactory;
-    private final CommandReceiver mCommandReceiver;
-
-    private final ExecutorService mIOExecutor;
-    private OAuthResult mOAuthResult;
-
-    public GCDNotificationHandler(DevToolsBridgeServer server) {
-        mServer = server;
-        mClientFactory = new ApiaryClientFactory();
-        mCommandReceiver = new CommandReceiver(server);
-        mIOExecutor = Executors.newSingleThreadExecutor();
-    }
-
-    public void dispose() {
-        mIOExecutor.shutdown();
-        mClientFactory.close();
-    }
-
-    public boolean isNotification(Intent intent) {
-        return EXPECTED_SENDER.equals(intent.getStringExtra(EXTRA_FROM))
-                && intent.getStringExtra(EXTRA_NOTIFICATION) != null;
-    }
-
-    public void onNotification(Intent intent, Runnable completionHandler) {
-        try {
-            handle(Notification.read(intent.getStringExtra(EXTRA_NOTIFICATION)), completionHandler);
-            return;
-        } catch (Notification.FormatException e) {
-            Log.e(TAG, "Invalid notification", e);
-        }
-        completionHandler.run();
-    }
-
-    public void updateCloudMessagesId(final String gcmChannelId, final Runnable completionHandler) {
-        final InstanceCredential credential = InstanceCredential.get(mServer.getPreferences());
-        if (credential == null) return;
-
-        mIOExecutor.submit(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    mClientFactory.newGCDClient(getAccessToken(credential))
-                            .patchInstanceGCMChannel(credential.id, gcmChannelId);
-                } catch (Exception e) {
-                    Log.e(TAG, "Failure when updating GCM channel id", e);
-                } finally {
-                    completionHandler.run();
-                }
-            }
-        });
-    }
-
-    private void handle(Notification notification, Runnable completionHandler) {
-        if (notification == null) {
-            // Unsupported notification type. Ignore.
-            Log.i(TAG, "Unsupported notification");
-            completionHandler.run();
-            return;
-        }
-
-        switch (notification.type) {
-            case INSTANCE_UNREGISTERED:
-                onInstanceUnregistered(notification.instanceId, completionHandler);
-                break;
-
-            case COMMAND_CREATED:
-                onCommand(notification.instanceId, notification.command, completionHandler);
-                break;
-
-            default:
-                completionHandler.run();
-                break;
-        }
-    }
-
-    private void onInstanceUnregistered(String instanceId, Runnable completionHandler) {
-        Log.i(TAG, "Received unregistration notification: " + instanceId);
-        InstanceCredential credential = InstanceCredential.get(mServer.getPreferences());
-        if (credential != null && credential.id.equals(instanceId)) {
-            SharedPreferences.Editor editor = mServer.getPreferences().edit();
-            InstanceCredential.remove(editor);
-            editor.commit();
-        }
-        completionHandler.run();
-    }
-
-    private void onCommand(String instanceId, Command command, Runnable completionHandler) {
-        InstanceCredential credential = InstanceCredential.get(mServer.getPreferences());
-        if (credential != null && credential.id.equals(instanceId)) {
-            mCommandReceiver.receive(
-                    command, new Responder(command, credential, completionHandler));
-        } else {
-            Log.w(TAG, "Ignored command " + command.type + " for " + instanceId);
-            completionHandler.run();
-        }
-    }
-
-    private String getAccessToken(InstanceCredential credential) throws IOException {
-        // Called on IO executor.
-        // TODO(serya): mOAuthResult should be persistent.
-        if (mOAuthResult == null) {
-            mOAuthResult = mClientFactory.newOAuthClient().authenticate(
-                    credential.secret);
-        }
-        return mOAuthResult.accessToken;
-    }
-
-    private final class Responder implements Runnable {
-        private final Command mCommand;
-        private final InstanceCredential mCredential;
-        private final Runnable mCompletionHandler;
-        private boolean mForwardedToIOThread = false;
-
-        public Responder(
-                Command command,
-                InstanceCredential credential,
-                Runnable completionHandler) {
-            assert command != null;
-            assert credential != null;
-            assert completionHandler != null;
-
-            mCommand = command;
-            mCredential = credential;
-            mCompletionHandler = completionHandler;
-        }
-
-        @Override
-        public void run() {
-            if (!mForwardedToIOThread) {
-                mForwardedToIOThread = true;
-                mIOExecutor.submit(this);
-                return;
-            }
-            try {
-                mClientFactory.newGCDClient(getAccessToken(mCredential)).patchCommand(mCommand);
-            } catch (Exception e) {
-                // TODO(serya): Handle authorization exception.
-                Log.e(TAG, "Failure when patching command", e);
-            }
-        }
-    }
-}
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/RTCConfiguration.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/RTCConfiguration.java
deleted file mode 100644
index bb2dbb03..0000000
--- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/RTCConfiguration.java
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Represents RTCConfiguration (http://www.w3.org/TR/webrtc/#rtcconfiguration-type).
- * Replacement for List<PeerConnection.IceServer> in Java WebRTC API.
- * Transferable through signaling channel.
- * Immutable.
- */
-public class RTCConfiguration {
-    /**
-     * Single ICE server description.
-     */
-    public static class IceServer {
-        public final String uri;
-        public final String username;
-        public final String credential;
-
-        public IceServer(String uri, String username, String credential) {
-            this.uri = uri;
-            this.username = username;
-            this.credential = credential;
-        }
-    }
-
-    public final List<IceServer> iceServers;
-
-    private RTCConfiguration(List<IceServer> iceServers) {
-        this.iceServers = Collections.unmodifiableList(new ArrayList<IceServer>(iceServers));
-    }
-
-    public RTCConfiguration() {
-        this(Collections.<IceServer>emptyList());
-    }
-
-    /**
-     * Builder for RTCConfiguration.
-     */
-    public static class Builder {
-        private final List<IceServer> mIceServers = new ArrayList<IceServer>();
-
-        public RTCConfiguration build() {
-            return new RTCConfiguration(mIceServers);
-        }
-
-        public Builder addIceServer(String uri, String username, String credential) {
-            mIceServers.add(new IceServer(uri, username, credential));
-            return this;
-        }
-
-        public Builder addIceServer(String uri) {
-            return addIceServer(uri, "", "");
-        }
-    }
-}
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/ServerSession.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/ServerSession.java
deleted file mode 100644
index 4dadcb9d..0000000
--- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/ServerSession.java
+++ /dev/null
@@ -1,178 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge;
-
-import java.util.List;
-
-/**
- * DevTools Bridge server session. Handles connection with a ClientSession.
- * See SessionBase description for more detais.
- */
-public class ServerSession extends SessionBase implements SessionBase.ServerSessionInterface {
-    private NegotiationCallback mNegotiationCallback;
-    private IceExchangeCallback mIceExchangeCallback;
-    private boolean mIceEchangeRequested = false;
-
-    protected int mGatheringDelayMs = 200;
-
-    public ServerSession(SessionDependencyFactory factory,
-                         Executor executor,
-                         String defaultSocketName) {
-        super(factory, executor, factory.newSocketTunnelServer(defaultSocketName));
-    }
-
-    @Override
-    public void stop() {
-        super.stop();
-        if (mNegotiationCallback != null) {
-            mNegotiationCallback.onFailure("Session stopped");
-            mNegotiationCallback = null;
-        }
-        if (mIceExchangeCallback != null) {
-            mIceExchangeCallback.onFailure("Session stopped");
-            mIceExchangeCallback = null;
-        }
-    }
-
-    @Override
-    public void startSession(RTCConfiguration config,
-                             String offer,
-                             NegotiationCallback callback) {
-        checkCalledOnSessionThread();
-        if (isStarted()) {
-            callback.onFailure("Session already started");
-            return;
-        }
-
-        ClientMessageHandler handler = new ClientMessageHandler();
-        start(config, handler);
-
-        negotiate(offer, callback);
-    }
-
-    @Override
-    public void renegotiate(String offer, NegotiationCallback callback) {
-        checkCalledOnSessionThread();
-        if (!isStarted()) {
-            callback.onFailure("Session is not started");
-            return;
-        }
-
-        callback.onFailure("Not implemented");
-    }
-
-    private void negotiate(String offer, NegotiationCallback callback) {
-        if (mNegotiationCallback != null) {
-            callback.onFailure("Negotiation already in progress");
-            return;
-        }
-
-        mNegotiationCallback = callback;
-        // If success will call onRemoteDescriptionSet.
-        connection().setRemoteDescription(
-                AbstractPeerConnection.SessionDescriptionType.OFFER, offer);
-    }
-
-    protected void onRemoteDescriptionSet() {
-        // If success will call onLocalDescriptionCreatedAndSet.
-        connection().createAndSetLocalDescription(
-                AbstractPeerConnection.SessionDescriptionType.ANSWER);
-    }
-
-    @Override
-    protected void onLocalDescriptionCreatedAndSet(
-            AbstractPeerConnection.SessionDescriptionType type, String description) {
-        assert type == AbstractPeerConnection.SessionDescriptionType.ANSWER;
-
-        mNegotiationCallback.onSuccess(description);
-        mNegotiationCallback = null;
-        onSessionNegotiated();
-    }
-
-    protected void onSessionNegotiated() {
-        if (!isControlChannelOpened())
-            startAutoCloseTimer();
-    }
-
-    @Override
-    public void iceExchange(List<String> clientCandidates,
-                            IceExchangeCallback callback) {
-        checkCalledOnSessionThread();
-        if (!isStarted()) {
-            callback.onFailure("Session disposed");
-            return;
-        }
-
-        if (mNegotiationCallback != null || mIceExchangeCallback != null) {
-            callback.onFailure("Concurrent requests detected");
-            return;
-        }
-
-        mIceExchangeCallback = callback;
-        addIceCandidates(clientCandidates);
-
-        // Give libjingle some time for gathering ice candidates.
-        postOnSessionThread(mGatheringDelayMs, new Runnable() {
-            @Override
-            public void run() {
-                if (isStarted())
-                    sendIceCandidatesBack();
-            }
-        });
-    }
-
-    private void sendIceCandidatesBack() {
-        mIceExchangeCallback.onSuccess(takeIceCandidates());
-        mIceExchangeCallback = null;
-        mIceEchangeRequested = false;
-    }
-
-    @Override
-    protected void onControlChannelOpened() {
-        stopAutoCloseTimer();
-    }
-
-    @Override
-    protected void onFailure(String message) {
-        if (mNegotiationCallback != null) {
-            mNegotiationCallback.onFailure(message);
-            mNegotiationCallback = null;
-        }
-        super.onFailure(message);
-    }
-
-    @Override
-    protected void onIceCandidate(String candidate) {
-        super.onIceCandidate(candidate);
-        if (isControlChannelOpened() && !mIceEchangeRequested) {
-            // New ICE candidate may improve connection even if control channel operable.
-            // If control channel closed client will exchange candidates anyway.
-            sendControlMessage(new SessionControlMessages.IceExchangeMessage());
-            mIceEchangeRequested = true;
-        }
-    }
-
-    protected SocketTunnel newSocketTunnelServer(String serverSocketName) {
-        return mFactory.newSocketTunnelServer(serverSocketName);
-    }
-
-    private final class ClientMessageHandler extends SessionControlMessages.ClientMessageHandler {
-        @Override
-        protected void onMessage(SessionControlMessages.ClientMessage message) {
-            switch (message.type) {
-                case UNKNOWN_REQUEST:
-                    sendControlMessage(((SessionControlMessages.UnknownRequestMessage) message)
-                            .createResponse());
-                    break;
-            }
-        }
-    }
-
-    @Override
-    protected void sendControlMessage(SessionControlMessages.Message<?> message) {
-        assert message instanceof SessionControlMessages.ServerMessage;
-        super.sendControlMessage(message);
-    }
-}
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/ServiceLifetimeManager.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/ServiceLifetimeManager.java
deleted file mode 100644
index 29f0f3b3..0000000
--- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/ServiceLifetimeManager.java
+++ /dev/null
@@ -1,83 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge;
-
-import android.app.IntentService;
-import android.app.Service;
-import android.content.Context;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.PowerManager;
-
-/**
- * Tracks count of running tasks and stops the service when all tasks completed. Supposed to be
- * a part of a service.
- *
- * Usage:
- * class MyService extends Service {
- *     public int onStartCommand(Intent intent, int flags, int startId) {
- *         Runnable intentHandlingTask = mLifetimeManager.startTask(startId);
- *         ...
- *         intentHandlingTask.run(); // Stops self if no other task started.
- *         return START_NOT_STICKY;
- *     }
- * }
- */
-class ServiceLifetimeManager {
-    private final Service mService;
-    private final String mWakeLockKey;
-    private int mLastStartId = -1;
-    private int mActiveTasks = 0;
-    private PowerManager.WakeLock mWakeLock;
-
-    public ServiceLifetimeManager(Service service, String wakeLockKey) {
-        // IntentService is incompatible with this class because it manages lifetime on its own.
-        assert !(service instanceof IntentService);
-
-        mService = service;
-        mWakeLockKey = wakeLockKey;
-    }
-
-    public Runnable startTask(int startId) {
-        mLastStartId = startId;
-        return startTask();
-    }
-
-    public Runnable startTask() {
-        assert isCalledOnServiceLooper();
-        if (mActiveTasks == 0) {
-            if (mWakeLock == null) {
-                PowerManager pm = (PowerManager) mService.getSystemService(Context.POWER_SERVICE);
-                mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, mWakeLockKey);
-            }
-            mWakeLock.acquire();
-        }
-        mActiveTasks++;
-        return new TaskCompletionHandler();
-    }
-
-    private boolean isCalledOnServiceLooper() {
-        return mService.getMainLooper() == Looper.myLooper();
-    }
-
-    private class TaskCompletionHandler implements Runnable {
-        private boolean mCompleted = false;
-
-        @Override
-        public void run() {
-            if (!isCalledOnServiceLooper()) {
-                new Handler(mService.getMainLooper()).post(this);
-                return;
-            }
-            if (mCompleted) return;
-
-            if (--mActiveTasks == 0) {
-                mWakeLock.release();
-                mService.stopSelf(mLastStartId);
-            }
-            mCompleted = true;
-        }
-    }
-}
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/SessionBase.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/SessionBase.java
deleted file mode 100644
index 11fd9b6f..0000000
--- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/SessionBase.java
+++ /dev/null
@@ -1,435 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge;
-
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Base class for ServerSession and ClientSession. Both opens a control channel and a default
- * tunnel. Control channel designated to exchange messages defined in SessionControlMessages.
- *
- * Signaling communication between client and server works in request/response manner. It's more
- * restrictive than traditional bidirectional signaling channel but give more freedom in
- * implementing signaling. Main motivation is that GCD provides API what works in that way.
- *
- * Session is initiated by a client. It creates an offer and sends it along with RTC configuration.
- * Server sends an answer in response. Once session negotiated client starts ICE candidates
- * exchange. It periodically sends own candidates and peeks server's ones. Periodic ICE exchange
- * stops when control channel opens. It resumes if connections state turns to DISCONNECTED (because
- * server may generate ICE candidates to recover connectivity but may not notify through
- * control channel). ICE exchange in CONNECTED state designated to let improve connection
- * when network configuration changed.
- *
- * If session is not started (or resumed) after mAutoCloseTimeoutMs it closes itself.
- *
- * Only default tunnel is supported at the moment. It designated for DevTools UNIX socket.
- * Additional tunnels may be useful for: 1) reverse port forwarding and 2) tunneling
- * WebView DevTools sockets of other applications. Additional tunnels negotiation should
- * be implemented by adding new types of control messages. Dynamic tunnel configuration
- * will need support for session renegotiation.
- *
- * Session is a single threaded object. Until started owner is responsible to synchronizing access
- * to it. When started it must be called on the thread of SessionBase.Executor.
- * All WebRTC callbacks are forwarded on this thread.
- */
-public abstract class SessionBase {
-    private static final int CONTROL_CHANNEL_ID = 0;
-    private static final int DEFAULT_TUNNEL_CHANNEL_ID = 1;
-
-    private final Executor mExecutor;
-    protected final SessionDependencyFactory mFactory;
-    private AbstractPeerConnection mConnection;
-    private AbstractDataChannel mControlChannel;
-    private List<String> mCandidates = new ArrayList<String>();
-    private boolean mControlChannelOpened = false;
-    private boolean mConnected = false;
-    private Cancellable mAutoCloseTask;
-    private SessionControlMessages.MessageHandler mControlMessageHandler;
-    private final Map<Integer, SocketTunnel> mTunnels =
-            new HashMap<Integer, SocketTunnel>();
-    private EventListener mEventListener;
-
-    protected int mAutoCloseTimeoutMs = 30000;
-
-    /**
-     * Allows to post tasks on the thread where the sessions lives.
-     */
-    public interface Executor {
-        Cancellable postOnSessionThread(int delayMs, Runnable runnable);
-        boolean isCalledOnSessionThread();
-    }
-
-    /**
-     * Interface for cancelling scheduled tasks.
-     */
-    public interface Cancellable {
-        void cancel();
-    }
-
-    /**
-     * Representation of server session. All methods are delivered through
-     * signaling channel (except test configurations). Server session is accessible
-     * in request/response manner.
-     */
-    public interface ServerSessionInterface {
-        /**
-         * Starts session with specified RTC configuration and offer.
-         */
-        void startSession(RTCConfiguration config,
-                          String offer,
-                          NegotiationCallback callback);
-
-        /**
-         * Renegoteates session. Needed when tunnels added/removed on the fly.
-         */
-        void renegotiate(String offer, NegotiationCallback callback);
-
-        /**
-         * Sends client's ICE candidates to the server and peeks server's ICE candidates.
-         */
-        void iceExchange(List<String> clientCandidates, IceExchangeCallback callback);
-    }
-
-    /**
-     * Base interface for server callbacks.
-     */
-    public interface ServerCallback {
-        void onFailure(String errorMessage);
-    }
-
-    /**
-     * Server's response to startSession and renegotiate methods.
-     */
-    public interface NegotiationCallback extends ServerCallback {
-        void onSuccess(String answer);
-    }
-
-    /**
-     * Server's response on iceExchange method.
-     */
-    public interface IceExchangeCallback  extends ServerCallback {
-        void onSuccess(List<String> serverCandidates);
-    }
-
-    /**
-     * Listener of session's events.
-     */
-    public interface EventListener {
-        void onCloseSelf();
-    }
-
-    protected SessionBase(SessionDependencyFactory factory,
-                          Executor executor,
-                          SocketTunnel defaultTunnel) {
-        mExecutor = executor;
-        mFactory = factory;
-        addTunnel(DEFAULT_TUNNEL_CHANNEL_ID, defaultTunnel);
-    }
-
-    public final void dispose() {
-        checkCalledOnSessionThread();
-
-        if (isStarted()) stop();
-
-        for (SocketTunnel tunnel : mTunnels.values()) {
-            tunnel.dispose();
-        }
-    }
-
-    public void setEventListener(EventListener listener) {
-        checkCalledOnSessionThread();
-
-        mEventListener = listener;
-    }
-
-    protected AbstractPeerConnection connection() {
-        return mConnection;
-    }
-
-    protected boolean doesTunnelExist(int channelId) {
-        return mTunnels.containsKey(channelId);
-    }
-
-    private final void addTunnel(int channelId, SocketTunnel tunnel) {
-        assert !mTunnels.containsKey(channelId);
-        assert !tunnel.isBound();
-        // Tunnel renegotiation not implemented.
-        assert channelId == DEFAULT_TUNNEL_CHANNEL_ID && !isStarted();
-
-        mTunnels.put(channelId, tunnel);
-    }
-
-    protected void removeTunnel(int channelId) {
-        assert mTunnels.containsKey(channelId);
-        mTunnels.get(channelId).unbind().dispose();
-        mTunnels.remove(channelId);
-    }
-
-    protected final boolean isControlChannelOpened() {
-        return mControlChannelOpened;
-    }
-
-    protected final boolean isConnected() {
-        return mConnected;
-    }
-
-    protected final void postOnSessionThread(Runnable runnable) {
-        postOnSessionThread(0, runnable);
-    }
-
-    protected final Cancellable postOnSessionThread(int delayMs, Runnable runnable) {
-        return mExecutor.postOnSessionThread(delayMs, runnable);
-    }
-
-    protected final void checkCalledOnSessionThread() {
-        assert mExecutor.isCalledOnSessionThread();
-    }
-
-    public final boolean isStarted() {
-        return mConnection != null;
-    }
-
-    /**
-     * Creates and configures peer connection and sets a control message handler.
-     */
-    protected void start(RTCConfiguration config,
-                         SessionControlMessages.MessageHandler handler) {
-        assert !isStarted();
-
-        mConnection = mFactory.createPeerConnection(config, new ConnectionObserver());
-        mControlChannel = mConnection.createDataChannel(CONTROL_CHANNEL_ID);
-        mControlMessageHandler = handler;
-        mControlChannel.registerObserver(new ControlChannelObserver());
-
-        for (Map.Entry<Integer, SocketTunnel> entry : mTunnels.entrySet()) {
-            int channelId = entry.getKey();
-            SocketTunnel tunnel = entry.getValue();
-            tunnel.bind(connection().createDataChannel(channelId));
-        }
-    }
-
-    /**
-     * Disposed objects created in |start|.
-     */
-    public void stop() {
-        checkCalledOnSessionThread();
-
-        assert isStarted();
-
-        stopAutoCloseTimer();
-
-        for (SocketTunnel tunnel : mTunnels.values()) {
-            tunnel.unbind().dispose();
-        }
-
-        AbstractPeerConnection connection = mConnection;
-        mConnection = null;
-        assert !isStarted();
-
-        mControlChannel.unregisterObserver();
-        mControlMessageHandler = null;
-        mControlChannel.dispose();
-        mControlChannel = null;
-
-        // Dispose connection after data channels.
-        connection.dispose();
-    }
-
-    protected abstract void onRemoteDescriptionSet();
-    protected abstract void onLocalDescriptionCreatedAndSet(
-            AbstractPeerConnection.SessionDescriptionType type, String description);
-    protected abstract void onControlChannelOpened();
-
-    protected void onControlChannelClosed() {
-        closeSelf();
-    }
-
-    protected void onIceConnectionChange() {}
-
-    private void handleFailureOnSignalingThread(final String message) {
-        postOnSessionThread(new Runnable() {
-            @Override
-            public void run() {
-                if (isStarted())
-                    onFailure(message);
-            }
-        });
-    }
-
-    protected final void startAutoCloseTimer() {
-        assert mAutoCloseTask == null;
-        assert isStarted();
-        mAutoCloseTask = postOnSessionThread(mAutoCloseTimeoutMs, new Runnable() {
-            @Override
-            public void run() {
-                assert isStarted();
-
-                mAutoCloseTask = null;
-                closeSelf();
-            }
-        });
-    }
-
-    protected final void stopAutoCloseTimer() {
-        if (mAutoCloseTask != null) {
-            mAutoCloseTask.cancel();
-            mAutoCloseTask = null;
-        }
-    }
-
-    protected void closeSelf() {
-        stop();
-        if (mEventListener != null) {
-            mEventListener.onCloseSelf();
-        }
-    }
-
-    // Returns collected candidates (for sending to the remote session) and removes them.
-    protected List<String> takeIceCandidates() {
-        List<String> result = new ArrayList<String>();
-        result.addAll(mCandidates);
-        mCandidates.clear();
-        return result;
-    }
-
-    protected void addIceCandidates(List<String> candidates) {
-        for (String candidate : candidates) {
-            mConnection.addIceCandidate(candidate);
-        }
-    }
-
-    protected void onFailure(String message) {
-        closeSelf();
-    }
-
-    protected void onIceCandidate(String candidate) {
-        mCandidates.add(candidate);
-    }
-
-    /**
-     * Receives callbacks from the peer connection on the signaling thread. Forwards them
-     * on the session thread. All session event handling methods assume session started (prevents
-     * disposed objects). It drops callbacks it closed.
-     */
-    private final class ConnectionObserver implements AbstractPeerConnection.Observer {
-        @Override
-        public void onFailure(final String description) {
-            postOnSessionThread(new Runnable() {
-                @Override
-                public void run() {
-                    if (!isStarted()) return;
-                    SessionBase.this.onFailure(description);
-                }
-            });
-        }
-
-        @Override
-        public void onLocalDescriptionCreatedAndSet(
-                final AbstractPeerConnection.SessionDescriptionType type,
-                final String description) {
-            postOnSessionThread(new Runnable() {
-                @Override
-                public void run() {
-                    if (!isStarted()) return;
-                    SessionBase.this.onLocalDescriptionCreatedAndSet(type, description);
-                }
-            });
-        }
-
-        @Override
-        public void onRemoteDescriptionSet() {
-            postOnSessionThread(new Runnable() {
-                @Override
-                public void run() {
-                    if (!isStarted()) return;
-                    SessionBase.this.onRemoteDescriptionSet();
-                }
-            });
-        }
-
-        @Override
-        public void onIceCandidate(final String candidate) {
-            postOnSessionThread(new Runnable() {
-                @Override
-                public void run() {
-                    if (!isStarted()) return;
-                    SessionBase.this.onIceCandidate(candidate);
-                }
-            });
-        }
-
-        @Override
-        public void onIceConnectionChange(final boolean connected) {
-            postOnSessionThread(new Runnable() {
-                @Override
-                public void run() {
-                    if (!isStarted()) return;
-                    mConnected = connected;
-                    SessionBase.this.onIceConnectionChange();
-                }
-            });
-        }
-    }
-
-    /**
-     * Receives callbacks from the control channel. Forwards them on the session thread.
-     */
-    private final class ControlChannelObserver implements AbstractDataChannel.Observer {
-        @Override
-        public void onStateChange(final AbstractDataChannel.State state) {
-            postOnSessionThread(new Runnable() {
-                @Override
-                public void run() {
-                    if (!isStarted()) return;
-                    mControlChannelOpened = state == AbstractDataChannel.State.OPEN;
-
-                    if (mControlChannelOpened) {
-                        onControlChannelOpened();
-                    } else {
-                        onControlChannelClosed();
-                    }
-                }
-            });
-        }
-
-        @Override
-        public void onMessage(ByteBuffer message) {
-            final byte[] bytes = new byte[message.remaining()];
-            message.get(bytes);
-            postOnSessionThread(new Runnable() {
-                @Override
-                public void run() {
-                    if (!isStarted() || mControlMessageHandler == null) return;
-
-                    try {
-                        mControlMessageHandler.readMessage(bytes);
-                    } catch (SessionControlMessages.InvalidFormatException e) {
-                        // TODO(serya): handle
-                    }
-                }
-            });
-        }
-    }
-
-    protected void sendControlMessage(SessionControlMessages.Message<?> message) {
-        assert mControlChannelOpened;
-
-        byte[] bytes = SessionControlMessages.toByteArray(message);
-        ByteBuffer rawMessage = ByteBuffer.allocateDirect(bytes.length);
-        rawMessage.put(bytes);
-
-        sendControlMessage(rawMessage);
-    }
-
-    private void sendControlMessage(ByteBuffer rawMessage) {
-        rawMessage.limit(rawMessage.position());
-        rawMessage.position(0);
-        mControlChannel.send(rawMessage, AbstractDataChannel.MessageType.TEXT);
-    }
-}
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/SessionControlMessages.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/SessionControlMessages.java
deleted file mode 100644
index 4c16520..0000000
--- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/SessionControlMessages.java
+++ /dev/null
@@ -1,251 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge;
-
-import android.util.JsonReader;
-import android.util.JsonWriter;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.OutputStreamWriter;
-
-/**
- * Defines protocol of control channel of SessionBase. Messages are JSON serializable
- * and transferred through AbstractDataChannel.
- */
-public final class SessionControlMessages {
-    private SessionControlMessages() {
-        throw new RuntimeException("Class not intended to instantiate");
-    }
-
-    /**
-     * Types of messages that client sends to server.
-     */
-    enum ClientMessageType {
-        UNKNOWN_REQUEST
-    }
-
-    /**
-     * Types of messages that servers sends to client.
-     */
-    enum ServerMessageType {
-        ICE_EXCHANGE,
-        UNKNOWN_RESPONSE
-    }
-
-    /**
-     * Base class for all messages.
-     */
-    public abstract static class Message<T extends Enum> {
-        public final T type;
-
-        protected Message(T type) {
-            this.type = type;
-        }
-
-        public void write(JsonWriter writer) throws IOException {
-            writer.name("type");
-            writer.value(type.toString());
-        }
-    }
-
-    /**
-     * Base calss for messages that client sends to server.
-     */
-    public abstract static class ClientMessage extends Message<ClientMessageType> {
-        protected ClientMessage(ClientMessageType type) {
-            super(type);
-        }
-    }
-
-    /**
-     * Base class for messages that server sends to client.
-     */
-    public abstract static class ServerMessage extends Message<ServerMessageType> {
-        protected ServerMessage(ServerMessageType type) {
-            super(type);
-        }
-    }
-
-    /**
-     * Server sends this message when it has ICE candidates to exchange. Client initiates
-     * ICE exchange over signaling channel.
-     */
-    public static final class IceExchangeMessage extends ServerMessage {
-        public IceExchangeMessage() {
-            super(ServerMessageType.ICE_EXCHANGE);
-        }
-    }
-
-    /**
-     * Server response on unrecognized client message.
-     */
-    public static final class UnknownResponseMessage extends ServerMessage {
-        public final String rawRequestType;
-
-        public UnknownResponseMessage(String rawRequestType) {
-            super(ServerMessageType.UNKNOWN_RESPONSE);
-            this.rawRequestType = rawRequestType;
-        }
-
-        @Override
-        public void write(JsonWriter writer) throws IOException {
-            super.write(writer);
-            writer.name("rawRequestType");
-            writer.value(rawRequestType.toString());
-        }
-    }
-
-    /**
-     * Helper class to represent message of unknown type. Should not be sent.
-     */
-    public static final class UnknownRequestMessage extends ClientMessage {
-        public final String rawType;
-
-        public UnknownRequestMessage(String rawType) {
-            super(ClientMessageType.UNKNOWN_REQUEST);
-            this.rawType = rawType;
-        }
-
-        @Override
-        public void write(JsonWriter writer) throws IOException {
-            throw new RuntimeException("Should not be serialized");
-        }
-
-        public UnknownResponseMessage createResponse() {
-            return new UnknownResponseMessage(rawType);
-        }
-    }
-
-    private static <T extends Enum<T>> T getMessageType(
-            Class<T> enumType, String rawType, T defaultType) throws IOException {
-        try {
-            return Enum.valueOf(enumType, rawType);
-        } catch (IllegalArgumentException e) {
-            if (defaultType != null)
-                return defaultType;
-            throw new IOException("Invalid message type " + rawType);
-        }
-    }
-
-    public static void write(JsonWriter writer, Message<?> message) throws IOException {
-        writer.beginObject();
-        message.write(writer);
-        writer.endObject();
-    }
-
-    public static ClientMessage readClientMessage(JsonReader reader) throws IOException {
-        String rawType = "";
-        boolean success = false;
-
-        reader.beginObject();
-        while (reader.hasNext()) {
-            String name = reader.nextName();
-            if ("type".equals(name)) {
-                rawType = reader.nextString();
-            }
-        }
-        reader.endObject();
-
-        switch (getMessageType(ClientMessageType.class,
-                               rawType,
-                               ClientMessageType.UNKNOWN_REQUEST)) {
-            case UNKNOWN_REQUEST:
-                return new UnknownRequestMessage(rawType);
-        }
-        throw new IOException("Invalid message");
-    }
-
-    public static ServerMessage readServerMessage(JsonReader reader) throws IOException {
-        String rawType = "";
-        String rawRequestType = null;
-
-        reader.beginObject();
-        while (reader.hasNext()) {
-            String name = reader.nextName();
-            if ("type".equals(name)) {
-                rawType = reader.nextString();
-            } else if ("rawRequestType".equals(name)) {
-                rawRequestType = reader.nextString();
-            }
-        }
-        reader.endObject();
-
-        switch (getMessageType(ServerMessageType.class, rawType, null)) {
-            case ICE_EXCHANGE:
-                return new IceExchangeMessage();
-            case UNKNOWN_RESPONSE:
-                return new UnknownResponseMessage(rawRequestType);
-        }
-        throw new IOException("Invalid message");
-    }
-
-    /**
-     * Base class for client and server message handlers.
-     */
-    public abstract static class MessageHandler {
-        protected abstract void readMessage(JsonReader reader) throws IOException;
-
-        public boolean readMessage(byte[] bytes) throws InvalidFormatException {
-            try {
-                readMessage(new JsonReader(new InputStreamReader(new ByteArrayInputStream(bytes))));
-                return true;
-            } catch (IOException e) {
-                throw new InvalidFormatException(e);
-            }
-        }
-    }
-
-    /**
-     * Exception when parsing or handling message.
-     */
-    public static class InvalidFormatException extends IOException {
-        public InvalidFormatException(IOException e) {
-            super(e);
-        }
-
-        public InvalidFormatException(String message) {
-            super(message);
-        }
-    }
-
-    /**
-     * Base class for handler of server messages (to be created on client).
-     */
-    public abstract static class ServerMessageHandler extends MessageHandler {
-        @Override
-        protected void readMessage(JsonReader reader) throws IOException {
-            onMessage(readServerMessage(reader));
-        }
-
-        protected abstract void onMessage(ServerMessage message);
-    }
-
-    /**
-     * Base class for handler of client messages (to be created on server).
-     */
-    public abstract static class ClientMessageHandler extends MessageHandler {
-        @Override
-        public void readMessage(JsonReader reader) throws IOException {
-            onMessage(readClientMessage(reader));
-        }
-
-        protected abstract void onMessage(ClientMessage message);
-    }
-
-    public static byte[] toByteArray(Message<?> message) {
-        ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
-        JsonWriter writer = new JsonWriter(new OutputStreamWriter(byteStream));
-        try {
-            write(writer, message);
-            writer.close();
-            return byteStream.toByteArray();
-        } catch (IOException e) {
-            throw new RuntimeException(e);
-        }
-    }
-}
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/SessionDependencyFactory.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/SessionDependencyFactory.java
deleted file mode 100644
index e90e8ce4..0000000
--- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/SessionDependencyFactory.java
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge;
-
-/**
- * Implements AbstractDataChannel and AbstractPeerConnection on top of org.webrtc.* API.
- * Isolation is needed because some configuration of DevTools bridge may not be based on
- * Java API.
- * In addition abstraction layer isolates SessionBase from complexity of underlying API
- * beside used features.
- */
-public abstract class SessionDependencyFactory {
-    private interface Constructor {
-        SessionDependencyFactory newInstance();
-    }
-
-    private static Constructor sConstructor;
-
-    public static SessionDependencyFactory newInstance() {
-        return sConstructor.newInstance();
-    }
-
-    public static <T extends SessionDependencyFactory> void init(final Class<T> c) {
-        sConstructor = new Constructor() {
-            @Override
-            public SessionDependencyFactory newInstance() {
-                try {
-                    return c.newInstance();
-                } catch (Exception e) {
-                    throw new RuntimeException(e);
-                }
-            }
-        };
-    }
-
-    public abstract AbstractPeerConnection createPeerConnection(
-            RTCConfiguration config, AbstractPeerConnection.Observer observer);
-
-    public abstract SocketTunnel newSocketTunnelServer(String socketName);
-
-    public abstract void dispose();
-}
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/SessionDependencyFactoryNative.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/SessionDependencyFactoryNative.java
deleted file mode 100644
index cac78a5..0000000
--- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/SessionDependencyFactoryNative.java
+++ /dev/null
@@ -1,283 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge;
-
-import org.chromium.base.CalledByNative;
-import org.chromium.base.JNINamespace;
-
-import java.nio.ByteBuffer;
-
-/**
- * Native implementation of session dependency factory on top of C++
- * libjingle API.
- */
-@JNINamespace("devtools_bridge::android")
-public class SessionDependencyFactoryNative extends SessionDependencyFactory {
-    private final long mFactoryPtr;
-
-    public SessionDependencyFactoryNative() {
-        mFactoryPtr = nativeCreateFactory();
-        assert mFactoryPtr != 0;
-    }
-
-    @Override
-    public AbstractPeerConnection createPeerConnection(
-            RTCConfiguration config, AbstractPeerConnection.Observer observer) {
-        assert config != null;
-        assert observer != null;
-
-        long configPtr = nativeCreateConfig();
-        for (RTCConfiguration.IceServer server : config.iceServers) {
-            nativeAddIceServer(configPtr, server.uri, server.username, server.credential);
-        }
-
-        return new PeerConnectionImpl(mFactoryPtr, configPtr, observer);
-    }
-
-    @Override
-    public SocketTunnel newSocketTunnelServer(String socketBase) {
-        return new SocketTunnelServerImpl(mFactoryPtr, socketBase);
-    }
-
-    @Override
-    public void dispose() {
-        nativeDestroyFactory(mFactoryPtr);
-    }
-
-    private static final class PeerConnectionImpl extends AbstractPeerConnection {
-        private final long mConnectionPtr;
-
-        // Takes ownership on |configPtr|.
-        public PeerConnectionImpl(
-                long factoryPtr, long configPtr,
-                AbstractPeerConnection.Observer observer) {
-            mConnectionPtr = nativeCreatePeerConnection(factoryPtr, configPtr, observer);
-            assert mConnectionPtr != 0;
-        }
-
-        @Override
-        public void createAndSetLocalDescription(SessionDescriptionType type) {
-            switch (type) {
-                case OFFER:
-                    nativeCreateAndSetLocalOffer(mConnectionPtr);
-                    break;
-
-                case ANSWER:
-                    nativeCreateAndSetLocalAnswer(mConnectionPtr);
-                    break;
-            }
-        }
-
-        @Override
-        public void setRemoteDescription(SessionDescriptionType type, String description) {
-            switch (type) {
-                case OFFER:
-                    nativeSetRemoteOffer(mConnectionPtr, description);
-                    break;
-
-                case ANSWER:
-                    nativeSetRemoteAnswer(mConnectionPtr, description);
-                    break;
-            }
-        }
-
-        @Override
-        public void addIceCandidate(String candidate) {
-            // TODO(serya): Handle IllegalArgumentException exception.
-            IceCandidate parsed = IceCandidate.fromString(candidate);
-            nativeAddIceCandidate(mConnectionPtr, parsed.sdpMid, parsed.sdpMLineIndex, parsed.sdp);
-        }
-
-        @Override
-        public void dispose() {
-            nativeDestroyPeerConnection(mConnectionPtr);
-        }
-
-        @Override
-        public AbstractDataChannel createDataChannel(int channelId) {
-            return new DataChannelImpl(nativeCreateDataChannel(mConnectionPtr, channelId));
-        }
-    }
-
-    private static final class DataChannelImpl extends AbstractDataChannel {
-        private final long mChannelPtr;
-
-        public DataChannelImpl(long ptr) {
-            assert ptr != 0;
-            mChannelPtr = ptr;
-        }
-
-        long nativePtr() {
-            return mChannelPtr;
-        }
-
-        @Override
-        public void registerObserver(Observer observer) {
-            nativeRegisterDataChannelObserver(mChannelPtr, observer);
-        }
-
-        @Override
-        public void unregisterObserver() {
-            nativeUnregisterDataChannelObserver(mChannelPtr);
-        }
-
-        @Override
-        public void send(ByteBuffer message, MessageType type) {
-            assert message.position() == 0;
-            int length = message.limit();
-            assert length > 0;
-
-            switch (type) {
-                case BINARY:
-                    nativeSendBinaryMessage(mChannelPtr, message, length);
-                    break;
-
-                case TEXT:
-                    nativeSendTextMessage(mChannelPtr, message, length);
-                    break;
-            }
-        }
-
-        @Override
-        public void close() {
-            nativeCloseDataChannel(mChannelPtr);
-        }
-
-        @Override
-        public void dispose() {
-            nativeDestroyDataChannel(mChannelPtr);
-        }
-    }
-
-    private static class SocketTunnelServerImpl implements SocketTunnel {
-        private final String mSocketName;
-        private final long mFactoryPtr;
-        private DataChannelImpl mDataChannel;
-        private long mTunnelPtr;
-
-        public SocketTunnelServerImpl(long factoryPtr, String socketName) {
-            mFactoryPtr = factoryPtr;
-            mSocketName = socketName;
-        }
-
-        @Override
-        public void bind(AbstractDataChannel dataChannel) {
-            mDataChannel = (DataChannelImpl) dataChannel;
-            mTunnelPtr = nativeCreateSocketTunnelServer(
-                    mFactoryPtr, mDataChannel.nativePtr(), mSocketName);
-        }
-
-        @Override
-        public AbstractDataChannel unbind() {
-            AbstractDataChannel result = mDataChannel;
-            nativeDestroySocketTunnelServer(mTunnelPtr);
-            mTunnelPtr = 0;
-            mDataChannel = null;
-            return result;
-        }
-
-        @Override
-        public boolean isBound() {
-            return mDataChannel != null;
-        }
-
-        @Override
-        public void dispose() {
-            assert !isBound();
-        }
-    }
-
-    // Peer connection callbacks.
-
-    @CalledByNative
-    private static void notifyLocalOfferCreatedAndSetSet(Object observer, String description) {
-        ((AbstractPeerConnection.Observer) observer).onLocalDescriptionCreatedAndSet(
-                AbstractPeerConnection.SessionDescriptionType.OFFER, description);
-    }
-
-    @CalledByNative
-    private static void notifyLocalAnswerCreatedAndSetSet(Object observer, String description) {
-        ((AbstractPeerConnection.Observer) observer).onLocalDescriptionCreatedAndSet(
-                AbstractPeerConnection.SessionDescriptionType.ANSWER, description);
-    }
-
-    @CalledByNative
-    private static void notifyRemoteDescriptionSet(Object observer) {
-        ((AbstractPeerConnection.Observer) observer).onRemoteDescriptionSet();
-    }
-
-    @CalledByNative
-    private static void notifyConnectionFailure(Object observer, String description) {
-        ((AbstractPeerConnection.Observer) observer).onFailure(description);
-    }
-
-    @CalledByNative
-    private static void notifyIceCandidate(
-            Object observer, String sdpMid, int sdpMLineIndex, String sdp) {
-        ((AbstractPeerConnection.Observer) observer)
-                .onIceCandidate(new AbstractPeerConnection.IceCandidate(
-                        sdpMid, sdpMLineIndex, sdp).toString());
-    }
-
-    @CalledByNative
-    private static void notifyIceConnectionChange(Object observer, boolean connected) {
-        ((AbstractPeerConnection.Observer) observer)
-                .onIceConnectionChange(connected);
-    }
-
-    // Data channel callbacks.
-
-    @CalledByNative
-    private static void notifyChannelOpen(Object observer) {
-        ((AbstractDataChannel.Observer) observer)
-                .onStateChange(AbstractDataChannel.State.OPEN);
-    }
-
-    @CalledByNative
-    private static void notifyChannelClose(Object observer) {
-        ((AbstractDataChannel.Observer) observer)
-                .onStateChange(AbstractDataChannel.State.CLOSED);
-    }
-
-    @CalledByNative
-    private static void notifyMessage(Object observer, ByteBuffer message) {
-        ((AbstractDataChannel.Observer) observer)
-                .onMessage(message);
-    }
-
-    private static native long nativeCreateFactory();
-    private static native void nativeDestroyFactory(long factoryPtr);
-
-    private static native long nativeCreateConfig();
-    private static native void nativeAddIceServer(
-            long configPtr, String uri, String username, String credential);
-
-    // Takes ownership on |configPtr|.
-    private static native long nativeCreatePeerConnection(
-            long factoryPtr, long configPtr, Object observer);
-    private static native void nativeDestroyPeerConnection(long connectionPtr);
-
-    private static native void nativeCreateAndSetLocalOffer(long connectionPtr);
-    private static native void nativeCreateAndSetLocalAnswer(long connectionPtr);
-    private static native void nativeSetRemoteOffer(long connectionPtr, String description);
-    private static native void nativeSetRemoteAnswer(long connectionPtr, String description);
-    private static native void nativeAddIceCandidate(
-            long peerConnectionPtr, String sdpMid, int sdpMLineIndex, String sdp);
-
-    private static native long nativeCreateDataChannel(long connectionPtr, int channelId);
-    private static native void nativeDestroyDataChannel(long channelPtr);
-
-    private static native void nativeRegisterDataChannelObserver(
-            long channelPtr, Object observer);
-    private static native void nativeUnregisterDataChannelObserver(long channelPtr);
-    private static native void nativeSendBinaryMessage(
-            long channelPtr, ByteBuffer message, int size);
-    private static native void nativeSendTextMessage(long channelPtr, ByteBuffer message, int size);
-    private static native void nativeCloseDataChannel(long channelPtr);
-
-    private static native long nativeCreateSocketTunnelServer(
-            long factoryPtr, long channelPtr, String socketName);
-    private static native void nativeDestroySocketTunnelServer(long tunnelPtr);
-}
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/SignalingReceiver.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/SignalingReceiver.java
deleted file mode 100644
index fb914d8..0000000
--- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/SignalingReceiver.java
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge;
-
-import java.util.List;
-
-/**
- * Signaling channel interface. Methods are marshalled through GCM.
- * Direct calling supported for tests.
- *
- * Primary reason of the signaling channel is supporting debugging sessions (so why
- * it looks like SessionBase.ServerSessionInterface with session ids). It also
- * may be used for retrieving information when establishing session is not appropriate.
- */
-public interface SignalingReceiver {
-    /**
-     * Starts new session and assigns sessionId to it. Passes all arguments to
-     * the ServerSession object. Session ID must be globay unique (like long random) to
-     * avoid conflicts among clients.
-     */
-    void startSession(
-            String sessionId,
-            RTCConfiguration config,
-            String offer,
-            SessionBase.NegotiationCallback callback);
-
-    /**
-     * Passes call to the appropriate ServerSession object (if it still exists).
-     */
-    void renegotiate(
-            String sessionId,
-            String offer,
-            SessionBase.NegotiationCallback callback);
-
-    /**
-     * Passes call to the appropriate ServerSession object (if it still exists).
-     */
-    void iceExchange(
-            String sessionId,
-            List<String> clientCandidates,
-            SessionBase.IceExchangeCallback callback);
-}
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/SocketTunnel.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/SocketTunnel.java
deleted file mode 100644
index f7670e8..0000000
--- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/SocketTunnel.java
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge;
-
-/**
- * Interface for client or server socket tunnel. Tunnels a socket over a data channel.
- * Client tunnel should be bound to one side and server tunnel to another.
- *
- * Data flow schema looks like this:
- *
- * DevToolsServer
- * <-unix socket->
- * SocketTunnelServer
- * <-data channel->
- * SocketTunnelClient
- * <- unix socket ->
- * Client (DevTools frontend)
- */
-interface SocketTunnel {
-    void bind(AbstractDataChannel dataChannel);
-    AbstractDataChannel unbind();
-    boolean isBound();
-
-    void dispose();
-}
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/apiary/ApiaryClientFactory.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/apiary/ApiaryClientFactory.java
deleted file mode 100644
index 92df28a..0000000
--- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/apiary/ApiaryClientFactory.java
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge.apiary;
-
-import android.net.http.AndroidHttpClient;
-
-import org.chromium.base.JNINamespace;
-
-/**
- * Factory for creating clients for external APIs.
- */
-@JNINamespace("devtools_bridge::android")
-public class ApiaryClientFactory {
-    private static final String USER_AGENT = "DevTools bridge";
-
-    public static final String OAUTH_SCOPE = "https://www.googleapis.com/auth/clouddevices";
-
-    protected final AndroidHttpClient mHttpClient = AndroidHttpClient.newInstance(USER_AGENT);
-
-    /**
-     * Creates a new GCD client with auth token.
-     */
-    public GCDClient newGCDClient(String oAuthToken) {
-        return new GCDClient(mHttpClient, getAPIKey(), oAuthToken);
-    }
-
-    /**
-     * Creates a new anonymous client. GCD requires client been not authenticated by user or
-     * device credentials for finalizing registration.
-     */
-    public GCDClient newAnonymousGCDClient() {
-        return new GCDClient(mHttpClient, nativeGetAPIKey());
-    }
-
-    public OAuthClient newOAuthClient() {
-        return new OAuthClient(
-                mHttpClient, OAUTH_SCOPE, getOAuthClientId(), nativeGetOAuthClientSecret());
-    }
-
-    public BlockingGCMRegistrar newGCMRegistrar() {
-        return new BlockingGCMRegistrar();
-    }
-
-    public void close() {
-        mHttpClient.close();
-    }
-
-    public String getOAuthClientId() {
-        return nativeGetOAuthClientId();
-    }
-
-    protected String getAPIKey() {
-        return nativeGetAPIKey();
-    }
-
-    private native String nativeGetAPIKey();
-    private native String nativeGetOAuthClientId();
-    private native String nativeGetOAuthClientSecret();
-}
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/apiary/BlockingGCMRegistrar.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/apiary/BlockingGCMRegistrar.java
deleted file mode 100644
index 3cf5eaf0..0000000
--- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/apiary/BlockingGCMRegistrar.java
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge.apiary;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.Looper;
-
-import com.google.ipc.invalidation.external.client.contrib.MultiplexingGcmListener;
-
-import java.io.IOException;
-import java.util.concurrent.CountDownLatch;
-
-/**
- * Helps using MultiplexingGcmListene in blocking manner. If the app has not registered in GCM
- * it sends registration request and waits for an intent with registration ID.
- * Waiting may be interrupted. Must not be used on UI (or Context's main) looper.
- */
-public final class BlockingGCMRegistrar {
-    public String blockingGetRegistrationId(Context context)
-            throws InterruptedException, IOException {
-        assert context != null;
-        assert context.getMainLooper() != Looper.myLooper();
-
-        Receiver receiver = new Receiver();
-        receiver.register(context);
-        try {
-            // MultiplexingGcmListener starts registration if the app has not registered yet.
-            String result = MultiplexingGcmListener.initializeGcm(context);
-            if (result != null && !result.isEmpty()) return result;
-            return receiver.awaitRegistrationId();
-        } finally {
-            receiver.unregister(context);
-        }
-    }
-
-    private static class Receiver extends BroadcastReceiver {
-        private final CountDownLatch mDone = new CountDownLatch(1);
-
-        private String mRegistrationId;
-
-        public void register(Context context) {
-            IntentFilter filter = new IntentFilter();
-            filter.addCategory(context.getPackageName());
-            filter.addAction(MultiplexingGcmListener.Intents.ACTION);
-            context.registerReceiver(this, filter);
-        }
-
-        public void unregister(Context context) {
-            context.unregisterReceiver(this);
-        }
-
-        public String awaitRegistrationId() throws InterruptedException, IOException {
-            mDone.await();
-            if (mRegistrationId != null) {
-                return mRegistrationId;
-            }
-            throw new IOException();
-        }
-
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            assert intent.getAction().equals(MultiplexingGcmListener.Intents.ACTION);
-
-            if (!intent.getBooleanExtra(
-                    MultiplexingGcmListener.Intents.EXTRA_OP_REGISTERED, false)) {
-                return;
-            }
-
-            mRegistrationId = intent.getStringExtra(
-                    MultiplexingGcmListener.Intents.EXTRA_DATA_REG_ID);
-
-            if (mRegistrationId != null) {
-                mDone.countDown();
-            }
-        }
-    }
-}
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/apiary/GCDClient.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/apiary/GCDClient.java
deleted file mode 100644
index 7a3f52d..0000000
--- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/apiary/GCDClient.java
+++ /dev/null
@@ -1,193 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge.apiary;
-
-import android.util.JsonReader;
-
-import org.apache.http.HttpResponse;
-import org.apache.http.client.HttpClient;
-import org.apache.http.client.HttpResponseException;
-import org.apache.http.client.ResponseHandler;
-import org.apache.http.client.methods.HttpDelete;
-import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
-import org.apache.http.client.methods.HttpGet;
-import org.apache.http.client.methods.HttpPost;
-import org.apache.http.client.methods.HttpRequestBase;
-import org.apache.http.entity.StringEntity;
-
-import org.chromium.components.devtools_bridge.commands.Command;
-import org.chromium.components.devtools_bridge.gcd.InstanceCredential;
-import org.chromium.components.devtools_bridge.gcd.InstanceDescription;
-import org.chromium.components.devtools_bridge.gcd.MessageReader;
-import org.chromium.components.devtools_bridge.gcd.MessageWriter;
-
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.net.URI;
-
-/**
- * Client for accessing GCD API.
- */
-public class GCDClient {
-    private static final String API_BASE = "https://www.googleapis.com/clouddevices/v1";
-    public static final String ENCODING = "UTF-8";
-    protected static final String CONTENT_TYPE = "application/json; charset=" + ENCODING;
-
-    protected final HttpClient mHttpClient;
-    private final String mAPIKey;
-    private final String mOAuthToken;
-
-    GCDClient(HttpClient httpClient, String apiKey, String oAuthToken) {
-        mHttpClient = httpClient;
-        mAPIKey = apiKey;
-        mOAuthToken = oAuthToken;
-    }
-
-    GCDClient(HttpClient httpClient, String apiKey) {
-        this(httpClient, apiKey, null);
-    }
-
-    /**
-     * Creation of a registration ticket is the first step in instance registration. Client must
-     * have user credentials. If the ticket has been registered it will be associated with the
-     * user. Next step is registration ticket patching.
-     */
-    public final String createRegistrationTicket() throws IOException {
-        assert mOAuthToken != null;
-
-        return mHttpClient.execute(
-                newHttpPost("/registrationTickets", "{\"userEmail\":\"me\"}"),
-                new JsonResponseHandler<String>() {
-                    @Override
-                    public String readResponse(JsonReader reader) throws IOException {
-                        return new MessageReader(reader).readTicketId();
-                    }
-                });
-    }
-
-    /**
-     * Patching registration ticket. GCD gets device definition including commands metadata,
-     * GCM channel description and user-visible instance name.
-     */
-    public final void patchRegistrationTicket(String ticketId, InstanceDescription description)
-            throws IOException {
-        String content = new MessageWriter().writeTicketPatch(description).close().toString();
-
-        mHttpClient.execute(
-                newHttpPatch("/registrationTickets/" + ticketId, content),
-                new EmptyResponseHandler());
-    }
-
-    /**
-     * Finalizing registration. Client must be anonymous (GCD requirement). GCD provides
-     * instance credentials needed for handling commands.
-     */
-    public final InstanceCredential finalizeRegistration(String ticketId) throws IOException {
-        return mHttpClient.execute(
-                newHttpPost("/registrationTickets/" + ticketId + "/finalize", ""),
-                new JsonResponseHandler<InstanceCredential>() {
-                    @Override
-                    public InstanceCredential readResponse(JsonReader reader) throws IOException {
-                        return new MessageReader(reader).readInstanceCredential();
-                    }
-                });
-    }
-
-    public final void patchInstanceGCMChannel(String instanceId, String gcmChannelId)
-            throws IOException {
-        String content = new MessageWriter()
-                .writeDeviceGCMChannelPatch(gcmChannelId).close().toString();
-
-        mHttpClient.execute(
-                newHttpPatch("/devices/" + instanceId, content),
-                new EmptyResponseHandler());
-    }
-
-    /**
-     * Deletes registered instance (unregisters). If client has instance credentials then
-     * instanceId must be it's own ID. If client has user credentials then instance must belong
-     * to the user.
-     */
-    public void deleteInstance(String instanceId) throws IOException {
-        mHttpClient.execute(
-                newHttpDelete("/devices/" + instanceId),
-                new EmptyResponseHandler());
-    }
-
-    /**
-     * Patches the command (previously received with Notification) with out-parameters or
-     * an error message.
-     */
-    public final void patchCommand(Command command) throws IOException {
-        String content = new MessageWriter().writeCommandPatch(command).close().toString();
-
-        mHttpClient.execute(
-                newHttpPatch("/commands/" + command.id, content),
-                new EmptyResponseHandler());
-    }
-
-    protected final HttpGet newHttpGet(String path) {
-        return prepare(new HttpGet(buildUrl(path)));
-    }
-
-    protected final HttpPost newHttpPost(String path, String content)
-            throws UnsupportedEncodingException {
-        return prepare(new HttpPost(buildUrl(path)), content);
-    }
-
-    protected final HttpPost newHttpPost(String path, String query, String content)
-            throws UnsupportedEncodingException {
-        return prepare(new HttpPost(buildUrl(path, query)), content);
-    }
-
-    protected final HttpPatch newHttpPatch(String path, String content)
-            throws UnsupportedEncodingException {
-        return prepare(new HttpPatch(buildUrl(path)), content);
-    }
-
-    protected final HttpDelete newHttpDelete(String path) {
-        return prepare(new HttpDelete(buildUrl(path)));
-    }
-
-    private String buildUrl(String path) {
-        return API_BASE + path + "?key=" + mAPIKey;
-    }
-
-    private String buildUrl(String path, String query) {
-        return API_BASE + path + "?" + query + "&key=" + mAPIKey;
-    }
-
-    private <T extends HttpEntityEnclosingRequestBase> T prepare(T request, String content)
-            throws UnsupportedEncodingException {
-        request.setEntity(new StringEntity(content, ENCODING));
-        request.addHeader("Content-Type", CONTENT_TYPE);
-        return prepare(request);
-    }
-
-    private <T extends HttpRequestBase> T prepare(T request) {
-        if (mOAuthToken != null) {
-            request.addHeader("Authorization", "Bearer " + mOAuthToken);
-        }
-        return request;
-    }
-
-    private static final class HttpPatch extends HttpEntityEnclosingRequestBase {
-        public HttpPatch(String uri) {
-            setURI(URI.create(uri));
-        }
-
-        public String getMethod() {
-            return "PATCH";
-        }
-    }
-
-    private static class EmptyResponseHandler implements ResponseHandler<Void> {
-        @Override
-        public Void handleResponse(HttpResponse response) throws HttpResponseException {
-            JsonResponseHandler.checkStatus(response);
-            return null;
-        }
-    }
-}
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/apiary/JsonResponseHandler.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/apiary/JsonResponseHandler.java
deleted file mode 100644
index 1700cc5..0000000
--- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/apiary/JsonResponseHandler.java
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge.apiary;
-
-import android.util.JsonReader;
-
-import org.apache.http.HttpEntity;
-import org.apache.http.HttpResponse;
-import org.apache.http.StatusLine;
-import org.apache.http.client.ClientProtocolException;
-import org.apache.http.client.HttpResponseException;
-import org.apache.http.client.ResponseHandler;
-
-import java.io.IOException;
-import java.io.InputStreamReader;
-
-/**
- * Base class for a ResponseHandler that reads response with JsonReader. Like BasicResponseHandler
- * throws HttpResponseException if response code >= 300.
- *
- * It catchs JsonReader's runtime exception (IllegalStateException and IllegalArgumentException)
- * and wraps them into ResponseFormatException.
- */
-abstract class JsonResponseHandler<T> implements ResponseHandler<T> {
-    public static void checkStatus(HttpResponse response) throws HttpResponseException {
-        StatusLine statusLine = response.getStatusLine();
-        if (response.getStatusLine().getStatusCode() >= 300) {
-            throw new HttpResponseException(
-                    statusLine.getStatusCode(), statusLine.getReasonPhrase());
-        }
-    }
-
-    @Override
-    public final T handleResponse(HttpResponse response)
-            throws IOException, ClientProtocolException {
-        checkStatus(response);
-        HttpEntity entity = response.getEntity();
-        if (entity == null) {
-            throw new ClientProtocolException("Missing content");
-        }
-        JsonReader reader = new JsonReader(new InputStreamReader(entity.getContent()));
-        try {
-            T result = readResponse(reader);
-            reader.close();
-
-            if (result == null) {
-                throw new ClientProtocolException("Missing result");
-            }
-
-            return result;
-        } catch (IllegalStateException e) {
-            throw new ResponseFormatException(e);
-        } catch (IllegalArgumentException e) {
-            throw new ResponseFormatException(e);
-        }
-    }
-
-    public abstract T readResponse(JsonReader reader)
-            throws IOException, ResponseFormatException;
-
-    public static class ResponseFormatException extends ClientProtocolException {
-        public ResponseFormatException(RuntimeException readerException) {
-            super(readerException);
-        }
-
-        public ResponseFormatException() {}
-    }
-}
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/apiary/OAuthClient.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/apiary/OAuthClient.java
deleted file mode 100644
index 7ddb381..0000000
--- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/apiary/OAuthClient.java
+++ /dev/null
@@ -1,102 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge.apiary;
-
-import android.util.JsonReader;
-
-import org.apache.http.client.HttpClient;
-import org.apache.http.client.methods.HttpPost;
-import org.apache.http.entity.StringEntity;
-
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.net.URLEncoder;
-
-/**
- * Google authentication client. Fetches a pair of refresh/access tokens for a
- * secret received while registering the instance in GCD.
- */
-public class OAuthClient {
-    public static final String API_BASE = "https://accounts.google.com/o/oauth2";
-    public static final String ENCODING = "UTF-8";
-    public static final String CONTENT_TYPE = "application/x-www-form-urlencoded";
-
-    private final HttpClient mHttpClient;
-    private final String mScope;
-    private final String mClientId;
-    private final String mClientSecret;
-
-    OAuthClient(HttpClient httpClient, String scope, String clientId, String clientSecret) {
-        assert httpClient != null;
-        assert scope != null;
-        assert clientId != null;
-        assert clientSecret != null;
-
-        mHttpClient = httpClient;
-        mScope = scope;
-        mClientId = clientId;
-        mClientSecret = clientSecret;
-    }
-
-    public OAuthResult authenticate(String secret) throws IOException {
-        final long startTimeMs = System.currentTimeMillis();
-
-        String content =
-                "client_id=" + urlEncode(mClientId)
-                + "&client_secret=" + urlEncode(mClientSecret)
-                + "&scope=" + urlEncode(mScope)
-                + "&code=" + urlEncode(secret)
-                + "&redirect_uri=oob"
-                + "&grant_type=authorization_code";
-
-        return mHttpClient.execute(
-                newHttpPost("/token", content),
-                new JsonResponseHandler<OAuthResult>() {
-                    @Override
-                    public OAuthResult readResponse(JsonReader reader) throws IOException {
-                        return readResponse(reader, startTimeMs);
-                    }
-                });
-    }
-
-    private HttpPost newHttpPost(String path, String content) throws UnsupportedEncodingException {
-        HttpPost request = new HttpPost(API_BASE + "/token");
-        request.setEntity(new StringEntity(content, ENCODING));
-        request.addHeader("Content-Type", CONTENT_TYPE);
-        return request;
-    }
-
-    private static String urlEncode(String value) {
-        try {
-            return URLEncoder.encode(value, ENCODING);
-        } catch (UnsupportedEncodingException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    static OAuthResult readResponse(JsonReader reader, long startTimeMs) throws IOException {
-        String refreshToken = null;
-        String accessToken = null;
-        long expiresInS = 0; // In seconds.
-
-        reader.beginObject();
-        while (reader.hasNext()) {
-            String name = reader.nextName();
-            if (name.equals("refresh_token")) {
-                refreshToken = reader.nextString();
-            } else if (name.equals("access_token")) {
-                accessToken = reader.nextString();
-            } else if (name.equals("expires_in")) {
-                expiresInS = reader.nextLong();
-            } else {
-                reader.skipValue();
-            }
-        }
-        reader.endObject();
-
-        return OAuthResult.create(
-                refreshToken, accessToken, startTimeMs + expiresInS * 1000);
-    }
-}
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/apiary/OAuthResult.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/apiary/OAuthResult.java
deleted file mode 100644
index 3c9c5ac..0000000
--- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/apiary/OAuthResult.java
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge.apiary;
-
-/**
- * Pair of refresh/access tokens fetched with OAuthClient.
- */
-public class OAuthResult {
-    public String refreshToken;
-    public String accessToken;
-    public final long expirationTimeMs; // In milliseconds.
-
-    private OAuthResult(String refreshToken, String accessToken, long expirationTimeMs) {
-        assert refreshToken != null;
-
-        this.refreshToken = refreshToken;
-        this.accessToken = accessToken;
-        this.expirationTimeMs = expirationTimeMs;
-    }
-
-    public static OAuthResult create(
-            String refreshToken, String accessToken, long expirationTimeMs) {
-        return refreshToken != null
-                ? new OAuthResult(refreshToken, accessToken, expirationTimeMs) : null;
-    }
-}
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/commands/Command.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/commands/Command.java
deleted file mode 100644
index d71eacf..0000000
--- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/commands/Command.java
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge.commands;
-
-import java.util.Map;
-
-/**
- * Base class for a command. Command is an abstracton over GCD's command. Command
- * has state, in- and out-parameters. Both parameters are encoded as a hash of strings.
- */
-public abstract class Command {
-    public final Type type;
-    public final String id;
-
-    private State mState = State.INITIAL;
-    private String mErrorMessage;
-
-    public enum State {
-        INITIAL, DONE, ERROR
-    }
-
-    public enum Type {
-        START_SESSION(Commands.StartSessionCommand.DEFINITION),
-        ICE_EXCHANGE(Commands.IceExchangeCommand.DEFINITION),
-        RENEGOTIATE(Commands.RenegotiateCommand.DEFINITION);
-
-        public final CommandDefinition definition;
-
-        Type(CommandDefinition definition) {
-            this.definition = definition;
-        }
-    }
-
-    /**
-     * Provides access to parameters values with the Visitor pattern.
-     */
-    public interface ParamVisitor {
-        void visit(ParamDefinition<?> param, String value);
-    }
-
-    protected Command(Type type, String id) {
-        assert type != null;
-
-        this.type = type;
-        this.id = id;
-    }
-
-    public State state() {
-        return mState;
-    }
-
-    public abstract void visitInParams(ParamVisitor visitor);
-
-    public abstract void visitOutParams(ParamVisitor visitor);
-
-    protected abstract void setOutParams(Map<String, String> actualOutParams)
-            throws CommandFormatException;
-
-    protected final void setDone() {
-        assert mState == State.INITIAL;
-
-        mState = State.DONE;
-    }
-
-    public void setSuccess(Map<String, String> actualOutParams) throws CommandFormatException {
-        setOutParams(actualOutParams);
-        setDone();
-    }
-
-    public void setFailure(String errorMessage) {
-        assert mState == State.INITIAL;
-
-        mState = State.ERROR;
-        mErrorMessage = errorMessage;
-    }
-
-    public String getErrorMessage() {
-        assert mState == State.ERROR;
-
-        return mErrorMessage;
-    }
-}
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/commands/CommandDefinition.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/commands/CommandDefinition.java
deleted file mode 100644
index b7ddaf0..0000000
--- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/commands/CommandDefinition.java
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge.commands;
-
-import java.util.List;
-import java.util.Map;
-
-/**
- * Definition for a Command and a command factory. Definition needed when
- * registering in GCD. GCD only interested in in-parameters so to CommandDefinition.
- */
-public abstract class CommandDefinition {
-    private final String mName;
-    private final List<ParamDefinition<?>> mInParams;
-
-    public CommandDefinition(String name, List<ParamDefinition<?>> inParams) {
-        mName = name;
-        mInParams = inParams;
-    }
-
-    public Iterable<ParamDefinition<?>> inParams() {
-        return mInParams;
-    }
-
-    public String shortName() {
-        return "_" + mName;
-    }
-
-    public String fullName() {
-        return "base._" + mName;
-    }
-
-    /**
-     * Factory method for creaiting a command from serialized state.
-     */
-    public abstract Command newCommand(String id, Map<String, String> actualParameters)
-            throws CommandFormatException;
-}
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/commands/CommandFormatException.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/commands/CommandFormatException.java
deleted file mode 100644
index 5054a3ad..0000000
--- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/commands/CommandFormatException.java
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge.commands;
-
-/**
- * This exception throws then a Command object cannot be reconstructed from serialized state.
- */
-public class CommandFormatException extends Exception {
-    public CommandFormatException(String message) {
-        super(message);
-    }
-
-    public CommandFormatException(String message, Exception cause) {
-        super(message, cause);
-    }
-}
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/commands/CommandReceiver.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/commands/CommandReceiver.java
deleted file mode 100644
index 96672c7d..0000000
--- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/commands/CommandReceiver.java
+++ /dev/null
@@ -1,97 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge.commands;
-
-import org.chromium.components.devtools_bridge.SessionBase;
-import org.chromium.components.devtools_bridge.SignalingReceiver;
-
-import java.util.List;
-
-/**
- * Converts commands to SignalingReceiver's calls.
- */
-public class CommandReceiver {
-    private final SignalingReceiver mBase;
-
-    public CommandReceiver(SignalingReceiver base) {
-        mBase = base;
-    }
-
-    public void receive(Command command, Runnable completionHandler) {
-        switch (command.type) {
-            case START_SESSION:
-                onCommand((Commands.StartSessionCommand) command, completionHandler);
-                break;
-
-            case RENEGOTIATE:
-                onCommand((Commands.RenegotiateCommand) command, completionHandler);
-                break;
-
-            case ICE_EXCHANGE:
-                onCommand((Commands.IceExchangeCommand) command, completionHandler);
-                break;
-
-            default:
-                assert false;
-        }
-    }
-
-    private void onCommand(
-            final Commands.StartSessionCommand command, final Runnable completionHandler) {
-        mBase.startSession(
-                command.sessionId, command.config, command.offer,
-                new SessionBase.NegotiationCallback() {
-                    @Override
-                    public void onSuccess(String answer) {
-                        command.setResult(answer);
-                        completionHandler.run();
-                    }
-
-                    @Override
-                    public void onFailure(String errorMessage) {
-                        command.setFailure(errorMessage);
-                        completionHandler.run();
-                    }
-                });
-    }
-
-    private void onCommand(
-            final Commands.RenegotiateCommand command, final Runnable completionHandler) {
-        mBase.renegotiate(
-                command.sessionId, command.offer,
-                new SessionBase.NegotiationCallback() {
-                    @Override
-                    public void onSuccess(String answer) {
-                        command.setResult(answer);
-                        completionHandler.run();
-                    }
-
-                    @Override
-                    public void onFailure(String errorMessage) {
-                        command.setFailure(errorMessage);
-                        completionHandler.run();
-                    }
-                });
-    }
-
-    private void onCommand(
-            final Commands.IceExchangeCommand command, final Runnable completionHandler) {
-        mBase.iceExchange(
-                command.sessionId, command.clientCandidates,
-                new SessionBase.IceExchangeCallback() {
-                    @Override
-                    public void onSuccess(List<String> serverCandidates) {
-                        command.setResult(serverCandidates);
-                        completionHandler.run();
-                    }
-
-                    @Override
-                    public void onFailure(String errorMessage) {
-                        command.setFailure(errorMessage);
-                        completionHandler.run();
-                    }
-                });
-    }
-}
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/commands/Commands.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/commands/Commands.java
deleted file mode 100644
index 2157078..0000000
--- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/commands/Commands.java
+++ /dev/null
@@ -1,196 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge.commands;
-
-import org.chromium.components.devtools_bridge.RTCConfiguration;
-
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Implementation of all commands.
- */
-final class Commands {
-    public static final String NO_ID = null;
-
-    // In params.
-    private static final ParamDefinition<String> PARAM_SESSION_ID =
-            ParamDefinitions.newStringParam("sessionId");
-    private static final ParamDefinition<RTCConfiguration> PARAM_CONFIG =
-            ParamDefinitions.newConfigParam("config");
-    private static final ParamDefinition<String> PARAM_OFFER =
-            ParamDefinitions.newStringParam("offer");
-    private static final ParamDefinition<List<String>> PARAM_CLIENT_CANDIDATES =
-            ParamDefinitions.newStringListParam("clientCandidates");
-
-    // Out params.
-    private static final ParamDefinition<String> PARAM_ANSWER =
-            ParamDefinitions.newStringParam("answer");
-    private static final ParamDefinition<List<String>> PARAM_SERVER_CANDIDATES =
-            ParamDefinitions.newStringListParam("serverCandidates");
-
-    /**
-     * Common base class for signaling commands. All commands needed so far have a session ID
-     * and a single out parameter (result).
-     */
-    abstract static class SignalingCommandBase<R> extends Command {
-        public final String sessionId;
-        public R mResult;
-
-        protected SignalingCommandBase(Type type, String id, String sessionId) {
-            super(type, id);
-            this.sessionId = sessionId;
-        }
-
-        @Override
-        public void visitInParams(ParamVisitor visitor) {
-            PARAM_SESSION_ID.pass(visitor, sessionId);
-        }
-
-        @Override
-        public final void visitOutParams(ParamVisitor visitor) {
-            resultDefinition().pass(visitor, mResult);
-        }
-
-        @Override
-        protected void setOutParams(Map<String, String> actualOutParams)
-                throws CommandFormatException {
-            mResult = resultDefinition().checkAndGet(actualOutParams);
-        }
-
-        public final void setResult(R result) {
-            mResult = result;
-            setDone();
-        }
-
-        public final R getResult() {
-            assert state() == State.DONE;
-            return mResult;
-        }
-
-        protected abstract ParamDefinition<R> resultDefinition();
-    }
-
-    static final class StartSessionCommand extends SignalingCommandBase<String> {
-        public final RTCConfiguration config;
-        public final String offer;
-
-        public static final CommandDefinition DEFINITION = new CommandDefinition(
-                "startSession", params(PARAM_SESSION_ID, PARAM_CONFIG, PARAM_OFFER)) {
-            @Override
-            public Command newCommand(String id, Map<String, String> actualParameters)
-                    throws CommandFormatException {
-                return new StartSessionCommand(
-                        id,
-                        PARAM_SESSION_ID.get(actualParameters),
-                        PARAM_CONFIG.get(actualParameters),
-                        PARAM_OFFER.get(actualParameters));
-            }
-        };
-
-        private StartSessionCommand(
-                String id, String sessionId, RTCConfiguration config, String offer) {
-            super(Type.START_SESSION, id, sessionId);
-            this.config = config;
-            this.offer = offer;
-        }
-
-        public StartSessionCommand(String sessionId, RTCConfiguration config, String offer) {
-            this(NO_ID, sessionId, config, offer);
-        }
-
-        @Override
-        public void visitInParams(ParamVisitor visitor) {
-            super.visitInParams(visitor);
-            PARAM_CONFIG.pass(visitor, config);
-            PARAM_OFFER.pass(visitor, offer);
-        }
-
-        @Override
-        protected ParamDefinition<String> resultDefinition() {
-            return PARAM_ANSWER;
-        }
-    }
-
-    static final class IceExchangeCommand extends SignalingCommandBase<List<String>> {
-        private static final String SERVER_CANDIDATES = "serverCandidates";
-
-        public final List<String> clientCandidates;
-
-        public static final CommandDefinition DEFINITION = new CommandDefinition(
-                "iceExchange", params(PARAM_SESSION_ID, PARAM_CLIENT_CANDIDATES)) {
-            @Override
-            public Command newCommand(String id, Map<String, String> actualParameters)
-                    throws CommandFormatException {
-                return new IceExchangeCommand(
-                        id,
-                        PARAM_SESSION_ID.get(actualParameters),
-                        PARAM_CLIENT_CANDIDATES.get(actualParameters));
-            }
-        };
-
-        private IceExchangeCommand(String id, String sessionId, List<String> clientCandidates) {
-            super(Type.ICE_EXCHANGE, id, sessionId);
-            this.clientCandidates = clientCandidates;
-        }
-
-        public IceExchangeCommand(String sessionId, List<String> clientCandidates) {
-            this(NO_ID, sessionId, clientCandidates);
-        }
-
-        @Override
-        public void visitInParams(ParamVisitor visitor) {
-            super.visitInParams(visitor);
-            PARAM_CLIENT_CANDIDATES.pass(visitor, clientCandidates);
-        }
-
-        @Override
-        protected ParamDefinition<List<String>> resultDefinition() {
-            return PARAM_SERVER_CANDIDATES;
-        }
-    }
-
-    static final class RenegotiateCommand extends SignalingCommandBase<String> {
-        public final String offer;
-
-        public static final CommandDefinition DEFINITION = new CommandDefinition(
-                "renegotiate", params(PARAM_SESSION_ID, PARAM_OFFER)) {
-            @Override
-            public Command newCommand(String id, Map<String, String> actualParameters)
-                    throws CommandFormatException {
-                return new RenegotiateCommand(
-                        id,
-                        PARAM_SESSION_ID.get(actualParameters),
-                        PARAM_OFFER.get(actualParameters));
-            }
-        };
-
-        private RenegotiateCommand(String id, String sessionId, String offer) {
-            super(Type.RENEGOTIATE, id, sessionId);
-            this.offer = offer;
-        }
-
-        public RenegotiateCommand(String sessionId, String offer) {
-            this(NO_ID, sessionId, offer);
-        }
-
-        @Override
-        public void visitInParams(ParamVisitor visitor) {
-            super.visitInParams(visitor);
-            PARAM_OFFER.pass(visitor, offer);
-        }
-
-        @Override
-        protected ParamDefinition<String> resultDefinition() {
-            return PARAM_ANSWER;
-        }
-    }
-
-    private static List<ParamDefinition<?>> params(ParamDefinition<?>... values) {
-        return Collections.unmodifiableList(Arrays.asList(values));
-    }
-}
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/commands/ParamDefinition.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/commands/ParamDefinition.java
deleted file mode 100644
index 07fd314..0000000
--- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/commands/ParamDefinition.java
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge.commands;
-
-import java.util.Map;
-
-/**
- * Desribes in- or out-parameter of a Command.
- * @param <T> Type of the parameter.
- */
-public abstract class ParamDefinition<T> {
-    public final String mName;
-
-    protected ParamDefinition(String name) {
-        mName = name;
-    }
-
-    public String name() {
-        return "_" + mName;
-    }
-
-    public String type() {
-        return "string";
-    }
-
-    public void checkPresents(Map<String, String> actualParameters) throws CommandFormatException {
-        if (!actualParameters.containsKey(name())) {
-            throw new CommandFormatException("Missing parameter " + mName);
-        }
-    }
-
-    public T get(Map<String, String> actualParameters) throws CommandFormatException {
-        return fromString(actualParameters.get(name()));
-    }
-
-    public T checkAndGet(Map<String, String> actualParameters) throws CommandFormatException {
-        checkPresents(actualParameters);
-        return get(actualParameters);
-    }
-
-    public final void pass(Command.ParamVisitor visitor, T value) {
-        visitor.visit(this, toString(value));
-    }
-
-    protected abstract T fromString(String value) throws CommandFormatException;
-    protected abstract String toString(T value);
-}
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/commands/ParamDefinitions.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/commands/ParamDefinitions.java
deleted file mode 100644
index c2b0446..0000000
--- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/commands/ParamDefinitions.java
+++ /dev/null
@@ -1,203 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge.commands;
-
-import android.util.JsonReader;
-import android.util.JsonWriter;
-
-import org.chromium.components.devtools_bridge.RTCConfiguration;
-
-import java.io.IOException;
-import java.io.StringReader;
-import java.io.StringWriter;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Hepler class with a collection of parameter definitions.
- */
-final class ParamDefinitions {
-    public static ParamDefinition<String> newStringParam(String name) {
-        return new ParamDefinition<String>(name) {
-            @Override
-            protected String fromString(String value) {
-                return value;
-            }
-
-            @Override
-            protected String toString(String value) {
-                return value;
-            }
-        };
-    }
-
-    public static ParamDefinition<List<String>> newStringListParam(String name) {
-        return new ParamDefinition<List<String>>(name) {
-            @Override
-            protected List<String> fromString(String value) throws CommandFormatException {
-                try {
-                    return new ParamReader(value)
-                            .readStringList()
-                            .close()
-                            .stringListResult;
-                } catch (Exception e) {
-                    throw newException(this, "Expected JSON-serialized string list", e);
-                }
-            }
-
-            @Override
-            protected String toString(List<String> value) {
-                try {
-                    return new ParamWriter().write(value).close().toString();
-                } catch (IOException e) {
-                    throw new RuntimeException(e);
-                }
-            }
-        };
-    }
-
-    public static ParamDefinition<RTCConfiguration> newConfigParam(String name) {
-        return new ParamDefinition<RTCConfiguration>(name) {
-            @Override
-            protected RTCConfiguration fromString(String value) throws CommandFormatException {
-                try {
-                    return new ParamReader(value)
-                        .readConfig()
-                        .close()
-                        .configResult;
-                } catch (Exception e) {
-                    throw newException(this, "Expected WebRTC configuration", e);
-                }
-            }
-
-            @Override
-            protected String toString(RTCConfiguration value) {
-                try {
-                    return new ParamWriter().write(value).close().toString();
-                } catch (IOException e) {
-                    throw new RuntimeException(e);
-                }
-            }
-        };
-    }
-
-    private static CommandFormatException newException(
-            ParamDefinition<?> param, String message, Exception cause) {
-        return new CommandFormatException(
-            "Exception in parameter " + param.name() + ": " + message, cause);
-    }
-
-    private static class ParamReader {
-        private final JsonReader mReader;
-
-        public List<String> stringListResult;
-        public RTCConfiguration configResult;
-
-        public ParamReader(String source) {
-            mReader = new JsonReader(new StringReader(source));
-        }
-
-        public ParamReader readStringList() throws IOException {
-            stringListResult = new ArrayList<String>();
-            mReader.beginArray();
-            while (mReader.hasNext()) {
-                stringListResult.add(mReader.nextString());
-            }
-            mReader.endArray();
-            return this;
-        }
-
-        public ParamReader readConfig() throws IOException {
-            RTCConfiguration.Builder builder = new RTCConfiguration.Builder();
-            mReader.beginObject();
-            while (mReader.hasNext()) {
-                String name = mReader.nextName();
-                if ("iceServers".equals(name)) {
-                    readIceServerList(builder);
-                } else {
-                    mReader.skipValue();
-                }
-            }
-            configResult = builder.build();
-            return this;
-        }
-
-        public ParamReader close() throws IOException {
-            mReader.close();
-            return this;
-        }
-
-        private void readIceServerList(RTCConfiguration.Builder builder) throws IOException {
-            mReader.beginArray();
-            while (mReader.hasNext()) {
-                readIceServer(builder);
-            }
-            mReader.endArray();
-        }
-
-        private void readIceServer(RTCConfiguration.Builder builder) throws IOException {
-            String uri = null;
-            String username = "";
-            String credential = "";
-            mReader.beginObject();
-            while (mReader.hasNext()) {
-                String name = mReader.nextName();
-                if ("uri".equals(name)) {
-                    uri = mReader.nextString();
-                } else if ("username".equals(name)) {
-                    username = mReader.nextString();
-                } else if ("credential".equals(name)) {
-                    credential = mReader.nextString();
-                } else {
-                    mReader.skipValue();
-                }
-            }
-            mReader.endObject();
-            if (uri != null) {
-                builder.addIceServer(uri, username, credential);
-            }
-        }
-    }
-
-    private static class ParamWriter {
-        private final StringWriter mStringWriter = new StringWriter();
-        private final JsonWriter mWriter = new JsonWriter(mStringWriter);
-
-        public ParamWriter write(List<String> value) throws IOException {
-            mWriter.beginArray();
-            for (String item : value) {
-                mWriter.value(item);
-            }
-            mWriter.endArray();
-            return this;
-        }
-
-        public ParamWriter write(RTCConfiguration config) throws IOException {
-            mWriter.beginObject();
-            mWriter.name("iceServers");
-            mWriter.beginArray();
-            for (RTCConfiguration.IceServer server : config.iceServers) {
-                mWriter.beginObject();
-                mWriter.name("uri").value(server.uri);
-                mWriter.name("username").value(server.username);
-                mWriter.name("credential").value(server.credential);
-                mWriter.endObject();
-            }
-            mWriter.endArray();
-            mWriter.endObject();
-            return this;
-        }
-
-        public ParamWriter close() throws IOException {
-            mWriter.close();
-            return this;
-        }
-
-        @Override
-        public String toString() {
-            return mStringWriter.toString();
-        }
-    }
-}
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/gcd/InstanceCredential.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/gcd/InstanceCredential.java
deleted file mode 100644
index 7edb8077..0000000
--- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/gcd/InstanceCredential.java
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge.gcd;
-
-import android.content.SharedPreferences;
-
-/**
- * Information provided by GCD when instance has registered. Instance id
- * can be used for:
- * 1. Making sure incoming messages are addressed to the instance.
- * 2. It needed when sending command results to GCD.
- * 3. For device unregistration.
- *
- * The Secret supposed to be used to authenticate the instance with OAuthClient
- * (it has no user credentials).
- */
-public final class InstanceCredential {
-    public static final String PREF_ID = "gcd.ID";
-    public static final String PREF_SECRET = "gcd.SECRET";
-
-    public final String id;
-    public final String secret;
-
-    public InstanceCredential(String id, String secret) {
-        assert id != null;
-        assert secret != null;
-
-        this.id = id;
-        this.secret = secret;
-    }
-
-    public static InstanceCredential get(SharedPreferences preferences) {
-        String id = preferences.getString(PREF_ID, null);
-        String secret = preferences.getString(PREF_SECRET, null);
-        return id != null && secret != null ? new InstanceCredential(id, secret) : null;
-    }
-
-    public void put(SharedPreferences.Editor editor) {
-        editor.putString(PREF_ID, id);
-        editor.putString(PREF_SECRET, secret);
-    }
-
-    public static void remove(SharedPreferences.Editor editor) {
-        editor.remove(PREF_ID);
-        editor.remove(PREF_SECRET);
-    }
-}
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/gcd/InstanceDescription.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/gcd/InstanceDescription.java
deleted file mode 100644
index 6d740bb7..0000000
--- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/gcd/InstanceDescription.java
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge.gcd;
-
-/**
- * Information needed for registration in GCD.
- * Instance secret will be bound to oAuthClientId.
- * gcmChannelId will be used for delivering commands.
- * displayName is a human readable name on the client side.
- */
-public final class InstanceDescription {
-    public final String oAuthClientId;
-    public final String gcmChannelId;
-    public final String displayName;
-
-    private InstanceDescription(String oAuthClientId, String gcmChannelId, String displayName) {
-        assert oAuthClientId != null;
-        assert gcmChannelId != null;
-        assert displayName != null;
-
-        this.oAuthClientId = oAuthClientId;
-        this.gcmChannelId = gcmChannelId;
-        this.displayName = displayName;
-    }
-
-    /**
-     * Builder for InstanceDescription.
-     */
-    public static final class Builder {
-        private String mOAuthClientId;
-        private String mGCMChannelId;
-        private String mDisplayName;
-
-        public Builder setOAuthClientId(String value) {
-            mOAuthClientId = value;
-            return this;
-        }
-
-        public Builder setGCMChannelId(String value) {
-            mGCMChannelId = value;
-            return this;
-        }
-
-        public Builder setDisplayName(String value) {
-            mDisplayName = value;
-            return this;
-        }
-
-        public InstanceDescription build() {
-            return new InstanceDescription(mOAuthClientId, mGCMChannelId, mDisplayName);
-        }
-    }
-}
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/gcd/MessageReader.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/gcd/MessageReader.java
deleted file mode 100644
index 87c61f6d..0000000
--- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/gcd/MessageReader.java
+++ /dev/null
@@ -1,181 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge.gcd;
-
-import android.util.JsonReader;
-
-import org.chromium.components.devtools_bridge.commands.Command;
-import org.chromium.components.devtools_bridge.commands.CommandFormatException;
-
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Helper class for parsing JSON-encoded GCD messages (HTTP responses and GCM notifications) used
- * in the DevTools bridge.
- */
-public final class MessageReader {
-    private final JsonReader mReader;
-
-    public MessageReader(JsonReader reader) {
-        mReader = reader;
-    }
-
-    /**
-     * Reads id from a registration ticket.
-     */
-    public String readTicketId() throws IOException {
-        return new TicketReader().readId();
-    }
-
-    /**
-     * Reads credentials from finalized registration ticket.
-     */
-    public InstanceCredential readInstanceCredential() throws IOException {
-        return new TicketReader().readCredential();
-    }
-
-    Notification readNotification() throws IOException, CommandFormatException {
-        return new NotificationReader().read();
-    }
-
-    private abstract class ObjectReader {
-        public final void readObject() throws IOException {
-            mReader.beginObject();
-            while (mReader.hasNext()) {
-                readItem(mReader.nextName());
-            }
-            mReader.endObject();
-        }
-
-        protected void readItem(String name) throws IOException {
-            mReader.skipValue();
-        }
-    }
-
-    private class TicketReader extends ObjectReader {
-        private String mId;
-        private String mDeviceId;
-        private String mDeviceSecret;
-
-        public String readId() throws IOException {
-            readObject();
-            if (mId == null) {
-                throw new IllegalArgumentException();
-            }
-            return mId;
-        }
-
-        public InstanceCredential readCredential() throws IOException {
-            readObject();
-            if (mDeviceId == null || mDeviceSecret == null) {
-                throw new IllegalArgumentException();
-            }
-            return new InstanceCredential(mDeviceId, mDeviceSecret);
-        }
-
-        @Override
-        protected void readItem(String name) throws IOException {
-            if (name.equals("id")) {
-                mId = mReader.nextString();
-            } else if (name.equals("deviceId")) {
-                mDeviceId = mReader.nextString();
-            } else if (name.equals("robotAccountAuthorizationCode")) {
-                mDeviceSecret = mReader.nextString();
-            } else {
-                super.readItem(name);
-            }
-        }
-    }
-
-    private class NotificationReader extends ObjectReader {
-        private String mDeviceId;
-        private String mType;
-        private String mCommandId;
-        private CommandReader mCommandReader;
-
-        public Notification read() throws IOException, CommandFormatException {
-            readObject();
-            if (mDeviceId == null || mType == null) return null;
-            if (mType.equals("COMMAND_CREATED")) {
-                if (mCommandReader == null) {
-                    throw new CommandFormatException("Command missing");
-                }
-                if (mCommandId == null) {
-                    throw new CommandFormatException("Command id missing");
-                }
-                return new Notification(
-                        mDeviceId, Notification.Type.COMMAND_CREATED,
-                        mCommandReader.newCommand(mCommandId));
-            } else if (mType.equals("DEVICE_DELETED")) {
-                return new Notification(mDeviceId, Notification.Type.INSTANCE_UNREGISTERED, null);
-            } else {
-                return null;
-            }
-        }
-
-        @Override
-        protected void readItem(String name) throws IOException {
-            if (name.equals("deviceId")) {
-                mDeviceId = mReader.nextString();
-            } else if (name.equals("type")) {
-                mType = mReader.nextString();
-            } else if (name.equals("commandId")) {
-                mCommandId = mReader.nextString();
-            } else if (name.equals("command")) {
-                mCommandReader = new CommandReader();
-                mCommandReader.readObject();
-            } else {
-                super.readItem(name);
-            }
-        }
-    }
-
-    private class CommandReader extends ObjectReader {
-        private String mType;
-        private Map<String, String> mParameters;
-
-        public Command newCommand(String id) throws CommandFormatException {
-            if (mType == null) {
-                throw new CommandFormatException("Missing command type");
-            }
-            if (mParameters == null) {
-                throw new CommandFormatException("Missing parameters");
-            }
-            return convertType(mType).definition.newCommand(id, mParameters);
-        }
-
-        @Override
-        protected void readItem(String name) throws IOException {
-            if (name.equals("name")) {
-                mType = mReader.nextString();
-            } else if (name.equals("parameters")) {
-                mParameters = readStringMap(mReader);
-            } else {
-                super.readItem(name);
-            }
-        }
-
-        private Command.Type convertType(String name) throws CommandFormatException {
-            for (Command.Type type : Command.Type.values()) {
-                if (type.definition.fullName().equals(name)) return type;
-            }
-            throw new CommandFormatException("Invalid type: " + name);
-        }
-    }
-
-    static Map<String, String> readStringMap(JsonReader reader) throws IOException {
-        Map<String, String> result = new HashMap<String, String>();
-        reader.beginObject();
-        while (reader.hasNext()) {
-            String name = reader.nextName();
-            String value = reader.nextString();
-            result.put(name, value);
-        }
-        reader.endObject();
-        return result;
-    }
-}
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/gcd/MessageWriter.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/gcd/MessageWriter.java
deleted file mode 100644
index 2d7388f..0000000
--- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/gcd/MessageWriter.java
+++ /dev/null
@@ -1,156 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge.gcd;
-
-import android.util.JsonWriter;
-
-import org.chromium.components.devtools_bridge.commands.Command;
-import org.chromium.components.devtools_bridge.commands.ParamDefinition;
-
-import java.io.IOException;
-import java.io.StringWriter;
-
-/**
- * Helper class for constructing GCD JSON messages (HTTP requests) used in the DevTools bridge.
- */
-public final class MessageWriter {
-    private final StringWriter mStringWriter;
-    private final JsonWriter mWriter;
-    boolean mClosed = false;
-
-    public MessageWriter() {
-        mStringWriter = new StringWriter();
-        mWriter = new JsonWriter(mStringWriter);
-    }
-
-    public MessageWriter close() throws IOException {
-        assert !mClosed;
-        mWriter.close();
-        mClosed = true;
-        return this;
-    }
-
-    @Override
-    public String toString() {
-        assert mClosed;
-        return mStringWriter.toString();
-    }
-
-    /**
-     * Writes body of registrationTicket PATCH request.
-     */
-    public MessageWriter writeTicketPatch(InstanceDescription description) throws IOException {
-        mWriter.beginObject();
-        mWriter.name("deviceDraft");
-        writeDeviceDraft(description);
-        mWriter.name("oauthClientId").value(description.oAuthClientId);
-        mWriter.endObject();
-        return this;
-    }
-
-    /**
-     * Writes body of devices/<instanceId> PATCH request.
-     */
-    public MessageWriter writeDeviceGCMChannelPatch(String gcmChannelId) throws IOException {
-        mWriter.beginObject();
-        mWriter.name("channel");
-        mWriter.beginObject();
-        mWriter.name("gcmRegistrationId").value(gcmChannelId);
-        mWriter.endObject();
-        mWriter.endObject();
-        return this;
-    }
-
-    private void writeDeviceDraft(InstanceDescription description) throws IOException {
-        mWriter.beginObject();
-        mWriter.name("deviceKind").value("vendor");
-        mWriter.name("displayName").value(description.displayName);
-        mWriter.name("systemName").value("Chrome DevTools Bridge");
-        mWriter.name("channel");
-        writeChannelDefinition(description);
-        mWriter.name("commandDefs");
-        writeCommandsDefinition();
-        mWriter.endObject();
-    }
-
-    private void writeChannelDefinition(InstanceDescription description) throws IOException {
-        mWriter.beginObject();
-        mWriter.name("supportedType").value("gcm");
-        mWriter.name("gcmRegistrationId").value(description.gcmChannelId);
-        mWriter.endObject();
-    }
-
-    private void writeCommandsDefinition() throws IOException {
-        mWriter.beginObject();
-        mWriter.name("base");
-        writeCommandsDefinitionBase();
-        mWriter.endObject();
-    }
-
-    private void writeCommandsDefinitionBase() throws IOException {
-        mWriter.beginObject();
-        for (Command.Type type : Command.Type.values()) {
-            mWriter.name(type.definition.shortName());
-            beginParameters();
-            for (ParamDefinition<?> param : type.definition.inParams()) {
-                writeParameter(param.name(), param.type());
-            }
-            endParameters();
-        }
-        mWriter.endObject();
-    }
-
-    private void beginParameters() throws IOException {
-        mWriter.beginObject();
-        mWriter.name("parameters");
-        mWriter.beginObject();
-    }
-
-    private void endParameters() throws IOException {
-        mWriter.endObject();
-        mWriter.endObject();
-    }
-
-    private void writeParameter(String name, String type) throws IOException {
-        mWriter.name(name);
-        mWriter.beginObject();
-        mWriter.name("type").value(type);
-        mWriter.endObject();
-    }
-
-    /**
-     * Writes body of command PATCH request. Updates command status and out parametes
-     * when the command has processed.
-     */
-    public MessageWriter writeCommandPatch(Command command) throws IOException {
-        mWriter.beginObject();
-        if (command.state() == Command.State.DONE) {
-            mWriter.name("state").value("done");
-            mWriter.name("results");
-            mWriter.beginObject();
-            command.visitOutParams(new ParamWriter());
-            mWriter.endObject();
-        } else if (command.state() == Command.State.ERROR) {
-            mWriter.name("state").value("error");
-            mWriter.name("error");
-            mWriter.beginObject();
-            mWriter.name("message").value(command.getErrorMessage());
-            mWriter.endObject();
-        }
-        mWriter.endObject();
-        return this;
-    }
-
-    private class ParamWriter implements Command.ParamVisitor {
-        @Override
-        public void visit(ParamDefinition<?> param, String value) {
-            try {
-                mWriter.name(param.name()).value(value);
-            } catch (IOException e) {
-                throw new RuntimeException(e);
-            }
-        }
-    }
-}
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/gcd/Notification.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/gcd/Notification.java
deleted file mode 100644
index e8899f4..0000000
--- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/gcd/Notification.java
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge.gcd;
-
-import android.util.JsonReader;
-
-import org.chromium.components.devtools_bridge.commands.Command;
-import org.chromium.components.devtools_bridge.commands.CommandFormatException;
-
-import java.io.IOException;
-import java.io.StringReader;
-
-/**
- * Notification that GCD sends to an instance.
- */
-public final class Notification {
-    public final String instanceId;
-    public final Type type;
-    public final Command command;
-
-    public enum Type {
-        COMMAND_CREATED, // Command created and needs to be executed.
-        INSTANCE_UNREGISTERED // Instance unregistered (possibly through external UI).
-    }
-
-    Notification(String instanceId, Type type, Command command) {
-        this.instanceId = instanceId;
-        this.type = type;
-        this.command = command;
-    }
-
-    public static Notification read(String source) throws FormatException {
-        JsonReader reader = new JsonReader(new StringReader(source));
-        try {
-            Notification result = new MessageReader(reader).readNotification();
-            reader.close();
-            return result;
-        } catch (CommandFormatException e) {
-            throw new FormatException(e);
-        } catch (IllegalStateException e) {
-            throw new FormatException(e);
-        } catch (IllegalArgumentException e) {
-            throw new FormatException(e);
-        } catch (IOException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /**
-     * Exception when parsing notification.
-     */
-    public static class FormatException extends Exception {
-        public FormatException(RuntimeException cause) {
-            super(cause);
-        }
-
-        public FormatException(CommandFormatException cause) {
-            super(cause);
-        }
-    }
-}
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/ui/GCDRegistrationFragment.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/ui/GCDRegistrationFragment.java
deleted file mode 100644
index 09989b37..0000000
--- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/ui/GCDRegistrationFragment.java
+++ /dev/null
@@ -1,320 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge.ui;
-
-import android.accounts.Account;
-import android.accounts.AccountManager;
-import android.accounts.AccountManagerCallback;
-import android.accounts.AccountManagerFuture;
-import android.app.Activity;
-import android.app.Fragment;
-import android.app.ProgressDialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.util.Log;
-import android.widget.Toast;
-
-import org.chromium.components.devtools_bridge.DevToolsBridgeServer;
-import org.chromium.components.devtools_bridge.apiary.ApiaryClientFactory;
-import org.chromium.components.devtools_bridge.apiary.OAuthResult;
-import org.chromium.components.devtools_bridge.gcd.InstanceCredential;
-import org.chromium.components.devtools_bridge.gcd.InstanceDescription;
-
-import java.io.IOException;
-
-/**
- * Fragment that responsible for:
- * 1. Displaying GCD registration status.
- * 2. Instance registration.
- * 3. Instance unregistration.
- *
- * Fragment is abstract and does not provide UI controls. Descendant is responsible for it.
- * It also should have actionable item for registration/unregistration which invokes
- * appropriate methods.
- */
-public abstract class GCDRegistrationFragment extends Fragment
-        implements SharedPreferences.OnSharedPreferenceChangeListener {
-    private static final String TAG = "GCDRegistrationFragment";
-    private static final String PREF_OWNER_EMAIL = "ui.OWNER_EMAIL";
-    private static final String PREF_DISPLAY_NAME = "ui.OWNER_EMAIL";
-    private static final int CODE_ACCOUNT_SELECTED = 1;
-
-    private ApiaryClientFactory mClientFactory;
-    private Account mSelectedAccount = null;
-
-    private SharedPreferences mPreferences;
-
-    private InstanceCredential mInstanceCredential;
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        mClientFactory = new ApiaryClientFactory();
-        mPreferences = DevToolsBridgeServer.getPreferences(getActivity());
-        mPreferences.registerOnSharedPreferenceChangeListener(this);
-        mInstanceCredential = InstanceCredential.get(mPreferences);
-        super.onCreate(savedInstanceState);
-    }
-
-    @Override
-    public void onDestroy() {
-        super.onDestroy();
-        mPreferences.unregisterOnSharedPreferenceChangeListener(this);
-        new AsyncTask<Void, Void, Void>() {
-            @Override
-            protected final Void doInBackground(Void... args) {
-                mClientFactory.close();
-                return null;
-            }
-        }.execute();
-    }
-
-    @Override
-    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
-        if (key.equals(InstanceCredential.PREF_ID)) {
-            mInstanceCredential = InstanceCredential.get(mPreferences);
-            onRegistrationStatusChange();
-        }
-    }
-
-    public void register() {
-        AccountManager manager = AccountManager.get(getActivity());
-
-        Intent intent = manager.newChooseAccountIntent(
-                mSelectedAccount,
-                null /* allowableAccounts */,
-                new String[] { "com.google" } /* allowableAccountTypes */,
-                true /* alwaysPromptForAccount */,
-                "Registration in GCD" /* descriptionOverrideText */,
-                null /* addAccountAuthTokenType */,
-                null /* addAccountRequiredFeatures */,
-                null /* addAccountOptions */);
-        startActivityForResult(intent, CODE_ACCOUNT_SELECTED);
-    }
-
-    public void unregister() {
-        if (mInstanceCredential == null) return;
-
-        new RegistrationTask("Unregistering instance") {
-            private InstanceCredential mInstranceCredentialCopy = mInstanceCredential;
-
-            @Override
-            protected void doInBackgroundImpl() throws IOException, InterruptedException {
-                OAuthResult result = mClientFactory.newOAuthClient()
-                        .authenticate(mInstranceCredentialCopy.secret);
-
-                checkInterrupted();
-
-                Log.d(TAG, "Access token: " + result.accessToken);
-
-                mClientFactory.newGCDClient(result.accessToken)
-                        .deleteInstance(mInstranceCredentialCopy.id);
-            }
-
-            @Override
-            protected void onSuccess() {
-                saveRegistration(null, null, null);
-                onRegistrationStatusChange();
-                showToast("Unregistered");
-            }
-
-            @Override
-            protected void onFailure(Exception e) {
-                Log.e(TAG, "Unregistration failed", e);
-                showToast("Unregistration failed. See log for details.");
-            }
-        }.execute();
-    }
-
-    public boolean isRegistered() {
-        return mInstanceCredential != null;
-    }
-
-    public String getOwner() {
-        return mPreferences.getString(PREF_OWNER_EMAIL, "");
-    }
-
-    public String getDisplayName() {
-        return mPreferences.getString(PREF_DISPLAY_NAME, "");
-    }
-
-    public void queryOAuthToken() {
-        if (mSelectedAccount == null) return;
-
-        AccountManager manager = AccountManager.get(getActivity());
-
-        final String ownerEmail = mSelectedAccount.name;
-
-        manager.getAuthToken(
-                mSelectedAccount,
-                "oauth2:" + ApiaryClientFactory.OAUTH_SCOPE, null /* options */, getActivity(),
-                new AccountManagerCallback<Bundle>() {
-                    @Override
-                    public void run(AccountManagerFuture<Bundle> future) {
-                        try {
-                            String token = future.getResult().getString(
-                                    AccountManager.KEY_AUTHTOKEN);
-                            register(ownerEmail, token);
-                        } catch (Exception e) {
-                            Log.e(TAG, "Failed to get token: ", e);
-                        }
-                    }
-                }, null);
-    }
-
-    private void register(final String ownerEmail, final String oAuthToken) {
-        new RegistrationTask("Registering instance") {
-            private Context mContext;
-
-            private String mDisplayName;
-            private InstanceDescription mDescription;
-            private InstanceCredential mCredential;
-
-            @Override
-            protected void onPreExecute() {
-                mContext = getActivity();
-
-                mDisplayName = generateDisplayName();
-                super.onPreExecute();
-            }
-
-            @Override
-            protected void doInBackgroundImpl() throws IOException, InterruptedException {
-                String ticketId = mClientFactory.newGCDClient(oAuthToken)
-                        .createRegistrationTicket();
-
-                checkInterrupted();
-
-                String gcmChannelId =
-                        mClientFactory.newGCMRegistrar().blockingGetRegistrationId(mContext);
-
-                mDescription = new InstanceDescription.Builder()
-                        .setOAuthClientId(mClientFactory.getOAuthClientId())
-                        .setGCMChannelId(gcmChannelId)
-                        .setDisplayName(mDisplayName)
-                        .build();
-
-                mClientFactory.newAnonymousGCDClient().patchRegistrationTicket(
-                        ticketId, mDescription);
-
-                checkInterrupted();
-
-                mCredential = mClientFactory.newAnonymousGCDClient().finalizeRegistration(ticketId);
-            }
-
-            @Override
-            protected void onSuccess() {
-                saveRegistration(mDescription, mCredential, ownerEmail);
-                onRegistrationStatusChange();
-                showToast("Registered");
-            }
-
-            @Override
-            protected void onFailure(Exception e) {
-                Log.e(TAG, "Registration failed", e);
-                showToast("Registration failed. See log for details.");
-            }
-        }.execute();
-    }
-
-    @Override
-    public void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
-        if (requestCode == CODE_ACCOUNT_SELECTED && resultCode == Activity.RESULT_OK) {
-            mSelectedAccount = new Account(
-                    data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME),
-                    data.getStringExtra(AccountManager.KEY_ACCOUNT_TYPE));
-            Log.d(TAG, "Selected account=" + mSelectedAccount);
-            queryOAuthToken();
-        }
-    }
-
-    private void saveRegistration(
-            InstanceDescription description, InstanceCredential credential, String ownerEmail) {
-        // TODO(serya): Make registration persistant.
-        mInstanceCredential = credential;
-
-        SharedPreferences.Editor editor = mPreferences.edit();
-        if (description != null && credential != null && ownerEmail != null) {
-            credential.put(editor);
-            editor.putString(PREF_DISPLAY_NAME, description.displayName);
-            editor.putString(PREF_OWNER_EMAIL, ownerEmail);
-        } else {
-            InstanceCredential.remove(editor);
-            editor.remove(PREF_DISPLAY_NAME);
-            editor.remove(PREF_OWNER_EMAIL);
-        }
-        editor.commit();
-    }
-
-    protected abstract void onRegistrationStatusChange();
-    protected abstract String generateDisplayName();
-
-    private abstract class RegistrationTask extends AsyncTask<Void, Void, Boolean> {
-        private ProgressDialog mDialog;
-        private Exception mException;
-
-        private final String mProgressMessage;
-
-        protected RegistrationTask(String progressMessage) {
-            mProgressMessage = progressMessage;
-        }
-
-        @Override
-        protected void onPreExecute() {
-            mDialog = ProgressDialog.show(
-                    getActivity(),
-                    "GCD registration",
-                    mProgressMessage,
-                    true,
-                    false,
-                    new DialogInterface.OnCancelListener() {
-                        @Override
-                        public void onCancel(DialogInterface dialog) {
-                            cancel(true);
-                        }
-                    });
-        }
-
-        @Override
-        protected final Boolean doInBackground(Void... args) {
-            try {
-                doInBackgroundImpl();
-                return Boolean.TRUE;
-            } catch (IOException e) {
-                mException = e;
-            } catch (InterruptedException e) {
-                Thread.currentThread().interrupt();
-            }
-            return Boolean.FALSE;
-        }
-
-        protected final void checkInterrupted() throws InterruptedException {
-            if (Thread.currentThread().isInterrupted()) {
-                throw new InterruptedException();
-            }
-        }
-
-        @Override
-        protected void onPostExecute(Boolean success) {
-            mDialog.dismiss();
-            if (Boolean.TRUE.equals(success)) {
-                onSuccess();
-            } else if (mException != null) {
-                onFailure(mException);
-            }
-        }
-
-        protected void showToast(String message) {
-            Toast.makeText(getActivity(), message, Toast.LENGTH_SHORT).show();
-        }
-
-        protected abstract void doInBackgroundImpl() throws IOException, InterruptedException;
-        protected abstract void onSuccess();
-        protected abstract void onFailure(Exception e);
-    }
-}
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/util/LooperExecutor.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/util/LooperExecutor.java
deleted file mode 100644
index ce383be..0000000
--- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/util/LooperExecutor.java
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge.util;
-
-import android.content.Context;
-import android.os.Handler;
-
-import org.chromium.components.devtools_bridge.SessionBase;
-
-/**
- * Implementation of SessionBase.Executor on top of android's handler.
- */
-public class LooperExecutor implements SessionBase.Executor {
-    private final Handler mHandler;
-
-    public LooperExecutor(Handler handler) {
-        mHandler = handler;
-    }
-
-    public static LooperExecutor newInstanceForMainLooper(Context context) {
-        return new LooperExecutor(new Handler(context.getMainLooper()));
-    }
-
-    @Override
-    public SessionBase.Cancellable postOnSessionThread(int delayMs, Runnable runnable) {
-        CancellableTask task = new CancellableTask(runnable);
-        mHandler.postDelayed(task, delayMs);
-        return task;
-    }
-
-    @Override
-    public boolean isCalledOnSessionThread() {
-        return mHandler.getLooper().getThread() == Thread.currentThread();
-    }
-
-    private final class CancellableTask implements SessionBase.Cancellable, Runnable {
-        private Runnable mTask;
-
-        public CancellableTask(Runnable task) {
-            mTask = task;
-        }
-
-        @Override
-        public void run() {
-            if (mTask != null) mTask.run();
-        }
-
-        @Override
-        public void cancel() {
-            mHandler.removeCallbacks(this);
-            mTask = null;
-        }
-    }
-}
diff --git a/components/devtools_bridge/android/javatests/AndroidManifest.xml b/components/devtools_bridge/android/javatests/AndroidManifest.xml
deleted file mode 100644
index c4671eb..0000000
--- a/components/devtools_bridge/android/javatests/AndroidManifest.xml
+++ /dev/null
@@ -1,74 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-  <!-- 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. -->
-  <!-- package name must be unique so suffix with "tests" so package loader
-       doesn't ignore this. -->
-  <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-      package="org.chromium.components.devtools_bridge.tests">
-    <application
-            android:name=".TestApplication">
-        <uses-library android:name="android.test.runner" />
-        <service
-                android:name=".DebugService" >
-        </service>
-        <activity
-                android:name=".DebugActivity"
-                android:label="DevToolsBridge tests" >
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-
-        <!-- DevToolsBridgeService multiplexed GCM receiver -->
-        <service android:name="org.chromium.components.devtools_bridge.TestDevToolsBridgeService"
-                android:exported="false" />
-            <receiver android:exported="false"
-                    android:name="org.chromium.components.devtools_bridge.TestDevToolsBridgeService$Receiver">
-            <intent-filter>
-                <action android:name="com.google.ipc.invalidation.gcmmplex.EVENT" />
-            </intent-filter>
-        </receiver>
-
-        <!-- GCM Broadcast Receiver -->
-        <receiver android:exported="true"
-                  android:name="com.google.ipc.invalidation.external.client.contrib.MultiplexingGcmListener$GCMReceiver"
-                  android:permission="com.google.android.c2dm.permission.SEND">
-            <intent-filter>
-                <action android:name="com.google.android.c2dm.intent.RECEIVE"/>
-                <action android:name="com.google.android.c2dm.intent.REGISTRATION"/>
-                <category android:name="com.google.ipc.invalidation.ticl.android2"/>
-            </intent-filter>
-        </receiver>
-        <!-- GCM multiplexer -->
-        <service android:exported="false" android:name="com.google.ipc.invalidation.external.client.contrib.MultiplexingGcmListener">
-            <!-- MultiplexingGcmListener fails if |sender_ids| looks like an integer.
-                 Make it look like a string by duplicating the ID. -->
-            <meta-data android:name="sender_ids" android:value="287888336735,287888336735"/>
-        </service>
-    </application>
-    <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="22" />
-    <instrumentation android:name="android.test.InstrumentationTestRunner"
-            android:targetPackage="org.chromium.components.devtools_bridge.tests"
-            android:label="Tests for org.chromium.components.devtools_bridge"/>
-
-    <permission
-            android:name="org.chromium.components.devtools_bridge.tests.permission.C2D_MESSAGE"
-            android:protectionLevel="signature" />
-
-    <uses-permission android:name="android.permission.RUN_INSTRUMENTATION" />
-    <uses-permission android:name="android.permission.INJECT_EVENTS" />
-    <uses-permission android:name="android.permission.INTERNET" />
-    <uses-permission android:name="android.permission.USE_CREDENTIALS" />
-    <uses-permission android:name="android.permission.WAKE_LOCK" />
-    <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
-    <uses-permission
-            android:name="org.chromium.components.devtools_bridge.tests.permission.C2D_MESSAGE" />
-
-    <!-- For manual testing with Chrome Shell -->
-    <uses-permission android:name="org.chromium.chrome.shell.permission.DEBUG" />
-
-    <!-- For manual testing with Clankium -->
-    <uses-permission android:name="com.google.android.apps.chrome.permission.DEBUG" />
-</manifest>
diff --git a/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/DevToolsBridgeServerTest.java b/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/DevToolsBridgeServerTest.java
deleted file mode 100644
index 9f1910a5..0000000
--- a/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/DevToolsBridgeServerTest.java
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge;
-
-import android.content.Context;
-import android.net.LocalServerSocket;
-import android.net.LocalSocket;
-import android.test.InstrumentationTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import junit.framework.Assert;
-
-import org.chromium.components.devtools_bridge.util.LooperExecutor;
-
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.Future;
-
-/**
- * Tests for {@link DevToolsBridgeServer}
- */
-public class DevToolsBridgeServerTest extends InstrumentationTestCase {
-    private static final String REQUEST = "Request";
-    private static final String RESPONSE = "Response";
-    private static final String SESSION_ID = "SESSION_ID";
-    private static final String CLIENT_SOCKET_NAME =
-            DevToolsBridgeServerTest.class.getName() + ".CLIENT_SOCKET_NAME";
-    private static final String SERVER_SOCKET_NAME =
-            DevToolsBridgeServerTest.class.getName() + ".SERVER_SOCKET_NAME";
-    private SessionDependencyFactory mFactory;
-
-    private LooperExecutor mServerExecutor;
-    private DevToolsBridgeServer mServer;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mFactory = SessionDependencyFactory.newInstance();
-        mServer = new DevToolsBridgeServer(new ServerDelegate());
-        mServerExecutor = LooperExecutor.newInstanceForMainLooper(
-                getInstrumentation().getTargetContext());
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        final CountDownLatch done = new CountDownLatch(1);
-        mServerExecutor.postOnSessionThread(0, new Runnable() {
-            @Override
-            public void run() {
-                mServer.dispose();
-                mServer = null;
-                done.countDown();
-            }
-        });
-        done.await();
-        mFactory.dispose();
-        super.tearDown();
-    }
-
-    @SmallTest
-    public void testRequestResponse() throws Exception {
-        LocalServerSocket serverListeningSocket = new LocalServerSocket(SERVER_SOCKET_NAME);
-        ClientSessionTestingHost clientSession = new ClientSessionTestingHost(
-                mFactory, mServer, mServerExecutor, SESSION_ID, CLIENT_SOCKET_NAME);
-        clientSession.start();
-
-        Future<String> response = TestUtils.asyncRequest(CLIENT_SOCKET_NAME, REQUEST);
-        LocalSocket serverSocket = serverListeningSocket.accept();
-        String request = TestUtils.read(serverSocket, REQUEST.length());
-        Assert.assertEquals(REQUEST, request);
-        TestUtils.write(serverSocket, RESPONSE);
-        serverSocket.close();
-        Assert.assertEquals(RESPONSE, response.get());
-
-        clientSession.dispose();
-    }
-
-    private class ServerDelegate implements DevToolsBridgeServer.Delegate {
-        @Override
-        public Context getContext() {
-            return getInstrumentation().getTargetContext();
-        }
-
-        @Override
-        public void querySocketName(DevToolsBridgeServer.QuerySocketCallback callback) {
-            callback.onSuccess(SERVER_SOCKET_NAME);
-        }
-
-        @Override
-        public void onSessionCountChange(int count) {}
-    }
-}
diff --git a/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/LocalSessionBridgeTest.java b/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/LocalSessionBridgeTest.java
deleted file mode 100644
index 358702c28..0000000
--- a/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/LocalSessionBridgeTest.java
+++ /dev/null
@@ -1,114 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge;
-
-import android.net.LocalServerSocket;
-import android.net.LocalSocket;
-import android.test.InstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-
-import junit.framework.Assert;
-
-import java.util.concurrent.Future;
-
-/**
- * Tests for both client and server sessions bound with {@link LocalSessionBridge}.
- */
-public class LocalSessionBridgeTest extends InstrumentationTestCase {
-    private static final String SERVER_SOCKET_NAME =
-            LocalSessionBridgeTest.class.getName() + ".SERVER_SOCKET";
-    private static final String CLIENT_SOCKET_NAME =
-            LocalSessionBridgeTest.class.getName() + ".CLIENT_SOCKET";
-
-    private static final String REQUEST = "Request";
-    private static final String RESPONSE = "Response";
-
-    private LocalSessionBridge mBridge;
-
-    @Override
-    public void setUp() throws Exception {
-        super.setUp();
-        mBridge = new LocalSessionBridge(SERVER_SOCKET_NAME, CLIENT_SOCKET_NAME);
-    }
-
-    @Override
-    public void tearDown() throws Exception {
-        mBridge.dispose();
-        super.tearDown();
-    }
-
-    @MediumTest
-    public void testDisposeAfeterStart() {
-        mBridge.start();
-    }
-
-    @MediumTest
-    public void testNegotiating() throws InterruptedException {
-        mBridge.start();
-        mBridge.awaitNegotiated();
-    }
-
-    @MediumTest
-    public void testOpenControlChannel() throws InterruptedException {
-        mBridge.start();
-        mBridge.awaitControlChannelOpened();
-    }
-
-    @MediumTest
-    public void testClientAutocloseTimeout() throws InterruptedException {
-        mBridge.setMessageDeliveryDelayMs(1000);
-        mBridge.setClientAutoCloseTimeoutMs(100);
-        mBridge.start();
-        mBridge.awaitClientAutoClosed();
-    }
-
-    @MediumTest
-    public void testServerAutocloseTimeout() throws InterruptedException {
-        mBridge.setMessageDeliveryDelayMs(1000);
-        mBridge.setServerAutoCloseTimeoutMs(100);
-        mBridge.start();
-        mBridge.awaitServerAutoClosed();
-    }
-
-    @MediumTest
-    public void testRequestResponse() throws Exception {
-        mBridge.start();
-
-        LocalServerSocket serverListeningSocket = new LocalServerSocket(SERVER_SOCKET_NAME);
-        Future<String> response = TestUtils.asyncRequest(CLIENT_SOCKET_NAME, REQUEST);
-        LocalSocket serverSocket = serverListeningSocket.accept();
-        String request = TestUtils.read(serverSocket, REQUEST.length());
-        Assert.assertEquals(REQUEST, request);
-        TestUtils.write(serverSocket, RESPONSE);
-        serverSocket.close();
-        Assert.assertEquals(RESPONSE, response.get());
-    }
-
-    @MediumTest
-    public void testRequestFailure1() throws Exception {
-        mBridge.start();
-        LocalServerSocket serverListeningSocket = new LocalServerSocket(SERVER_SOCKET_NAME);
-        Future<String> response = TestUtils.asyncRequest(CLIENT_SOCKET_NAME, REQUEST);
-        LocalSocket socket = serverListeningSocket.accept();
-        int firstByte = socket.getInputStream().read();
-
-        Assert.assertEquals((int) REQUEST.charAt(0), firstByte);
-
-        socket.close();
-        Assert.assertEquals("", response.get());
-    }
-
-    @MediumTest
-    public void testRequestFailure2() throws Exception {
-        mBridge.dispose();
-        // Android system socket will reject connection.
-        mBridge = new LocalSessionBridge("jdwp-control", CLIENT_SOCKET_NAME);
-        mBridge.start();
-
-        Future<String> response = TestUtils.asyncRequest(CLIENT_SOCKET_NAME, REQUEST);
-
-        Assert.assertEquals("", response.get());
-    }
-}
diff --git a/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/SessionControlMessagesTest.java b/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/SessionControlMessagesTest.java
deleted file mode 100644
index a3181686..0000000
--- a/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/SessionControlMessagesTest.java
+++ /dev/null
@@ -1,94 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge;
-
-import android.test.InstrumentationTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import junit.framework.Assert;
-
-import org.chromium.components.devtools_bridge.SessionControlMessages.ClientMessage;
-import org.chromium.components.devtools_bridge.SessionControlMessages.ClientMessageHandler;
-import org.chromium.components.devtools_bridge.SessionControlMessages.IceExchangeMessage;
-import org.chromium.components.devtools_bridge.SessionControlMessages.InvalidFormatException;
-import org.chromium.components.devtools_bridge.SessionControlMessages.Message;
-import org.chromium.components.devtools_bridge.SessionControlMessages.MessageHandler;
-import org.chromium.components.devtools_bridge.SessionControlMessages.ServerMessage;
-import org.chromium.components.devtools_bridge.SessionControlMessages.ServerMessageHandler;
-import org.chromium.components.devtools_bridge.SessionControlMessages.UnknownRequestMessage;
-import org.chromium.components.devtools_bridge.SessionControlMessages.UnknownResponseMessage;
-
-/**
- * Tests for {@link SessionControlMessages}
- */
-public class SessionControlMessagesTest extends InstrumentationTestCase {
-    private static final String UNKNOWN_REQUEST_TYPE = "@unknown request@";
-    private static final String UNKNOWN_REQUEST = "{\"type\": \"" + UNKNOWN_REQUEST_TYPE + "\"}";
-
-    @SmallTest
-    public void testIceExchangeMessage() {
-        recode(new IceExchangeMessage());
-    }
-
-    @SmallTest
-    public void testUnknownRequest() throws InvalidFormatException {
-        UnknownRequestMessage request =
-                (UnknownRequestMessage) ClientMessageReader.readMessage(UNKNOWN_REQUEST);
-        UnknownResponseMessage response = ServerMessageReader.recode(request.createResponse());
-        Assert.assertEquals(UNKNOWN_REQUEST_TYPE, response.rawRequestType);
-    }
-
-    private <T extends ServerMessage> T recode(T message) {
-        assert message != null;
-        return ServerMessageReader.recode(message);
-    }
-
-    @SuppressWarnings("unchecked")
-    private static <T> T cast(T prototype, Object object) {
-        Assert.assertNotNull(object);
-        if (prototype.getClass() == object.getClass())
-            return (T) object;
-        else
-            throw new ClassCastException();
-    }
-
-    private static void checkedRead(MessageHandler handler, Message<?> message) {
-        try {
-            handler.readMessage(SessionControlMessages.toByteArray(message));
-        } catch (InvalidFormatException e) {
-            Assert.fail(e.toString());
-        }
-    }
-
-    private static class ServerMessageReader extends ServerMessageHandler {
-        private ServerMessage mLastMessage;
-
-        @Override
-        protected void onMessage(ServerMessage message) {
-            mLastMessage = message;
-        }
-
-        public static <T extends ServerMessage> T recode(T message) {
-            ServerMessageReader handler = new ServerMessageReader();
-            checkedRead(handler, message);
-            return cast(message, handler.mLastMessage);
-        }
-    }
-
-    private static class ClientMessageReader extends ClientMessageHandler {
-        private ClientMessage mLastMessage;
-
-        @Override
-        protected void onMessage(ClientMessage message) {
-            mLastMessage = message;
-        }
-
-        public static ClientMessage readMessage(String json) throws InvalidFormatException {
-            ClientMessageReader reader = new ClientMessageReader();
-            reader.readMessage(json.getBytes());
-            return reader.mLastMessage;
-        }
-    }
-}
diff --git a/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/SessionDependencyFactoryTest.java b/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/SessionDependencyFactoryTest.java
deleted file mode 100644
index 90a3a9c..0000000
--- a/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/SessionDependencyFactoryTest.java
+++ /dev/null
@@ -1,200 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge;
-
-import android.test.InstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import junit.framework.Assert;
-
-import java.nio.ByteBuffer;
-
-/**
- * Tests for {@link SessionDependencyFactory}
- */
-public class SessionDependencyFactoryTest extends InstrumentationTestCase {
-    private static final int DATA_CHANNEL_ID = 0;
-
-    private SessionDependencyFactory mInstance;
-    private AbstractPeerConnection mConnection;
-    private PeerConnectionObserverMock mObserver;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mObserver = new PeerConnectionObserverMock();
-    }
-
-    @SmallTest
-    public void testCreateFactory() {
-        mInstance = newFactory();
-        mInstance.dispose();
-    }
-
-    @SmallTest
-    public void testCreateConnection() {
-        mInstance = newFactory();
-        RTCConfiguration config = new RTCConfiguration.Builder()
-                .addIceServer("http://expample.org")
-                .build();
-        mInstance.createPeerConnection(config, mObserver).dispose();
-        mInstance.dispose();
-    }
-
-    @SmallTest
-    public void testCreateAndSetLocalOffer() throws Exception {
-        mInstance = newFactory();
-        mConnection = newConnection();
-        mConnection.createAndSetLocalDescription(
-                AbstractPeerConnection.SessionDescriptionType.OFFER);
-
-        mObserver.localDescriptionAvailable.await();
-
-        Assert.assertEquals(
-                AbstractPeerConnection.SessionDescriptionType.OFFER,
-                mObserver.localDescriptionType);
-        mConnection.dispose();
-        mInstance.dispose();
-    }
-
-    @SmallTest
-    public void testTerminateCallback() {
-        mInstance = newFactory();
-        mConnection = newConnection();
-        mConnection.createAndSetLocalDescription(
-                AbstractPeerConnection.SessionDescriptionType.OFFER);
-
-        // Do not wait.
-
-        mConnection.dispose();
-        mInstance.dispose();
-    }
-
-    @SmallTest
-    public void testCreateAndSetLocalAnswerFailed() throws Exception {
-        mInstance = newFactory();
-        mConnection = newConnection();
-        // Creating answer without offer set must fail.
-        mConnection.createAndSetLocalDescription(
-                AbstractPeerConnection.SessionDescriptionType.ANSWER);
-
-        mObserver.failureAvailable.await();
-
-        mConnection.dispose();
-        mInstance.dispose();
-    }
-
-    @SmallTest
-    public void testSetRemoteOffer() throws Exception {
-        mInstance = newFactory();
-        mConnection = newConnection();
-        mConnection.createAndSetLocalDescription(
-                AbstractPeerConnection.SessionDescriptionType.OFFER);
-        mObserver.localDescriptionAvailable.await();
-        String offer = mObserver.localDescription;
-        mConnection.dispose();
-
-        mConnection = newConnection();
-        mConnection.setRemoteDescription(
-                AbstractPeerConnection.SessionDescriptionType.OFFER, offer);
-        mObserver.remoteDescriptionSet.await();
-
-        mConnection.dispose();
-        mInstance.dispose();
-    }
-
-    @SmallTest
-    public void testNegotiation() throws Exception {
-        mInstance = newFactory();
-        DataPipe pipe = new DataPipe(mInstance);
-        pipe.negotiate();
-        pipe.dispose();
-        mInstance.dispose();
-    }
-
-    @SmallTest
-    public void testConnection() throws Exception {
-        mInstance = newFactory();
-        DataPipe pipe = new DataPipe(mInstance);
-        pipe.negotiate();
-        pipe.awaitConnected();
-        pipe.dispose();
-        mInstance.dispose();
-    }
-
-    @SmallTest
-    public void testDataChannel() {
-        mInstance = newFactory();
-        mConnection = newConnection();
-        AbstractDataChannel channel = mConnection.createDataChannel(DATA_CHANNEL_ID);
-
-        channel.registerObserver(new DataChannelObserverMock());
-        channel.send(ByteBuffer.allocateDirect(1), AbstractDataChannel.MessageType.TEXT);
-        channel.send(ByteBuffer.allocateDirect(1), AbstractDataChannel.MessageType.BINARY);
-        channel.unregisterObserver();
-        channel.close();
-
-        channel.dispose();
-        mConnection.dispose();
-        mInstance.dispose();
-    }
-
-    @SmallTest
-    public void testDataChannelOpens() throws Exception {
-        mInstance = newFactory();
-        DataPipe pipe = new DataPipe(mInstance);
-
-        pipe.registerDatatChannelObservers();
-
-        pipe.negotiate();
-
-        pipe.dataChannelObserver(0).opened.await();
-        pipe.dataChannelObserver(1).opened.await();
-
-        pipe.unregisterDatatChannelObservers();
-
-        pipe.dispose();
-        mInstance.dispose();
-    }
-
-    @MediumTest
-    public void testPumpData() throws Exception {
-        mInstance = newFactory();
-        DataPipe pipe = new DataPipe(mInstance);
-        pipe.registerDatatChannelObservers();
-        pipe.negotiate();
-        pipe.dataChannelObserver(0).opened.await();
-
-        // Make sure data channel don't leave local references on stack
-        // of signaling thread. References causes failure like
-        // "Failed adding to JNI local ref table (has 512 entries)".
-        final int count = 1000;
-
-        for (int i = 0; i < count; i++) {
-            pipe.send(0, "A");
-        }
-
-        for (int i = 0; i < count; i++) {
-            pipe.dataChannelObserver(1).received.take();
-        }
-
-        pipe.unregisterDatatChannelObservers();
-        pipe.dispose();
-        mInstance.dispose();
-    }
-
-    private SessionDependencyFactory newFactory() {
-        return SessionDependencyFactory.newInstance();
-    }
-
-    private AbstractPeerConnection newConnection() {
-        return newConnection(mObserver);
-    }
-
-    private AbstractPeerConnection newConnection(PeerConnectionObserverMock observer) {
-        return mInstance.createPeerConnection(new RTCConfiguration(), observer);
-    }
-}
diff --git a/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/SocketTunnelServerTest.java b/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/SocketTunnelServerTest.java
deleted file mode 100644
index 53aab71..0000000
--- a/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/SocketTunnelServerTest.java
+++ /dev/null
@@ -1,234 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge;
-
-import android.net.LocalServerSocket;
-import android.net.LocalSocket;
-import android.test.InstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-
-import junit.framework.Assert;
-
-import org.chromium.base.annotations.SuppressFBWarnings;
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.nio.ByteBuffer;
-
-/**
- * Tests for {@link SocketTunnelServer}
- */
-public class SocketTunnelServerTest extends InstrumentationTestCase {
-    private static final int CONNECTION_ID = 30;
-    private static final String SOCKET_NAME = "ksdjhflksjhdflk";
-
-    private static final int SERVER_CHANNEL = 1;
-    private static final int CLIENT_CHANNEL = 0;
-
-    private SessionDependencyFactory mFactory;
-    private DataPipe mPipe;
-    private SocketTunnel mServer;
-    private LocalServerSocket mSocket;
-    private DataChannelObserverMock mObserverMock;
-
-    @Override
-    public void setUp() throws Exception {
-        super.setUp();
-        mFactory = SessionDependencyFactory.newInstance();
-        mPipe = new DataPipe(mFactory);
-        mServer = mFactory.newSocketTunnelServer(SOCKET_NAME);
-        mServer.bind(mPipe.dataChannel(SERVER_CHANNEL));
-        mSocket = new LocalServerSocket(SOCKET_NAME);
-        mObserverMock = new DataChannelObserverMock();
-        mPipe.dataChannel(CLIENT_CHANNEL).registerObserver(mObserverMock);
-        mPipe.negotiate();
-        mPipe.awaitConnected();
-    }
-
-    @Override
-    public void tearDown() throws Exception {
-        mPipe.dataChannel(CLIENT_CHANNEL).unregisterObserver();
-        mServer.unbind();
-        mPipe.dispose();
-        mFactory.dispose();
-        super.tearDown();
-    }
-
-    private void sendPacket(ByteBuffer packet) {
-        packet.position(0);
-        mPipe.send(CLIENT_CHANNEL, packet);
-    }
-
-    @MediumTest
-    public void testConnectToSocket() throws IOException {
-        LocalSocket socket = connectToSocket(1);
-        socket.close();
-    }
-
-    private LocalSocket connectToSocket(int connectionId) throws IOException {
-        sendPacket(SocketTunnelBase.buildControlPacket(
-                connectionId, SocketTunnelBase.CLIENT_OPEN));
-        return mSocket.accept();
-    }
-
-    private void sendClose(int connectionId) {
-        sendPacket(SocketTunnelBase.buildControlPacket(
-                connectionId, SocketTunnelBase.CLIENT_CLOSE));
-    }
-
-    @MediumTest
-    public void testReceiveOpenAcknowledgement() throws IOException, InterruptedException {
-        LocalSocket socket = connectToSocket(CONNECTION_ID);
-
-        receiveOpenAck(CONNECTION_ID);
-
-        socket.close();
-    }
-
-    private PacketDecoder receivePacket() throws InterruptedException {
-        byte[] bytes = mObserverMock.received.take();
-        ByteBuffer buffer = ByteBuffer.allocate(bytes.length);
-        buffer.put(bytes);
-        buffer.position(0);
-        return PacketDecoder.decode(buffer);
-    }
-
-    private PacketDecoder receiveControlPacket(int connectionId) throws InterruptedException {
-        PacketDecoder decoder = receivePacket();
-        Assert.assertTrue(decoder.isControlPacket());
-        Assert.assertEquals(connectionId, decoder.connectionId());
-        return decoder;
-    }
-
-    private void receiveOpenAck(int connectionId) throws InterruptedException {
-        PacketDecoder decoder = receiveControlPacket(connectionId);
-        Assert.assertEquals(SocketTunnelBase.SERVER_OPEN_ACK, decoder.opCode());
-    }
-
-    private void receiveClose(int connectionId) throws InterruptedException {
-        PacketDecoder decoder = receiveControlPacket(connectionId);
-        Assert.assertEquals(SocketTunnelBase.SERVER_CLOSE, decoder.opCode());
-    }
-
-    @MediumTest
-    public void testClosingSocket() throws IOException, InterruptedException {
-        LocalSocket socket = connectToSocket(CONNECTION_ID);
-        receiveOpenAck(CONNECTION_ID);
-
-        socket.close();
-
-        PacketDecoder decoder = receiveControlPacket(CONNECTION_ID);
-
-        Assert.assertEquals(SocketTunnelBase.SERVER_CLOSE, decoder.opCode());
-    }
-
-    @MediumTest
-    public void testReadData() throws IOException, InterruptedException {
-        LocalSocket socket = connectToSocket(CONNECTION_ID);
-        receiveOpenAck(CONNECTION_ID);
-
-        byte[] sample = "Sample".getBytes();
-
-        socket.getOutputStream().write(sample);
-        socket.getOutputStream().flush();
-        socket.shutdownOutput();
-
-        ByteBuffer result = receiveData(CONNECTION_ID, sample.length);
-        Assert.assertEquals(ByteBuffer.wrap(sample), result);
-    }
-
-    private ByteBuffer receiveData(int connectionId, int length) throws InterruptedException {
-        ByteBuffer result = ByteBuffer.allocate(length);
-
-        while (true) {
-            PacketDecoder decoder = receivePacket();
-            if (decoder.isDataPacket()) {
-                Assert.assertEquals(connectionId, decoder.connectionId());
-                result.put(decoder.data());
-            } else if (decoder.isControlPacket()) {
-                Assert.assertEquals(SocketTunnelBase.SERVER_CLOSE, decoder.opCode());
-                Assert.assertEquals(connectionId, decoder.connectionId());
-                break;
-            }
-        }
-        result.limit(result.position());
-        result.position(0);
-        return result;
-    }
-
-    private int sum(int[] values) {
-        int result = 0;
-        for (int v : values)
-            result += v;
-        return result;
-    }
-
-    private static final int[] CHUNK_SIZES =
-            new int[] { 0, 1, 5, 100, 1000, SocketTunnelBase.READING_BUFFER_SIZE * 2 };
-
-    @MediumTest
-    public void testReadLongDataChunk() throws IOException, InterruptedException {
-        LocalSocket socket = connectToSocket(CONNECTION_ID);
-        receiveOpenAck(CONNECTION_ID);
-
-        byte[] buffer = new byte[CHUNK_SIZES[CHUNK_SIZES.length - 1]];
-        ByteBuffer sentData = ByteBuffer.allocate(sum(CHUNK_SIZES));
-        OutputStream stream = socket.getOutputStream();
-        byte next = 0;
-        int prevSize = 0;
-        for (int size : CHUNK_SIZES) {
-            while (prevSize < size)
-                buffer[prevSize++] = next++;
-
-            stream.write(buffer, 0, size);
-            sentData.put(buffer, 0, size);
-        }
-
-        socket.shutdownOutput();
-
-        sentData.limit(sentData.position());
-        sentData.position(0);
-        ByteBuffer readData = receiveData(CONNECTION_ID, sentData.limit());
-
-        Assert.assertEquals(sentData, readData);
-    }
-
-    @SuppressFBWarnings("DLS_DEAD_LOCAL_STORE")
-    @MediumTest
-    public void testReuseConnectionId() throws IOException, InterruptedException {
-        LocalSocket socket = connectToSocket(CONNECTION_ID);
-        receiveOpenAck(CONNECTION_ID);
-
-        socket.close();
-        receiveClose(CONNECTION_ID);
-        sendClose(CONNECTION_ID);
-
-        // Open connection with the same ID
-        socket = connectToSocket(CONNECTION_ID);
-        receiveOpenAck(CONNECTION_ID);
-    }
-
-    private static final byte[] SAMPLE = "Sample".getBytes();
-
-    @MediumTest
-    public void testWriteData() throws IOException, InterruptedException {
-        LocalSocket socket = connectToSocket(CONNECTION_ID);
-        receiveOpenAck(CONNECTION_ID);
-
-        sendPacket(SocketTunnelBase.buildDataPacket(CONNECTION_ID, SAMPLE, SAMPLE.length));
-
-        byte[] result = new byte[SAMPLE.length];
-        int read = 0;
-        while (read < SAMPLE.length) {
-            int count = socket.getInputStream().read(result, 0, SAMPLE.length - read);
-            Assert.assertTrue(count > 0);
-            read += count;
-        }
-
-        Assert.assertEquals(ByteBuffer.wrap(SAMPLE), ByteBuffer.wrap(result));
-
-        socket.close();
-    }
-}
diff --git a/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/apiary/JsonResponseHandlerTest.java b/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/apiary/JsonResponseHandlerTest.java
deleted file mode 100644
index cb4b95c4..0000000
--- a/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/apiary/JsonResponseHandlerTest.java
+++ /dev/null
@@ -1,138 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge.apiary;
-
-import android.test.InstrumentationTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.util.JsonReader;
-
-import junit.framework.Assert;
-
-import org.apache.http.ProtocolVersion;
-import org.apache.http.client.ClientProtocolException;
-import org.apache.http.client.HttpResponseException;
-import org.apache.http.entity.StringEntity;
-import org.apache.http.message.BasicHttpResponse;
-
-import java.io.IOException;
-
-/**
- * Tests for {@link JsonResponseHandler}.
- */
-public class JsonResponseHandlerTest extends InstrumentationTestCase {
-    @SmallTest
-    public void testInvalidResponse() throws IOException {
-        try {
-            new JsonResponseHandler<String>() {
-                        @Override
-                        public String readResponse(JsonReader reader) {
-                            return "";
-                        }
-                    }.handleResponse(newResponse(404, null));
-
-            Assert.fail();
-        } catch (HttpResponseException e) {
-            // Expected
-        }
-    }
-
-    @SmallTest
-    public void testIOException() {
-        try {
-            new JsonResponseHandler<String>() {
-                        @Override
-                        public String readResponse(JsonReader reader) throws IOException {
-                            throw new IOException();
-                        }
-                    }.handleResponse(newResponse(200, ""));
-
-            Assert.fail();
-        } catch (IOException e) {
-            // Expected
-        }
-    }
-
-    @SmallTest
-    public void testStateException() throws IOException {
-        try {
-            new JsonResponseHandler<String>() {
-                        @Override
-                        public String readResponse(JsonReader reader) throws IOException {
-                            reader.beginObject();
-                            reader.endObject();
-                            return "";
-                        }
-                    }.handleResponse(newResponse(200, "[]"));
-
-            Assert.fail();
-        } catch (JsonResponseHandler.ResponseFormatException e) {
-            // Expected
-        }
-    }
-
-    @SmallTest
-    public void testFormatException() throws IOException {
-        try {
-            new JsonResponseHandler<String>() {
-                        @Override
-                        public String readResponse(JsonReader reader) throws IOException {
-                            reader.beginArray();
-                            reader.nextLong();
-                            reader.endArray();
-                            return "";
-                        }
-                    }.handleResponse(newResponse(200, "[\"XXX\"]"));
-
-            Assert.fail();
-        } catch (JsonResponseHandler.ResponseFormatException e) {
-            // Expected
-        }
-    }
-
-    @SmallTest
-    public void testNullResultException() throws IOException {
-        try {
-            new JsonResponseHandler<String>() {
-                        @Override
-                        public String readResponse(JsonReader reader) throws IOException {
-                            reader.beginArray();
-                            reader.endArray();
-                            return null;
-                        }
-                    }.handleResponse(newResponse(200, "[]"));
-
-            Assert.fail();
-        } catch (ClientProtocolException e) {
-            // Expected
-        }
-    }
-
-    @SmallTest
-    public void testSuccess() throws IOException {
-        String result = new JsonResponseHandler<String>() {
-                    @Override
-                    public String readResponse(JsonReader reader) throws IOException {
-                        reader.beginArray();
-                        reader.endArray();
-                        return "OK";
-                    }
-                }.handleResponse(newResponse(200, "[]"));
-
-        Assert.assertEquals("OK", result);
-    }
-
-    private BasicHttpResponse newResponse(int status, String content) {
-        BasicHttpResponse response = new BasicHttpResponse(
-                new ProtocolVersion("HTTP", 1, 1), status, "reason");
-        if (content != null) {
-            try {
-                response.setEntity(new StringEntity(content, "UTF-8"));
-            } catch (Exception e) {
-                throw new RuntimeException(e);
-            }
-        }
-        return response;
-    }
-}
diff --git a/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/apiary/OAuthClientTest.java b/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/apiary/OAuthClientTest.java
deleted file mode 100644
index 78c7c54..0000000
--- a/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/apiary/OAuthClientTest.java
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge.apiary;
-
-import android.test.InstrumentationTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import junit.framework.Assert;
-
-import org.chromium.components.devtools_bridge.util.TestSource;
-
-/**
- * Tests for {@link OAuthClient}.
- */
-public class OAuthClientTest extends InstrumentationTestCase {
-    private static final String ACCESS_TOKEN =
-            "ya29.rgBgy64Y1MACXNmPDUpPGbwFuAec2NCCDJwaEp8DwLnV8RBk45p9RBqBfEQUYxL6OVB-oyktRqZj0w";
-    private static final String REFRESH_TOKEN =
-            "1/cWihsJmDMujYfhzBVTwgh4ukiFyiiRWLmFwTv4EigzU";
-
-    @SmallTest
-    public void testResponse() throws Exception {
-        TestSource source = new TestSource();
-        source.write()
-                .beginObject()
-                .name("access_token").value(ACCESS_TOKEN)
-                .name("token_type").value("Bearer")
-                .name("expires_in").value(3600) // seconds
-                .name("refresh_token").value(REFRESH_TOKEN)
-                .endObject()
-                .close();
-        OAuthResult result = OAuthClient.readResponse(source.read(), 1111);
-        Assert.assertEquals(ACCESS_TOKEN, result.accessToken);
-        Assert.assertEquals(REFRESH_TOKEN, result.refreshToken);
-        Assert.assertEquals(1111 + 3600000, result.expirationTimeMs);
-    }
-}
diff --git a/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/commands/CommandReceiverTest.java b/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/commands/CommandReceiverTest.java
deleted file mode 100644
index e5226ff..0000000
--- a/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/commands/CommandReceiverTest.java
+++ /dev/null
@@ -1,91 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge.commands;
-
-import android.test.InstrumentationTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import junit.framework.Assert;
-
-import org.chromium.components.devtools_bridge.RTCConfiguration;
-import org.chromium.components.devtools_bridge.SignalingReceiverMock;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Tests for {@link CommandReceiver}
- */
-public class CommandReceiverTest extends InstrumentationTestCase {
-    private static final RTCConfiguration CONFIG = new RTCConfiguration.Builder()
-            .build();
-
-    private final SignalingReceiverMock mMock = new SignalingReceiverMock();
-    private final CommandReceiver mReceiver = new CommandReceiver(mMock);
-    private final CompletionHandler mCompletionHandler = new CompletionHandler();
-
-    private static class CompletionHandler implements Runnable {
-        public boolean done = false;
-
-        @Override
-        public void run() {
-            done = true;
-        }
-    };
-
-    @SmallTest
-    public void testStartSessionCommand() {
-        Commands.StartSessionCommand command =
-                new Commands.StartSessionCommand("SESSION_ID", CONFIG, "OFFER");
-
-        mReceiver.receive(command, mCompletionHandler);
-        Assert.assertEquals("SESSION_ID", mMock.sessionId);
-        Assert.assertEquals("OFFER", mMock.offer);
-
-        mMock.negotiationCallback.onSuccess("ANSWER");
-        Assert.assertTrue(mCompletionHandler.done);
-        Assert.assertEquals(command.getResult(), "ANSWER");
-    }
-
-    @SmallTest
-    public void testRenegotiateCommand() {
-        Commands.RenegotiateCommand command =
-                new Commands.RenegotiateCommand("SESSION_ID", "OFFER");
-
-        mReceiver.receive(command, mCompletionHandler);
-        Assert.assertEquals("SESSION_ID", mMock.sessionId);
-        Assert.assertEquals("OFFER", mMock.offer);
-
-        mMock.negotiationCallback.onSuccess("ANSWER");
-        Assert.assertTrue(mCompletionHandler.done);
-        Assert.assertEquals(command.getResult(), "ANSWER");
-    }
-
-    @SmallTest
-    public void testIceExchangeCommand() {
-        List<String> candidates = new ArrayList<String>();
-
-        Commands.IceExchangeCommand command =
-                new Commands.IceExchangeCommand("SESSION_ID", candidates);
-
-        mReceiver.receive(command, mCompletionHandler);
-        Assert.assertEquals("SESSION_ID", mMock.sessionId);
-
-        mMock.iceExchangeCallback.onSuccess(candidates);
-        Assert.assertTrue(mCompletionHandler.done);
-    }
-
-    @SmallTest
-    public void testCommandFailure() {
-        Commands.RenegotiateCommand command =
-                new Commands.RenegotiateCommand("SESSION_ID", "OFFER");
-
-        mReceiver.receive(command, mCompletionHandler);
-
-        mMock.negotiationCallback.onFailure("ERROR_MESSAGE");
-        Assert.assertTrue(mCompletionHandler.done);
-        Assert.assertEquals(command.getErrorMessage(), "ERROR_MESSAGE");
-    }
-}
diff --git a/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/commands/CommandSenderTest.java b/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/commands/CommandSenderTest.java
deleted file mode 100644
index 3d03935..0000000
--- a/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/commands/CommandSenderTest.java
+++ /dev/null
@@ -1,126 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge.commands;
-
-import android.test.InstrumentationTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import junit.framework.Assert;
-
-import org.chromium.base.annotations.SuppressFBWarnings;
-import org.chromium.components.devtools_bridge.RTCConfiguration;
-import org.chromium.components.devtools_bridge.SessionBase;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Tests for {@link CommandSender}
- */
-@SuppressFBWarnings("URF_UNREAD_FIELD")
-public class CommandSenderTest extends InstrumentationTestCase {
-    private static final RTCConfiguration CONFIG = new RTCConfiguration.Builder()
-            .addIceServer("http://example.org")
-            .build();
-
-    private Command mCommand;
-    private Runnable mCompletionCallback;
-    private String mAnswer;
-    private String mErrorMessage;
-    private List<String> mServerCandidates;
-
-    @SmallTest
-    public void testStartSessionCommand() {
-        new SenderMock().startSession("SESSION_ID", CONFIG, "OFFER", new NegotiationCallbackMock());
-
-        Commands.StartSessionCommand command = (Commands.StartSessionCommand) mCommand;
-        Assert.assertNotNull(command);
-
-        Assert.assertEquals("SESSION_ID", command.sessionId);
-        Assert.assertEquals("OFFER", command.offer);
-
-        command.setResult("ANSWER");
-
-        mCompletionCallback.run();
-        Assert.assertEquals("ANSWER", mAnswer);
-        Assert.assertNull(mErrorMessage);
-    }
-
-    @SmallTest
-    public void testRenegotiateCommand() {
-        new SenderMock().renegotiate("SESSION_ID", "OFFER", new NegotiationCallbackMock());
-        Commands.RenegotiateCommand command = (Commands.RenegotiateCommand) mCommand;
-        Assert.assertNotNull(command);
-
-        Assert.assertEquals("SESSION_ID", command.sessionId);
-        Assert.assertEquals("OFFER", command.offer);
-
-        command.setResult("ANSWER");
-
-        mCompletionCallback.run();
-        Assert.assertEquals("ANSWER", mAnswer);
-        Assert.assertNull(mErrorMessage);
-    }
-
-    @SmallTest
-    public void testIceExchangeCommand() {
-        ArrayList<String> candidates = new ArrayList<String>();
-        new SenderMock().iceExchange("SESSION_ID", candidates, new IceExchangeCallbackMock());
-        Commands.IceExchangeCommand command = (Commands.IceExchangeCommand) mCommand;
-        Assert.assertNotNull(command);
-
-        Assert.assertEquals("SESSION_ID", command.sessionId);
-        command.setResult(candidates);
-
-        mCompletionCallback.run();
-        Assert.assertNull(mErrorMessage);
-    }
-
-    @SmallTest
-    public void testCommandFailure() {
-        new SenderMock().renegotiate("SESSION_ID", "OFFER", new NegotiationCallbackMock());
-
-        Commands.RenegotiateCommand command = (Commands.RenegotiateCommand) mCommand;
-        Assert.assertNotNull(command);
-
-        command.setFailure("TEST_MESSAGE");
-
-        mCompletionCallback.run();
-        Assert.assertNull(mAnswer);
-        Assert.assertEquals("TEST_MESSAGE", mErrorMessage);
-    }
-
-    private class SenderMock extends CommandSender {
-        @Override
-        protected void send(Command command, Runnable completionCallback) {
-            mCommand = command;
-            mCompletionCallback = completionCallback;
-        }
-    }
-
-    private class NegotiationCallbackMock implements SessionBase.NegotiationCallback {
-        @Override
-        public void onSuccess(String answer) {
-            mAnswer = answer;
-        }
-
-        @Override
-        public void onFailure(String errorMessage) {
-            mErrorMessage = errorMessage;
-        }
-    }
-
-    private class IceExchangeCallbackMock implements SessionBase.IceExchangeCallback {
-        @Override
-        public void onSuccess(List<String> serverCandidates) {
-            mServerCandidates = serverCandidates;
-        }
-
-        @Override
-        public void onFailure(String errorMessage) {
-            mErrorMessage = errorMessage;
-        }
-    }
-}
diff --git a/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/commands/CommandsTest.java b/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/commands/CommandsTest.java
deleted file mode 100644
index 2c7e6d8..0000000
--- a/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/commands/CommandsTest.java
+++ /dev/null
@@ -1,124 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge.commands;
-
-import android.test.InstrumentationTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import junit.framework.Assert;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Tests for {@link Commands}
- */
-public class CommandsTest extends InstrumentationTestCase {
-    @SmallTest
-    public void testStartSessionCommand() throws Exception {
-        CommandDefinition def = Command.Type.START_SESSION.definition;
-
-        Assert.assertEquals("_startSession", def.shortName());
-        Assert.assertEquals("base._startSession", def.fullName());
-
-        Assert.assertEquals(3, getParamCount(def));
-        Assert.assertEquals("_sessionId", getParam(def, 0).name());
-        Assert.assertEquals("_config", getParam(def, 1).name());
-        Assert.assertEquals("_offer", getParam(def, 2).name());
-
-        Map<String, String> values = new HashMap<String, String>();
-        values.put("_sessionId", "SESSION_ID");
-        values.put("_config", "{}");
-        values.put("_offer", "OFFER");
-
-        Commands.StartSessionCommand command =
-                (Commands.StartSessionCommand) def.newCommand("ID", values);
-
-        Assert.assertEquals(Command.Type.START_SESSION, command.type);
-        Assert.assertEquals("ID", command.id);
-        Assert.assertEquals("SESSION_ID", command.sessionId);
-        Assert.assertEquals("OFFER", command.offer);
-
-        visitInParams(command, values);
-    }
-
-    @SmallTest
-    public void testRenegotiateCommand() throws Exception {
-        CommandDefinition def = Command.Type.RENEGOTIATE.definition;
-
-        Assert.assertEquals("_renegotiate", def.shortName());
-        Assert.assertEquals("base._renegotiate", def.fullName());
-
-        Assert.assertEquals(2, getParamCount(def));
-        Assert.assertEquals("_sessionId", getParam(def, 0).name());
-        Assert.assertEquals("_offer", getParam(def, 1).name());
-
-        Map<String, String> values = new HashMap<String, String>();
-        values.put("_sessionId", "SESSION_ID");
-        values.put("_offer", "OFFER");
-
-        Commands.RenegotiateCommand command =
-                (Commands.RenegotiateCommand) def.newCommand("ID", values);
-
-        Assert.assertEquals(Command.Type.RENEGOTIATE, command.type);
-        Assert.assertEquals("ID", command.id);
-        Assert.assertEquals("OFFER", command.offer);
-
-        visitInParams(command, values);
-    }
-
-    @SmallTest
-    public void testIceExchangeCommand() throws Exception {
-        CommandDefinition def = Command.Type.ICE_EXCHANGE.definition;
-
-        Assert.assertEquals("_iceExchange", def.shortName());
-        Assert.assertEquals("base._iceExchange", def.fullName());
-
-        Assert.assertEquals(2, getParamCount(def));
-        Assert.assertEquals("_sessionId", getParam(def, 0).name());
-        Assert.assertEquals("_clientCandidates", getParam(def, 1).name());
-
-        Map<String, String> values = new HashMap<String, String>();
-        values.put("_sessionId", "SESSION_ID");
-        values.put("_clientCandidates", "[\"candidate\"]");
-
-        Commands.IceExchangeCommand command =
-                (Commands.IceExchangeCommand) def.newCommand("ID", values);
-
-        Assert.assertEquals(Command.Type.ICE_EXCHANGE, command.type);
-        Assert.assertEquals("ID", command.id);
-
-        visitInParams(command, values);
-    }
-
-    private void visitInParams(Command command, final Map<String, String> expectedValues) {
-        final Map<String, String> actualValues = new HashMap<String, String>();
-        command.visitInParams(new Command.ParamVisitor() {
-            @Override
-            public void visit(ParamDefinition param, String value) {
-                String name = param.name();
-                Assert.assertTrue(expectedValues.containsKey(name));
-                actualValues.put(name, value);
-            }
-        });
-        Assert.assertEquals(expectedValues.size(), actualValues.size());
-    }
-
-    private int getParamCount(CommandDefinition def) {
-        int count = 0;
-        for (ParamDefinition param : def.inParams()) {
-            count++;
-        }
-        return count;
-    }
-
-    private ParamDefinition getParam(CommandDefinition def, int index) {
-        for (ParamDefinition param : def.inParams()) {
-            if (index == 0) return param;
-            index--;
-        }
-        return null;
-    }
-}
diff --git a/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/commands/ParamDefinitionsTest.java b/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/commands/ParamDefinitionsTest.java
deleted file mode 100644
index 3bf72c8..0000000
--- a/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/commands/ParamDefinitionsTest.java
+++ /dev/null
@@ -1,81 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge.commands;
-
-import android.test.InstrumentationTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import junit.framework.Assert;
-
-import org.chromium.components.devtools_bridge.RTCConfiguration;
-
-import java.util.List;
-
-/**
- * Tests for {@link ParamDefinitions}
- */
-public class ParamDefinitionsTest extends InstrumentationTestCase {
-    @SmallTest
-    public void testStringParam() throws Exception {
-        ParamDefinition<String> param = ParamDefinitions.newStringParam("NAME");
-        Assert.assertEquals("_NAME", param.name());
-        Assert.assertEquals("string", param.type());
-        Assert.assertEquals("STRING", param.fromString("STRING"));
-        Assert.assertEquals("STRING", param.toString("STRING"));
-    }
-
-    @SmallTest
-    public void testStringListParam() throws Exception {
-        ParamDefinition<List<String>> param = ParamDefinitions.newStringListParam("NAME");
-        Assert.assertEquals("_NAME", param.name());
-        Assert.assertEquals("string", param.type());
-
-        List<String> value = param.fromString("[\"ITEM1\",\"ITEM2\"]");
-        Assert.assertEquals(2, value.size());
-        Assert.assertEquals("ITEM1", value.get(0));
-        Assert.assertEquals("ITEM2", value.get(1));
-
-        try {
-            param.fromString("{\"ITEM1\",\"ITEM2\"}");
-            Assert.fail("Exception expected");
-        } catch (CommandFormatException e) {
-            // Expected.
-        }
-
-        List<String> clone = param.fromString(param.toString(value));
-        Assert.assertEquals(value.size(), clone.size());
-        Assert.assertEquals(value.get(0), clone.get(0));
-        Assert.assertEquals(value.get(1), clone.get(1));
-    }
-
-    @SmallTest
-    public void testConfigParam() throws Exception {
-        ParamDefinition<RTCConfiguration> param = ParamDefinitions.newConfigParam("NAME");
-        Assert.assertEquals("_NAME", param.name());
-        Assert.assertEquals("string", param.type());
-
-        RTCConfiguration value = param.fromString(
-                "{\"iceServers\": [{\"uri\": \"http://example.org\"}]}");
-        Assert.assertNotNull(value);
-        Assert.assertEquals(1, value.iceServers.size());
-        Assert.assertEquals("http://example.org", value.iceServers.get(0).uri);
-
-        try {
-            param.fromString("[");
-            Assert.fail("Exception expected");
-        } catch (CommandFormatException e) {
-            // Expected.
-        }
-
-        value = new RTCConfiguration.Builder()
-                .addIceServer("http://example.org/1", "USERNAME", "CREDENTIAL")
-                .addIceServer("http://example.org/2", "USERNAME", "CREDENTIAL")
-                .build();
-        RTCConfiguration clone = param.fromString(param.toString(value));
-        Assert.assertEquals(value.iceServers.size(), clone.iceServers.size());
-        Assert.assertEquals(value.iceServers.get(0).username, clone.iceServers.get(0).username);
-        Assert.assertEquals(value.iceServers.get(1).credential, clone.iceServers.get(1).credential);
-    }
-}
diff --git a/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/gcd/MessageReaderTest.java b/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/gcd/MessageReaderTest.java
deleted file mode 100644
index 72b5254..0000000
--- a/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/gcd/MessageReaderTest.java
+++ /dev/null
@@ -1,119 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge.gcd;
-
-import android.test.InstrumentationTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import junit.framework.Assert;
-
-import org.chromium.components.devtools_bridge.commands.Command;
-import org.chromium.components.devtools_bridge.util.TestSource;
-
-/**
- * Tests for {@link MessageReader}.
- */
-public class MessageReaderTest extends InstrumentationTestCase {
-    private static final String DEVICE_ID = "4ac8a0f8-??????????????-192e2727710d";
-    private static final String ROBOT_ACCOUNT_EMAIL =
-            "2a3???????????????????????????87@clouddevices.gserviceaccount.com";
-    private static final String AUTHORIZATION_CODE =
-            "4/6V0jpup-????????????????????????????????????????????_e85kQI";
-    private static final String COMMAND_ID =
-            "a0217abb-????-????-????-?????????????????????????-????-2725-b2332fe99829";
-
-    @SmallTest
-    public void testReadTicket() throws Exception {
-        TestSource source = new TestSource();
-        source.write().beginObject()
-                .name("kind").value("clouddevices#registrationTicket")
-                .name("id").value("p8hI4")
-                .name("deviceId").value(DEVICE_ID)
-                .name("creationTimeMs").value("1411029429794")
-                .name("expirationTimeMs").value("1411029669794")
-                .endObject().close();
-        String result = new MessageReader(source.read()).readTicketId();
-        Assert.assertEquals("p8hI4", result);
-    }
-
-    @SmallTest
-    public void testReadCredential() throws Exception {
-        TestSource source = new TestSource();
-        source.write().beginObject()
-                .name("kind").value("clouddevices#registrationTicket")
-                .name("id").value("p8hI4")
-                .name("deviceId").value(DEVICE_ID)
-                .name("userEmail").value("...@chromium.org")
-                .name("creationTimeMs").value("1411029429794")
-                .name("expirationTimeMs").value("1411029669794")
-                .name("robotAccountEmail").value(ROBOT_ACCOUNT_EMAIL)
-                .name("robotAccountAuthorizationCode").value(AUTHORIZATION_CODE)
-                .endObject().close();
-        InstanceCredential result = new MessageReader(source.read()).readInstanceCredential();
-        Assert.assertEquals(DEVICE_ID, result.id);
-        Assert.assertEquals(AUTHORIZATION_CODE, result.secret);
-    }
-
-    @SmallTest
-    public void testReadNotificationCommandCreated() throws Exception {
-        TestSource source = new TestSource();
-        source.write().beginObject()
-                .name("type").value("COMMAND_CREATED")
-                .name("commandId").value(COMMAND_ID)
-                .name("deviceId").value(DEVICE_ID)
-                .name("command").beginObject()
-                .name("kind").value("clouddevices#command")
-                .name("id").value(COMMAND_ID)
-                .name("deviceId").value(DEVICE_ID)
-                .name("name").value("base._startSession")
-                .name("parameters").beginObject()
-                .name("_sessionId").value("SESSION_ID")
-                .name("_config").value("{}")
-                .name("_offer").value("INVALID_OFFER")
-                .endObject() // parameters
-                .name("state").value("queued")
-                .name("error").beginObject()
-                .name("arguments").beginArray().endArray()
-                .name("creationTimeMs").value("1411137527329")
-                .name("expirationTimeMs").value("1411137547329")
-                .endObject() // error
-                .endObject() // command
-                .name("expirationTimeMs").value("1411029669794")
-                .endObject().close();
-        Notification result = new MessageReader(source.read()).readNotification();
-
-        Assert.assertEquals(Notification.Type.COMMAND_CREATED, result.type);
-        Assert.assertEquals(DEVICE_ID, result.instanceId);
-        Assert.assertNotNull(result.command);
-        Assert.assertEquals(COMMAND_ID, result.command.id);
-        Assert.assertEquals(Command.Type.START_SESSION, result.command.type);
-    }
-
-    @SmallTest
-    public void testReadNotificationCommandExpired() throws Exception {
-        TestSource source = new TestSource();
-        source.write().beginObject()
-                .name("type").value("COMMAND_EXPIRED")
-                .name("commandId").value(COMMAND_ID)
-                .name("deviceId").value(DEVICE_ID)
-                .endObject().close();
-        Notification result = new MessageReader(source.read()).readNotification();
-        Assert.assertNull(result);
-    }
-
-    @SmallTest
-    public void testReadNotificationInstanceUNregistered() throws Exception {
-        TestSource source = new TestSource();
-        source.write().beginObject()
-                .name("type").value("DEVICE_DELETED")
-                .name("deviceId").value(DEVICE_ID)
-                .endObject().close();
-        Notification result = new MessageReader(source.read()).readNotification();
-
-        Assert.assertEquals(Notification.Type.INSTANCE_UNREGISTERED, result.type);
-        Assert.assertEquals(DEVICE_ID, result.instanceId);
-        Assert.assertNull(result.command);
-    }
-}
diff --git a/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/tests/DebugActivity.java b/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/tests/DebugActivity.java
deleted file mode 100644
index 3fab9d3f..0000000
--- a/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/tests/DebugActivity.java
+++ /dev/null
@@ -1,136 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge.tests;
-
-import android.app.Activity;
-import android.content.Intent;
-import android.os.Build;
-import android.os.Bundle;
-import android.text.Html;
-import android.text.method.LinkMovementMethod;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.Button;
-import android.widget.LinearLayout;
-import android.widget.LinearLayout.LayoutParams;
-import android.widget.TextView;
-
-import org.chromium.components.devtools_bridge.ui.GCDRegistrationFragment;
-import org.chromium.components.devtools_bridge.ui.RemoteInstanceListFragment;
-
-/**
- * Activity for testing devtools bridge.
- */
-public class DebugActivity extends Activity {
-    private static final int LAYOUT_ID = 1000;
-    private static final String DOC_HREF =
-            "https://docs.google.com/a/chromium.org/document/d/"
-            + "188V6TWV8ivbjAPIp6aqwffWrY78xN2an5REajZHpunk/edit?usp=sharing";
-
-    private LinearLayout mLayout;
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        mLayout = new LinearLayout(this);
-        mLayout.setId(LAYOUT_ID);
-        mLayout.setOrientation(LinearLayout.VERTICAL);
-
-        TextView textView = new TextView(this);
-        textView.setText(Html.fromHtml(
-                "See <a href=\"" + DOC_HREF + "\">testing instructions</a>."));
-        textView.setMovementMethod(LinkMovementMethod.getInstance());
-        mLayout.addView(textView);
-
-        addActionButton("Start LocalSessionBridge", DebugService.START_SESSION_BRIDGE_ACTION);
-        addActionButton("Start DevToolsBridgeServer", DebugService.START_SERVER_ACTION);
-        addActionButton("Stop", DebugService.STOP_ACTION);
-
-        LayoutParams layoutParam = new LayoutParams(LayoutParams.MATCH_PARENT,
-                                                    LayoutParams.MATCH_PARENT);
-
-        getFragmentManager()
-                .beginTransaction()
-                .add(LAYOUT_ID, new TestGCDRegistrationFragment())
-                .add(LAYOUT_ID, new RemoteInstanceListFragmentImpl())
-                .commit();
-
-        setContentView(mLayout, layoutParam);
-    }
-
-    private void addActionButton(String text, String action) {
-        Button button = new Button(this);
-        button.setText(text);
-        button.setOnClickListener(new SendActionOnClickListener(action));
-        mLayout.addView(button);
-    }
-
-    private class SendActionOnClickListener implements View.OnClickListener {
-        private final String mAction;
-
-        SendActionOnClickListener(String action) {
-            mAction = action;
-        }
-
-        @Override
-        public void onClick(View v) {
-            Intent intent = new Intent(DebugActivity.this, DebugService.class);
-            intent.setAction(mAction);
-            startService(intent);
-        }
-    }
-
-    private static class TestGCDRegistrationFragment
-            extends GCDRegistrationFragment implements View.OnClickListener {
-        private Button mButton;
-
-        @Override
-        public View onCreateView(
-                LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
-            mButton = new Button(getActivity());
-            mButton.setOnClickListener(this);
-            updateText();
-            return mButton;
-        }
-
-        public void updateText() {
-            mButton.setText(isRegistered()
-                    ? "Unregister (registered for " + getOwner() + ")"
-                    : "Register in GCD");
-        }
-
-        @Override
-        protected void onRegistrationStatusChange() {
-            updateText();
-        }
-
-        @Override
-        protected String generateDisplayName() {
-            return Build.MODEL + " Test app";
-        }
-
-        @Override
-        public void onClick(View v) {
-            if (!isRegistered()) {
-                register();
-            } else {
-                unregister();
-            }
-        }
-    }
-
-    private final class RemoteInstanceListFragmentImpl extends RemoteInstanceListFragment {
-        @Override
-        protected void connect(String oAuthToken, String remoteInstanceId) {
-            startService(new Intent(DebugActivity.this, DebugService.class)
-                    .setAction(DebugService.START_GCD_CLIENT_ACTION)
-                    .putExtra(DebugService.EXTRA_OAUTH_TOKEN, oAuthToken)
-                    .putExtra(DebugService.EXTRA_REMOTE_INSTANCE_ID, remoteInstanceId));
-        }
-    }
-}
-
diff --git a/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/tests/DebugService.java b/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/tests/DebugService.java
deleted file mode 100644
index b009555..0000000
--- a/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/tests/DebugService.java
+++ /dev/null
@@ -1,243 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge.tests;
-
-import android.app.Notification;
-import android.app.PendingIntent;
-import android.app.Service;
-import android.content.Intent;
-import android.os.Binder;
-import android.os.IBinder;
-import android.os.Process;
-import android.widget.Toast;
-
-import org.chromium.components.devtools_bridge.DevToolsBridgeServerSandbox;
-import org.chromium.components.devtools_bridge.GCDClientSessionTestingHost;
-import org.chromium.components.devtools_bridge.LocalSessionBridge;
-
-import java.io.IOException;
-
-/**
- * Service for testing devtools bridge.
- */
-public class DebugService extends Service {
-    public static final String START_SESSION_BRIDGE_ACTION = "action.START_SESSION_BRIDGE";
-    public static final String START_SERVER_ACTION = "action.START_SERVER";
-    public static final String START_GCD_CLIENT_ACTION = "action.START_GCD_CLIENT";
-    public static final String STOP_ACTION = "action.STOP";
-
-    public static final String EXTRA_OAUTH_TOKEN = "extra.OAUTH_TOKEN";
-    public static final String EXTRA_REMOTE_INSTANCE_ID = "extra.REMOTE_INSTANCE_ID";
-
-    private static final int NOTIFICATION_ID = 1;
-
-    private Controller mRunningController;
-
-    private interface Controller {
-        void create() throws IOException;
-        void start() throws Exception;
-        void stop();
-        void dispose();
-    }
-
-    private String replicatingSocketName() {
-        return "chrome_shell_devtools_remote";
-    }
-
-    private String exposingSocketName() {
-        return "webview_devtools_remote_" + Integer.valueOf(Process.myPid());
-    }
-
-    private class LocalSessionBridgeController implements Controller {
-        private LocalSessionBridge mBridge;
-
-        @Override
-        public void create() throws IOException {
-            mBridge = new LocalSessionBridge(replicatingSocketName(), exposingSocketName());
-        }
-
-        @Override
-        public void start() {
-            mBridge.start();
-        }
-
-        @Override
-        public void stop() {
-            mBridge.stop();
-        }
-
-        @Override
-        public void dispose() {
-            mBridge.dispose();
-        }
-
-        @Override
-        public String toString() {
-            return "LocalSessionBridge";
-        }
-    }
-
-    private class DevToolsBridgeServerSandboxController implements Controller {
-        private DevToolsBridgeServerSandbox mSandbox;
-
-        @Override
-        public void create() {
-            mSandbox = new DevToolsBridgeServerSandbox();
-        }
-
-        @Override
-        public void start() throws Exception {
-            mSandbox.start(DebugService.this);
-        }
-
-        @Override
-        public void stop() {
-            mSandbox.stop();
-        }
-
-        @Override
-        public void dispose() {}
-
-        @Override
-        public String toString() {
-            return "DevToolsBridgeServerSandbox";
-        }
-    }
-
-    private class GCDClientController implements Controller {
-        private final String mOAuthToken;
-        private final String mRemoteInstanceId;
-
-        private GCDClientSessionTestingHost mHost;
-
-        public GCDClientController(String oAuthToken, String remoteInstanceId) {
-            mOAuthToken = oAuthToken;
-            mRemoteInstanceId = remoteInstanceId;
-        }
-
-        @Override
-        public void create() {
-        }
-
-        @Override
-        public void start() throws Exception {
-            final GCDClientSessionTestingHost host = new GCDClientSessionTestingHost(
-                    mOAuthToken, exposingSocketName(), mRemoteInstanceId);
-            host.start(new Runnable() {
-                        @Override
-                        public void run() {
-                            String text;
-                            if (!host.isStarted()) {
-                                text = "Session not started. See log for details";
-                            } else {
-                                text = "Session started";
-                            }
-                            Toast.makeText(DebugService.this, text, Toast.LENGTH_SHORT).show();
-                        }
-                    });
-            mHost = host;
-        }
-
-        @Override
-        public void stop() {
-        }
-
-        @Override
-        public void dispose() {
-            mHost.dispose();
-        }
-
-        @Override
-        public String toString() {
-            return "GCDClientSessionTestingHost";
-        }
-    }
-
-    @Override
-    public int onStartCommand(Intent intent, int flags, int startId) {
-        if (intent == null) return START_NOT_STICKY;
-
-        String action = intent.getAction();
-        if (START_SESSION_BRIDGE_ACTION.equals(action)) {
-            return start(new LocalSessionBridgeController());
-        } else if (START_SERVER_ACTION.equals(action)) {
-            return start(new DevToolsBridgeServerSandboxController());
-        } else if (START_GCD_CLIENT_ACTION.equals(action)) {
-            String oAuthToken = intent.getStringExtra(EXTRA_OAUTH_TOKEN);
-            String remoteInstanceId = intent.getStringExtra(EXTRA_REMOTE_INSTANCE_ID);
-            return start(new GCDClientController(oAuthToken, remoteInstanceId));
-        } else if (STOP_ACTION.equals(action)) {
-            return stop();
-        }
-        return START_NOT_STICKY;
-    }
-
-    private int start(Controller controller) {
-        if (mRunningController != null) {
-            Toast.makeText(this, "Already started", Toast.LENGTH_SHORT).show();
-            return START_NOT_STICKY;
-        }
-
-        try {
-            controller.create();
-            controller.start();
-        } catch (Exception e) {
-            e.printStackTrace();
-            Toast.makeText(this, "Failed to start", Toast.LENGTH_SHORT).show();
-            controller.dispose();
-            return START_NOT_STICKY;
-        }
-        mRunningController = controller;
-
-        startForeground(NOTIFICATION_ID, makeForegroundServiceNotification());
-        Toast.makeText(this, controller.toString() + " started", Toast.LENGTH_SHORT).show();
-        return START_STICKY;
-    }
-
-    private int stop() {
-        if (mRunningController == null)
-            return START_NOT_STICKY;
-
-        String name = mRunningController.toString();
-        mRunningController.stop();
-        mRunningController.dispose();
-        mRunningController = null;
-        stopSelf();
-        Toast.makeText(this, name + " stopped", Toast.LENGTH_SHORT).show();
-        return START_NOT_STICKY;
-    }
-
-    @Override
-    public IBinder onBind(Intent intent) {
-        return new Binder();
-    }
-
-    private Notification makeForegroundServiceNotification() {
-        Intent showInfoIntent = new Intent(this, DebugActivity.class);
-        showInfoIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
-        PendingIntent showInfoPendingIntent =
-                PendingIntent.getActivity(DebugService.this, 0, showInfoIntent, 0);
-
-        Intent stopIntent = new Intent(this, DebugService.class);
-        stopIntent.setAction(STOP_ACTION);
-        PendingIntent stopPendingIntent =
-                    PendingIntent.getService(DebugService.this, 0, stopIntent, 0);
-
-        return new Notification.Builder(this)
-                // Mandatory fiends
-                .setSmallIcon(android.R.drawable.alert_dark_frame)
-                .setContentTitle("DevTools Bridge")
-                .setContentText("DevTools socket local test tunnel works")
-
-                // Optional
-                .setContentIntent(showInfoPendingIntent)
-                .addAction(android.R.drawable.ic_delete,
-                        "Stop", stopPendingIntent)
-                .setOngoing(true)
-                .setWhen(System.currentTimeMillis())
-                .build();
-    }
-}
-
diff --git a/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/tests/TestApplication.java b/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/tests/TestApplication.java
deleted file mode 100644
index d6b16ba..0000000
--- a/components/devtools_bridge/android/javatests/src/org/chromium/components/devtools_bridge/tests/TestApplication.java
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge.tests;
-
-import android.app.Application;
-
-import org.chromium.base.library_loader.LibraryLoader;
-import org.chromium.base.library_loader.LibraryProcessType;
-import org.chromium.base.library_loader.ProcessInitException;
-import org.chromium.components.devtools_bridge.SessionDependencyFactory;
-import org.chromium.components.devtools_bridge.SessionDependencyFactoryNative;
-
-/**
- * Performs initialization for DevTools Bridge test APK.
- */
-public class TestApplication extends Application {
-    static {
-        System.loadLibrary("devtools_bridge_natives_so");
-        SessionDependencyFactory.init(SessionDependencyFactoryNative.class);
-        try {
-            LibraryLoader.get(LibraryProcessType.PROCESS_BROWSER).ensureInitialized();
-        } catch (ProcessInitException e) {
-            throw new RuntimeException(e);
-        }
-    }
-}
diff --git a/components/devtools_bridge/android/session_dependency_factory_android.cc b/components/devtools_bridge/android/session_dependency_factory_android.cc
deleted file mode 100644
index 50c81c5..0000000
--- a/components/devtools_bridge/android/session_dependency_factory_android.cc
+++ /dev/null
@@ -1,302 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/devtools_bridge/android/session_dependency_factory_android.h"
-
-#include "base/android/jni_string.h"
-#include "base/android/scoped_java_ref.h"
-#include "base/bind.h"
-#include "components/devtools_bridge/abstract_data_channel.h"
-#include "components/devtools_bridge/abstract_peer_connection.h"
-#include "components/devtools_bridge/rtc_configuration.h"
-#include "components/devtools_bridge/socket_tunnel_server.h"
-#include "jni/SessionDependencyFactoryNative_jni.h"
-
-using base::android::AttachCurrentThread;
-using base::android::ConvertJavaStringToUTF8;
-using base::android::ConvertUTF8ToJavaString;
-
-namespace devtools_bridge {
-namespace android {
-
-namespace {
-
-/**
- * Wraps Java observer and adapts it to native delegate. Chromium code normally
- * leaves local java references for automatic disposing. It doesn't happen here
- * (because calls originated from native thread). For instance, instead of
- *
- * ConvertUTF8ToJavaString(env, ...).Release()
- *
- * please use ConvertUTF8ToJavaString(env, ...).obj() or ScopedJavaLocalFrame.
- */
-class PeerConnectionDelegateImpl
-    : public AbstractPeerConnection::Delegate {
- public:
-  PeerConnectionDelegateImpl(JNIEnv* env, jobject java_object) {
-    java_object_.Reset(env, java_object);
-    connected_ = false;
-  }
-
-  void OnIceConnectionChange(bool connected) override {
-    JNIEnv* env = AttachCurrentThread();
-    Java_SessionDependencyFactoryNative_notifyIceConnectionChange(
-        env, java_object_.obj(), connected);
-  }
-
-  void OnIceCandidate(const std::string& sdp_mid,
-                      int sdp_mline_index,
-                      const std::string& sdp) override {
-    JNIEnv* env = AttachCurrentThread();
-    Java_SessionDependencyFactoryNative_notifyIceCandidate(
-        env, java_object_.obj(),
-        ConvertUTF8ToJavaString(env, sdp_mid).obj(),
-        sdp_mline_index, ConvertUTF8ToJavaString(env, sdp).obj());
-  }
-
-  void NotifyLocalOfferCreatedAndSetSet(const std::string& description) {
-    JNIEnv* env = AttachCurrentThread();
-    Java_SessionDependencyFactoryNative_notifyLocalOfferCreatedAndSetSet(
-        env, java_object_.obj(),
-        ConvertUTF8ToJavaString(env, description).obj());
-  }
-
-  void OnLocalOfferCreatedAndSetSet(const std::string& description) override {
-    JNIEnv* env = AttachCurrentThread();
-    Java_SessionDependencyFactoryNative_notifyLocalOfferCreatedAndSetSet(
-        env, java_object_.obj(),
-        ConvertUTF8ToJavaString(env, description).obj());
-  }
-
-  void OnLocalAnswerCreatedAndSetSet(const std::string& description) override {
-    JNIEnv* env = AttachCurrentThread();
-    Java_SessionDependencyFactoryNative_notifyLocalAnswerCreatedAndSetSet(
-        env, java_object_.obj(),
-        ConvertUTF8ToJavaString(env, description).obj());
-  }
-
-  void OnRemoteDescriptionSet() override {
-    JNIEnv* env = AttachCurrentThread();
-    Java_SessionDependencyFactoryNative_notifyRemoteDescriptionSet(
-        env, java_object_.obj());
-  }
-
-  void OnFailure(const std::string& description) override {
-    JNIEnv* env = AttachCurrentThread();
-    Java_SessionDependencyFactoryNative_notifyConnectionFailure(
-        env, java_object_.obj(),
-        ConvertUTF8ToJavaString(env, description).obj());
-  }
-
- private:
-  base::android::ScopedJavaGlobalRef<jobject> java_object_;
-  bool connected_;
-};
-
-class DataChannelObserverImpl : public AbstractDataChannel::Observer {
- public:
-  DataChannelObserverImpl(JNIEnv* env, jobject java_object) {
-    java_object_.Reset(env, java_object);
-  }
-
-  void OnOpen() override {
-    JNIEnv* env = AttachCurrentThread();
-    Java_SessionDependencyFactoryNative_notifyChannelOpen(
-        env, java_object_.obj());
-  }
-
-  void OnClose() override {
-    JNIEnv* env = AttachCurrentThread();
-    Java_SessionDependencyFactoryNative_notifyChannelClose(
-        env, java_object_.obj());
-  }
-
-  void OnMessage(const void* data, size_t length) override {
-    JNIEnv* env = AttachCurrentThread();
-
-    ScopedJavaLocalRef<jobject> byte_buffer(
-        env, env->NewDirectByteBuffer(const_cast<void*>(data), length));
-
-    Java_SessionDependencyFactoryNative_notifyMessage(
-        env, java_object_.obj(), byte_buffer.obj());
-  }
-
- private:
-  base::android::ScopedJavaGlobalRef<jobject> java_object_;
-};
-
-static void CleanupOnSignalingThread() {
-  // Called on signaling thread when SessionDependencyFactory is destroying.
-  base::android::DetachFromVM();
-}
-
-}  // namespace
-
-// SessionDependencyFactoryNative
-
-SessionDependencyFactoryAndroid::SessionDependencyFactoryAndroid()
-    : impl_(SessionDependencyFactory::CreateInstance(
-          base::Bind(&CleanupOnSignalingThread))) {
-}
-
-SessionDependencyFactoryAndroid::~SessionDependencyFactoryAndroid() {
-}
-
-// static
-bool SessionDependencyFactoryAndroid::RegisterNatives(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
-scoped_ptr<AbstractPeerConnection>
-SessionDependencyFactoryAndroid::CreatePeerConnection(
-    scoped_ptr<RTCConfiguration> config,
-    scoped_ptr<AbstractPeerConnection::Delegate> delegate) {
-  return impl_->CreatePeerConnection(config.Pass(), delegate.Pass());
-}
-
-scoped_refptr<base::TaskRunner>
-SessionDependencyFactoryAndroid::signaling_thread_task_runner() {
-  return impl_->signaling_thread_task_runner();
-}
-
-scoped_refptr<base::TaskRunner>
-SessionDependencyFactoryAndroid::io_thread_task_runner() {
-  return impl_->io_thread_task_runner();
-}
-
-// JNI generated methods
-
-static jlong CreateFactory(JNIEnv* env, jclass jcaller) {
-  return reinterpret_cast<jlong>(new SessionDependencyFactoryAndroid());
-}
-
-static void DestroyFactory(JNIEnv* env, jclass jcaller, jlong factory_ptr) {
-  delete reinterpret_cast<SessionDependencyFactoryAndroid*>(factory_ptr);
-}
-
-static jlong CreateConfig(JNIEnv* env, jclass jcaller) {
-  return reinterpret_cast<jlong>(
-      RTCConfiguration::CreateInstance().release());
-}
-
-static void AddIceServer(
-    JNIEnv* env, jclass jcaller, jlong config_ptr,
-    jstring uri, jstring username, jstring credential) {
-  reinterpret_cast<RTCConfiguration*>(config_ptr)->AddIceServer(
-      ConvertJavaStringToUTF8(env, uri),
-      ConvertJavaStringToUTF8(env, username),
-      ConvertJavaStringToUTF8(env, credential));
-}
-
-static jlong CreatePeerConnection(
-    JNIEnv* env, jclass jcaller,
-    jlong factory_ptr, jlong config_ptr, jobject observer) {
-  auto factory =
-      reinterpret_cast<SessionDependencyFactoryAndroid*>(factory_ptr);
-  auto config = reinterpret_cast<RTCConfiguration*>(config_ptr);
-
-  auto delegate = new PeerConnectionDelegateImpl(env, observer);
-
-  return reinterpret_cast<jlong>(factory->CreatePeerConnection(
-         make_scoped_ptr(config), make_scoped_ptr(delegate)).release());
-}
-
-static void DestroyPeerConnection(
-    JNIEnv* env, jclass jcaller, jlong connection_ptr) {
-  delete reinterpret_cast<AbstractPeerConnection*>(connection_ptr);
-}
-
-static void CreateAndSetLocalOffer(
-    JNIEnv* env, jclass jcaller, jlong connection_ptr) {
-  reinterpret_cast<AbstractPeerConnection*>(
-      connection_ptr)->CreateAndSetLocalOffer();
-}
-
-static void CreateAndSetLocalAnswer(
-    JNIEnv* env, jclass jcaller, jlong connection_ptr) {
-  reinterpret_cast<AbstractPeerConnection*>(
-      connection_ptr)->CreateAndSetLocalAnswer();
-}
-
-static void SetRemoteOffer(
-    JNIEnv* env, jclass jcaller, jlong connection_ptr, jstring description) {
-  reinterpret_cast<AbstractPeerConnection*>(connection_ptr)->SetRemoteOffer(
-      ConvertJavaStringToUTF8(env, description));
-}
-
-static void SetRemoteAnswer(
-    JNIEnv* env, jclass jcaller, jlong connection_ptr, jstring description) {
-  reinterpret_cast<AbstractPeerConnection*>(connection_ptr)->SetRemoteAnswer(
-      ConvertJavaStringToUTF8(env, description));
-}
-
-static void AddIceCandidate(
-    JNIEnv* env, jclass jcaller,
-    jlong connection_ptr, jstring sdp_mid, jint sdp_mline_index, jstring sdp) {
-  reinterpret_cast<AbstractPeerConnection*>(connection_ptr)->AddIceCandidate(
-      ConvertJavaStringToUTF8(env, sdp_mid),
-      sdp_mline_index,
-      ConvertJavaStringToUTF8(env, sdp));
-}
-
-static jlong CreateDataChannel(
-    JNIEnv* env, jclass jcaller, jlong connection_ptr, jint channel_id) {
-  return reinterpret_cast<jlong>(
-      reinterpret_cast<AbstractPeerConnection*>(
-          connection_ptr)->CreateDataChannel(channel_id).release());
-}
-
-static void DestroyDataChannel(
-    JNIEnv* env, jclass jcaller, jlong channel_ptr) {
-  delete reinterpret_cast<AbstractDataChannel*>(channel_ptr);
-}
-
-static void RegisterDataChannelObserver(
-    JNIEnv* env, jclass jcaller, jlong channel_ptr, jobject observer) {
-  reinterpret_cast<AbstractDataChannel*>(channel_ptr)->RegisterObserver(
-      make_scoped_ptr(new DataChannelObserverImpl(env, observer)));
-}
-
-static void UnregisterDataChannelObserver(
-    JNIEnv* env, jclass jcaller, jlong channel_ptr) {
-  reinterpret_cast<AbstractDataChannel*>(channel_ptr)->UnregisterObserver();
-}
-
-static void SendBinaryMessage(
-    JNIEnv* env, jclass jcaller, jlong channel_ptr, jobject message,
-    jint size) {
-  DCHECK(size > 0);
-  reinterpret_cast<AbstractDataChannel*>(channel_ptr)->SendBinaryMessage(
-      env->GetDirectBufferAddress(message), size);
-}
-
-static void SendTextMessage(
-    JNIEnv* env, jclass jcaller, jlong channel_ptr, jobject message,
-    jint size) {
-  DCHECK(size > 0);
-  reinterpret_cast<AbstractDataChannel*>(channel_ptr)->SendTextMessage(
-      env->GetDirectBufferAddress(message), size);
-}
-
-static void CloseDataChannel(JNIEnv* env, jclass jcaller, jlong channel_ptr) {
-  reinterpret_cast<AbstractDataChannel*>(channel_ptr)->Close();
-}
-
-static jlong CreateSocketTunnelServer(
-    JNIEnv* env, jclass jcaller, jlong factory_ptr, jlong channel_ptr,
-    jstring socket_name) {
-  return reinterpret_cast<jlong>(
-      new SocketTunnelServer(
-          reinterpret_cast<SessionDependencyFactory*>(factory_ptr),
-          reinterpret_cast<AbstractDataChannel*>(channel_ptr),
-          ConvertJavaStringToUTF8(env, socket_name)));
-}
-
-static void DestroySocketTunnelServer(
-    JNIEnv* env, jclass jcaller, jlong tunnel_ptr) {
-  delete reinterpret_cast<SocketTunnelServer*>(tunnel_ptr);
-}
-
-}  // namespace android
-}  // namespace devtools_bridge
diff --git a/components/devtools_bridge/android/session_dependency_factory_android.h b/components/devtools_bridge/android/session_dependency_factory_android.h
deleted file mode 100644
index 24496de1..0000000
--- a/components/devtools_bridge/android/session_dependency_factory_android.h
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_DEVTOOLS_BRIDGE_ANDROID_SESSION_DEPENDENCY_FACTORY_ANDROID_H_
-#define COMPONENTS_DEVTOOLS_BRIDGE_ANDROID_SESSION_DEPENDENCY_FACTORY_ANDROID_H_
-
-#include "components/devtools_bridge/session_dependency_factory.h"
-#include "jni.h"
-
-namespace devtools_bridge {
-namespace android {
-
-class SessionDependencyFactoryAndroid : public SessionDependencyFactory {
- public:
-  SessionDependencyFactoryAndroid();
-  ~SessionDependencyFactoryAndroid() override;
-
-  static bool RegisterNatives(JNIEnv* env);
-
-  scoped_ptr<AbstractPeerConnection> CreatePeerConnection(
-      scoped_ptr<RTCConfiguration> config,
-      scoped_ptr<AbstractPeerConnection::Delegate> delegate) override;
-
-  scoped_refptr<base::TaskRunner> signaling_thread_task_runner() override;
-  scoped_refptr<base::TaskRunner> io_thread_task_runner() override;
-
- private:
-  const scoped_ptr<SessionDependencyFactory> impl_;
-
-  DISALLOW_COPY_AND_ASSIGN(SessionDependencyFactoryAndroid);
-};
-
-}  // namespace android
-}  // namespace devtools_bridge
-
-#endif  // COMPONENTS_DEVTOOLS_BRIDGE_ANDROID_SESSION_DEPENDENCY_FACTORY_ANDROID_H_
diff --git a/components/devtools_bridge/rtc_configuration.h b/components/devtools_bridge/rtc_configuration.h
deleted file mode 100644
index 7eb0a220..0000000
--- a/components/devtools_bridge/rtc_configuration.h
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_DEVTOOLS_BRIDGE_RTC_CONFIGURATION_H_
-#define COMPONENTS_DEVTOOLS_BRIDGE_RTC_CONFIGURATION_H_
-
-#include <string>
-
-#include "base/memory/scoped_ptr.h"
-
-namespace devtools_bridge {
-
-/**
- * WebRTC configuration for DevTools Bridge.
- */
-class RTCConfiguration {
- public:
-  class Impl;
-
-  RTCConfiguration() {}
-  virtual ~RTCConfiguration() {}
-
-  virtual void AddIceServer(
-      const std::string& uri,
-      const std::string& username,
-      const std::string& credential) = 0;
-
-  virtual const Impl& impl() const = 0;
-
-  static scoped_ptr<RTCConfiguration> CreateInstance();
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(RTCConfiguration);
-};
-
-}  // namespace devtools_bridge
-
-#endif  // COMPONENTS_DEVTOOLS_BRIDGE_RTC_CONFIGURATION_H_
diff --git a/components/devtools_bridge/session_dependency_factory.cc b/components/devtools_bridge/session_dependency_factory.cc
deleted file mode 100644
index 2efa641..0000000
--- a/components/devtools_bridge/session_dependency_factory.cc
+++ /dev/null
@@ -1,641 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/devtools_bridge/session_dependency_factory.h"
-
-#include "base/bind.h"
-#include "base/location.h"
-#include "base/task_runner.h"
-#include "base/threading/thread.h"
-#include "components/devtools_bridge/abstract_data_channel.h"
-#include "components/devtools_bridge/abstract_peer_connection.h"
-#include "components/devtools_bridge/rtc_configuration.h"
-#include "third_party/libjingle/source/talk/app/webrtc/mediaconstraintsinterface.h"
-#include "third_party/libjingle/source/talk/app/webrtc/peerconnectioninterface.h"
-#include "third_party/webrtc/base/bind.h"
-#include "third_party/webrtc/base/messagehandler.h"
-#include "third_party/webrtc/base/messagequeue.h"
-#include "third_party/webrtc/base/ssladapter.h"
-#include "third_party/webrtc/base/thread.h"
-
-namespace devtools_bridge {
-
-class RTCConfiguration::Impl
-    : public RTCConfiguration,
-      public webrtc::PeerConnectionInterface::RTCConfiguration {
- public:
-  void AddIceServer(const std::string& uri,
-                    const std::string& username,
-                    const std::string& credential) override {
-    webrtc::PeerConnectionInterface::IceServer server;
-    server.uri = uri;
-    server.username = username;
-    server.password = credential;
-    servers.push_back(server);
-  }
-
-  const Impl& impl() const override {
-    return *this;
-  }
-
- private:
-  webrtc::PeerConnectionInterface::RTCConfiguration base_;
-};
-
-namespace {
-
-template <typename T>
-void CheckedRelease(rtc::scoped_refptr<T>* ptr) {
-  CHECK_EQ(0, ptr->release()->Release());
-}
-
-class MediaConstraints
-    : public webrtc::MediaConstraintsInterface {
- public:
-  ~MediaConstraints() override {}
-
-  const Constraints& GetMandatory() const override { return mandatory_; }
-
-  const Constraints& GetOptional() const override { return optional_; }
-
-  void AddMandatory(const std::string& key, const std::string& value) {
-    mandatory_.push_back(Constraint(key, value));
-  }
-
- private:
-  Constraints mandatory_;
-  Constraints optional_;
-};
-
-/**
- * Posts tasks on signaling thread. If stopped (when SesseionDependencyFactry
- * is destroying) ignores posted tasks.
- */
-class SignalingThreadTaskRunner : public base::TaskRunner,
-                                  private rtc::MessageHandler {
- public:
-  explicit SignalingThreadTaskRunner(rtc::Thread* thread) : thread_(thread) {}
-
-  bool PostDelayedTask(const tracked_objects::Location& from_here,
-                       const base::Closure& task,
-                       base::TimeDelta delay) override {
-    DCHECK(delay.ToInternalValue() == 0);
-
-    rtc::CritScope scope(&critical_section_);
-
-    if (thread_)
-      thread_->Send(this, 0, new Task(task));
-
-    return true;
-  }
-
-  bool RunsTasksOnCurrentThread() const override {
-    rtc::CritScope scope(&critical_section_);
-
-    return thread_ != NULL && thread_->IsCurrent();
-  }
-
-  void Stop() {
-    rtc::CritScope scope(&critical_section_);
-    thread_ = NULL;
-  }
-
- private:
-  typedef rtc::TypedMessageData<base::Closure> Task;
-
-  ~SignalingThreadTaskRunner() override {}
-
-  void OnMessage(rtc::Message* msg) override {
-    static_cast<Task*>(msg->pdata)->data().Run();
-  }
-
-  mutable rtc::CriticalSection critical_section_;
-  rtc::Thread* thread_;  // Guarded by |critical_section_|.
-};
-
-class DataChannelObserverImpl : public webrtc::DataChannelObserver {
- public:
-  DataChannelObserverImpl(
-      webrtc::DataChannelInterface* data_channel,
-      scoped_ptr<AbstractDataChannel::Observer> observer)
-      : data_channel_(data_channel),
-        observer_(observer.Pass()) {
-  }
-
-  void InitState() {
-    open_ = data_channel_->state() == webrtc::DataChannelInterface::kOpen;
-  }
-
-  void OnStateChange() override {
-    bool open = data_channel_->state() == webrtc::DataChannelInterface::kOpen;
-
-    if (open == open_) return;
-
-    open_ = open;
-    if (open) {
-      observer_->OnOpen();
-    } else {
-      observer_->OnClose();
-    }
-  }
-
-  void OnMessage(const webrtc::DataBuffer& buffer) override {
-    observer_->OnMessage(buffer.data.data(), buffer.size());
-  }
-
- private:
-  webrtc::DataChannelInterface* const data_channel_;
-  scoped_ptr<AbstractDataChannel::Observer> const observer_;
-  bool open_;
-};
-
-/**
- * Thread-safe view on AbstractDataChannel.
- */
-class DataChannelProxyImpl : public AbstractDataChannel::Proxy {
- public:
-  DataChannelProxyImpl(
-      SessionDependencyFactory* factory,
-      rtc::scoped_refptr<webrtc::DataChannelInterface> data_channel)
-      : data_channel_(data_channel),
-        signaling_thread_task_runner_(
-            factory->signaling_thread_task_runner()) {
-  }
-
-  void StopOnSignalingThread() {
-    data_channel_ = NULL;
-  }
-
-  void SendBinaryMessage(const void* data, size_t length) override {
-    auto buffer = make_scoped_ptr(new webrtc::DataBuffer(rtc::Buffer(), true));
-    buffer->data.SetData(static_cast<const uint8_t*>(data), length);
-
-    signaling_thread_task_runner_->PostTask(
-        FROM_HERE, base::Bind(
-            &DataChannelProxyImpl::SendMessageOnSignalingThread,
-            this,
-            base::Passed(&buffer)));
-  }
-
-  void Close() override {
-    signaling_thread_task_runner_->PostTask(
-        FROM_HERE, base::Bind(&DataChannelProxyImpl::CloseOnSignalingThread,
-                              this));
-  }
-
- private:
-
-  ~DataChannelProxyImpl() override {}
-
-  void SendMessageOnSignalingThread(scoped_ptr<webrtc::DataBuffer> message) {
-    if (data_channel_ != NULL)
-      data_channel_->Send(*message);
-  }
-
-  void CloseOnSignalingThread() {
-    if (data_channel_ != NULL)
-      data_channel_->Close();
-  }
-
-  // Accessed on signaling thread.
-  rtc::scoped_refptr<webrtc::DataChannelInterface> data_channel_;
-
-  const scoped_refptr<base::TaskRunner> signaling_thread_task_runner_;
-};
-
-class DataChannelImpl : public AbstractDataChannel {
- public:
-  DataChannelImpl(
-      SessionDependencyFactory* factory,
-      rtc::Thread* const signaling_thread,
-      rtc::scoped_refptr<webrtc::DataChannelInterface> impl)
-      : factory_(factory),
-        signaling_thread_(signaling_thread),
-        impl_(impl) {
-  }
-
-  ~DataChannelImpl() override {
-    if (proxy_.get()) {
-      signaling_thread_->Invoke<void>(rtc::Bind(
-          &DataChannelProxyImpl::StopOnSignalingThread, proxy_.get()));
-    }
-  }
-
-  void RegisterObserver(scoped_ptr<Observer> observer) override {
-    observer_.reset(new DataChannelObserverImpl(impl_.get(), observer.Pass()));
-    signaling_thread_->Invoke<void>(rtc::Bind(
-        &DataChannelImpl::RegisterObserverOnSignalingThread, this));
-  }
-
-  void UnregisterObserver() override {
-    DCHECK(observer_.get() != NULL);
-    impl_->UnregisterObserver();
-    observer_.reset();
-  }
-
-  void SendBinaryMessage(void* data, size_t length) override {
-    SendMessage(data, length, true);
-  }
-
-  void SendTextMessage(void* data, size_t length) override {
-    SendMessage(data, length, false);
-  }
-
-  void SendMessage(void* data, size_t length, bool is_binary) {
-    impl_->Send(webrtc::DataBuffer(
-        rtc::Buffer(static_cast<uint8_t*>(data), length), is_binary));
-  }
-
-  void Close() override {
-    impl_->Close();
-  }
-
-  scoped_refptr<Proxy> proxy() override {
-    if (!proxy_.get())
-      proxy_ = new DataChannelProxyImpl(factory_, impl_);
-    return proxy_;
-  }
-
- private:
-  void RegisterObserverOnSignalingThread() {
-    // State initialization and observer registration happen atomically
-    // if done on the signaling thread (see rtc::Thread::Send).
-    observer_->InitState();
-    impl_->RegisterObserver(observer_.get());
-  }
-
-  SessionDependencyFactory* const factory_;
-  scoped_refptr<DataChannelProxyImpl> proxy_;
-  rtc::Thread* const signaling_thread_;
-  scoped_ptr<DataChannelObserverImpl> observer_;
-  const rtc::scoped_refptr<webrtc::DataChannelInterface> impl_;
-};
-
-class PeerConnectionObserverImpl
-    : public webrtc::PeerConnectionObserver {
- public:
-  PeerConnectionObserverImpl(AbstractPeerConnection::Delegate* delegate)
-      : delegate_(delegate),
-        connected_(false) {
-  }
-
-  void OnAddStream(webrtc::MediaStreamInterface* stream) override {}
-
-  void OnRemoveStream(webrtc::MediaStreamInterface* stream) override {}
-
-  void OnDataChannel(webrtc::DataChannelInterface* data_channel) override {}
-
-  void OnRenegotiationNeeded() override {}
-
-  void OnSignalingChange(
-      webrtc::PeerConnectionInterface::SignalingState new_state) override {}
-
-  void OnIceConnectionChange(
-      webrtc::PeerConnectionInterface::IceConnectionState new_state) override {
-    bool connected =
-        new_state == webrtc::PeerConnectionInterface::kIceConnectionConnected ||
-        new_state == webrtc::PeerConnectionInterface::kIceConnectionCompleted;
-
-    if (connected != connected_) {
-      connected_ = connected;
-      delegate_->OnIceConnectionChange(connected_);
-    }
-  }
-
-  void OnIceCandidate(const webrtc::IceCandidateInterface* candidate) override {
-    std::string sdp;
-    candidate->ToString(&sdp);
-
-    delegate_->OnIceCandidate(
-        candidate->sdp_mid(), candidate->sdp_mline_index(), sdp);
-  }
-
- private:
-  AbstractPeerConnection::Delegate* const delegate_;
-  bool connected_;
-};
-
-/**
- * Helper object which may outlive PeerConnectionImpl. Provides access
- * to the connection and the delegate to operaion callback objects
- * in a safe way. Always accessible on the signaling thread.
- */
-class PeerConnectionHolder : public rtc::RefCountInterface {
- public:
-  PeerConnectionHolder(
-      rtc::Thread* signaling_thread,
-      webrtc::PeerConnectionInterface* connection,
-      AbstractPeerConnection::Delegate* delegate)
-      : signaling_thread_(signaling_thread),
-        connection_(connection),
-        delegate_(delegate),
-        disposed_(false) {
-  }
-
-  ~PeerConnectionHolder() override { DCHECK(disposed_); }
-
-  void Dispose() {
-    DCHECK(!IsDisposed());
-    disposed_ = true;
-  }
-
-  webrtc::PeerConnectionInterface* connection() {
-    DCHECK(!IsDisposed());
-    return connection_;
-  }
-
-  AbstractPeerConnection::Delegate* delegate() {
-    DCHECK(!IsDisposed());
-    return delegate_;
-  }
-
-  bool IsDisposed() {
-    DCHECK(signaling_thread_->IsCurrent());
-    return disposed_;
-  }
-
- private:
-  rtc::Thread* const signaling_thread_;
-  webrtc::PeerConnectionInterface* const connection_;
-  AbstractPeerConnection::Delegate* const delegate_;
-  bool disposed_;
-};
-
-class CreateAndSetHandler
-    : public webrtc::CreateSessionDescriptionObserver,
-      public webrtc::SetSessionDescriptionObserver {
- public:
-  explicit CreateAndSetHandler(
-      rtc::scoped_refptr<PeerConnectionHolder> holder)
-      : holder_(holder) {
-  }
-
-  void OnSuccess(webrtc::SessionDescriptionInterface* desc) override {
-    if (holder_->IsDisposed()) return;
-
-    type_ = desc->type();
-    if (desc->ToString(&description_)) {
-      holder_->connection()->SetLocalDescription(this, desc);
-    } else {
-      OnFailure("Can't serialize session description");
-    }
-  }
-
-  void OnSuccess() override {
-    if (holder_->IsDisposed()) return;
-
-    if (type_ == webrtc::SessionDescriptionInterface::kOffer) {
-      holder_->delegate()->OnLocalOfferCreatedAndSetSet(description_);
-    } else {
-      DCHECK_EQ(webrtc::SessionDescriptionInterface::kAnswer, type_);
-
-      holder_->delegate()->OnLocalAnswerCreatedAndSetSet(description_);
-    }
-  }
-
-  void OnFailure(const std::string& error) override {
-    if (holder_->IsDisposed()) return;
-
-    holder_->delegate()->OnFailure(error);
-  }
-
- private:
-  const rtc::scoped_refptr<PeerConnectionHolder> holder_;
-  std::string type_;
-  std::string description_;
-};
-
-class SetRemoteDescriptionHandler
-   : public webrtc::SetSessionDescriptionObserver {
- public:
-  SetRemoteDescriptionHandler(
-      rtc::scoped_refptr<PeerConnectionHolder> holder)
-      : holder_(holder) {
-  }
-
-  void OnSuccess() override {
-    if (holder_->IsDisposed()) return;
-
-    holder_->delegate()->OnRemoteDescriptionSet();
-  }
-
-  void OnFailure(const std::string& error) override {
-    if (holder_->IsDisposed()) return;
-
-    holder_->delegate()->OnFailure(error);
-  }
-
- private:
-  const rtc::scoped_refptr<PeerConnectionHolder> holder_;
-};
-
-class PeerConnectionImpl : public AbstractPeerConnection {
- public:
-  PeerConnectionImpl(
-      SessionDependencyFactory* const factory,
-      rtc::Thread* signaling_thread,
-      rtc::scoped_refptr<webrtc::PeerConnectionInterface> connection,
-      scoped_ptr<PeerConnectionObserverImpl> observer,
-      scoped_ptr<AbstractPeerConnection::Delegate> delegate)
-      : factory_(factory),
-        holder_(new rtc::RefCountedObject<PeerConnectionHolder>(
-            signaling_thread, connection.get(), delegate.get())),
-        signaling_thread_(signaling_thread),
-        connection_(connection),
-        observer_(observer.Pass()),
-        delegate_(delegate.Pass()) {
-  }
-
-  ~PeerConnectionImpl() override {
-    signaling_thread_->Invoke<void>(rtc::Bind(
-        &PeerConnectionImpl::DisposeOnSignalingThread, this));
-  }
-
-  void CreateAndSetLocalOffer() override {
-    connection_->CreateOffer(MakeCreateAndSetHandler(), NULL);
-  }
-
-  void CreateAndSetLocalAnswer() override {
-    connection_->CreateAnswer(MakeCreateAndSetHandler(), NULL);
-  }
-
-  void SetRemoteOffer(const std::string& description) override {
-    SetRemoteDescription(
-        webrtc::SessionDescriptionInterface::kOffer, description);
-  }
-
-  void SetRemoteAnswer(const std::string& description) override {
-    SetRemoteDescription(
-        webrtc::SessionDescriptionInterface::kAnswer, description);
-  }
-
-  void SetRemoteDescription(
-      const std::string& type, const std::string& description) {
-    webrtc::SdpParseError error;
-    scoped_ptr<webrtc::SessionDescriptionInterface> value(
-        webrtc::CreateSessionDescription(type, description, &error));
-    if (value == NULL) {
-      OnParseError(error);
-      return;
-    }
-    // Takes ownership on |value|.
-    connection_->SetRemoteDescription(
-        new rtc::RefCountedObject<SetRemoteDescriptionHandler>(holder_),
-        value.release());
-  }
-
-  void AddIceCandidate(const std::string& sdp_mid,
-                       int sdp_mline_index,
-                       const std::string& sdp) override {
-    webrtc::SdpParseError error;
-    auto candidate = webrtc::CreateIceCandidate(
-        sdp_mid, sdp_mline_index, sdp, &error);
-    if (candidate == NULL) {
-      OnParseError(error);
-      return;
-    }
-    // Doesn't takes ownership.
-    connection_->AddIceCandidate(candidate);
-    delete candidate;
-  }
-
-  scoped_ptr<AbstractDataChannel> CreateDataChannel(int channelId) override {
-    webrtc::DataChannelInit init;
-    init.ordered = true;
-    init.negotiated = true;
-    init.id = channelId;
-
-    return make_scoped_ptr(new DataChannelImpl(
-        factory_,
-        signaling_thread_,
-        connection_->CreateDataChannel("", &init)));
-  }
-
- private:
-  webrtc::CreateSessionDescriptionObserver* MakeCreateAndSetHandler() {
-    return new rtc::RefCountedObject<CreateAndSetHandler>(holder_);
-  }
-
-  void DisposeOnSignalingThread() {
-    DCHECK(signaling_thread_->IsCurrent());
-
-    CheckedRelease(&connection_);
-    holder_->Dispose();
-  }
-
-  void OnParseError(const webrtc::SdpParseError& error) {
-    // TODO(serya): Send on signaling thread.
-  }
-
-  SessionDependencyFactory* const factory_;
-  const rtc::scoped_refptr<PeerConnectionHolder> holder_;
-  rtc::Thread* const signaling_thread_;
-  rtc::scoped_refptr<webrtc::PeerConnectionInterface> connection_;
-  const scoped_ptr<PeerConnectionObserverImpl> observer_;
-  const scoped_ptr<AbstractPeerConnection::Delegate> delegate_;
-};
-
-class SessionDependencyFactoryImpl : public SessionDependencyFactory {
- public:
-  SessionDependencyFactoryImpl(
-      const base::Closure& cleanup_on_signaling_thread)
-      : cleanup_on_signaling_thread_(cleanup_on_signaling_thread) {
-    signaling_thread_.SetName("signaling_thread", NULL);
-    signaling_thread_.Start();
-    worker_thread_.SetName("worker_thread", NULL);
-    worker_thread_.Start();
-
-    factory_ = webrtc::CreatePeerConnectionFactory(
-        &worker_thread_, &signaling_thread_, NULL, NULL, NULL);
-  }
-
-  ~SessionDependencyFactoryImpl() override {
-    if (signaling_thread_task_runner_.get())
-      signaling_thread_task_runner_->Stop();
-
-    signaling_thread_.Invoke<void>(rtc::Bind(
-        &SessionDependencyFactoryImpl::DisposeOnSignalingThread, this));
-  }
-
-  scoped_ptr<AbstractPeerConnection> CreatePeerConnection(
-      scoped_ptr<RTCConfiguration> config,
-      scoped_ptr<AbstractPeerConnection::Delegate> delegate) override {
-    auto observer = make_scoped_ptr(
-        new PeerConnectionObserverImpl(delegate.get()));
-
-    MediaConstraints constraints;
-    constraints.AddMandatory(
-        MediaConstraints::kEnableDtlsSrtp, MediaConstraints::kValueTrue);
-
-    auto connection = factory_->CreatePeerConnection(
-        config->impl(), &constraints, NULL, NULL, observer.get());
-
-    return make_scoped_ptr(new PeerConnectionImpl(
-        this, &signaling_thread_, connection, observer.Pass(),
-        delegate.Pass()));
-  }
-
-  scoped_refptr<base::TaskRunner> signaling_thread_task_runner() override {
-    if (!signaling_thread_task_runner_.get()) {
-      signaling_thread_task_runner_ =
-          new SignalingThreadTaskRunner(&signaling_thread_);
-    }
-    return signaling_thread_task_runner_;
-  }
-
-  scoped_refptr<base::TaskRunner> io_thread_task_runner() override {
-    if (!io_thread_.get()) {
-      io_thread_.reset(new base::Thread("devtools bridge IO thread"));
-      base::Thread::Options options;
-      options.message_loop_type = base::MessageLoop::TYPE_IO;
-      CHECK(io_thread_->StartWithOptions(options));
-    }
-    return io_thread_->task_runner();
-  }
-
- private:
-  void DisposeOnSignalingThread() {
-    DCHECK(signaling_thread_.IsCurrent());
-    CheckedRelease(&factory_);
-    if (!cleanup_on_signaling_thread_.is_null())
-      cleanup_on_signaling_thread_.Run();
-  }
-
-  scoped_ptr<base::Thread> io_thread_;
-  scoped_refptr<SignalingThreadTaskRunner> signaling_thread_task_runner_;
-  base::Closure cleanup_on_signaling_thread_;
-  rtc::Thread signaling_thread_;
-  rtc::Thread worker_thread_;
-  rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface> factory_;
-};
-
-} // namespace
-
-// RTCCOnfiguration
-
-// static
-scoped_ptr<RTCConfiguration> RTCConfiguration::CreateInstance() {
-  return make_scoped_ptr(new RTCConfiguration::Impl());
-}
-
-// SessionDependencyFactory
-
-// static
-bool SessionDependencyFactory::InitializeSSL() {
-  return rtc::InitializeSSL();
-}
-
-// static
-bool SessionDependencyFactory::CleanupSSL() {
-  return rtc::CleanupSSL();
-}
-
-// static
-scoped_ptr<SessionDependencyFactory> SessionDependencyFactory::CreateInstance(
-    const base::Closure& cleanup_on_signaling_thread) {
-  return make_scoped_ptr(new SessionDependencyFactoryImpl(
-      cleanup_on_signaling_thread));
-}
-
-}  // namespace devtools_bridge
diff --git a/components/devtools_bridge/session_dependency_factory.h b/components/devtools_bridge/session_dependency_factory.h
deleted file mode 100644
index 23d7b03..0000000
--- a/components/devtools_bridge/session_dependency_factory.h
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_DEVTOOLS_BRIDGE_SESSION_DEPENDENCY_FACTORY_H_
-#define COMPONENTS_DEVTOOLS_BRIDGE_SESSION_DEPENDENCY_FACTORY_H_
-
-#include <string>
-
-#include "base/callback.h"
-#include "base/memory/scoped_ptr.h"
-#include "components/devtools_bridge/abstract_peer_connection.h"
-#include "components/devtools_bridge/rtc_configuration.h"
-
-namespace base {
-class TaskRunner;
-}
-
-namespace devtools_bridge {
-
-/**
- * Abstraction layer over WebRTC API used in DevTools Bridge.
- * It helps to isolate ref counting and threading logic needed.
- */
-class SessionDependencyFactory {
- public:
-  SessionDependencyFactory() {}
-  virtual ~SessionDependencyFactory() {}
-
-  static bool InitializeSSL();
-  static bool CleanupSSL();
-
-  static scoped_ptr<SessionDependencyFactory> CreateInstance(
-      const base::Closure& cleanup_on_signaling_thread);
-
-  virtual scoped_ptr<AbstractPeerConnection> CreatePeerConnection(
-      scoped_ptr<RTCConfiguration> config,
-      scoped_ptr<AbstractPeerConnection::Delegate> delegate) = 0;
-
-  virtual scoped_refptr<base::TaskRunner> signaling_thread_task_runner() = 0;
-  virtual scoped_refptr<base::TaskRunner> io_thread_task_runner() = 0;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(SessionDependencyFactory);
-};
-
-}  // namespace devtools_bridge
-
-#endif  // COMPONENTS_DEVTOOLS_BRIDGE_SESSION_DEPENDENCY_FACTORY_H_
diff --git a/components/devtools_bridge/socket_tunnel_connection.cc b/components/devtools_bridge/socket_tunnel_connection.cc
deleted file mode 100644
index 2c01aa2..0000000
--- a/components/devtools_bridge/socket_tunnel_connection.cc
+++ /dev/null
@@ -1,96 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/devtools_bridge/socket_tunnel_connection.h"
-
-#include <stdlib.h>
-
-#include "net/base/io_buffer.h"
-#include "net/base/net_errors.h"
-#include "net/socket/stream_socket.h"
-
-namespace devtools_bridge {
-
-SocketTunnelConnection::SocketTunnelConnection(int index) : index_(index) {
-}
-
-SocketTunnelConnection::~SocketTunnelConnection() {
-}
-
-void SocketTunnelConnection::Write(scoped_refptr<net::IOBufferWithSize> chunk) {
-  // TODO(serya): While it is unlikely (socket normally much faster than
-  // data channel) we should disconnect if too much data buffered.
-  buffer_.push_back(chunk);
-  if (buffer_.size() == 1) {
-    current_ = new net::DrainableIOBuffer(chunk.get(), chunk->size());
-    WriteCurrent();
-  }
-}
-
-void SocketTunnelConnection::BuildControlPacket(char* buffer,
-                                                int op_code) {
-  static_assert(kControlPacketSizeBytes == 3,
-                "kControlPacketSizeBytes should equal 3");
-  buffer[0] = kControlConnectionId;
-  buffer[1] = op_code;
-  buffer[2] = index_ + kMinConnectionId;
-}
-
-void SocketTunnelConnection::WriteCurrent() {
-  while (true) {
-    while(current_->BytesRemaining() > 0) {
-      int result = socket()->Write(current_.get(), current_->BytesRemaining(),
-          base::Bind(&SocketTunnelConnection::OnWriteComplete,
-                     base::Unretained(this)));
-      if (result > 0)
-        current_->DidConsume(result);
-    }
-    current_ = NULL;
-
-    buffer_.pop_front();
-    if (buffer_.empty())
-      return;  // Stop writing.
-
-    net::IOBufferWithSize* chunk = buffer_.front().get();
-    current_ = new net::DrainableIOBuffer(chunk, chunk->size());
-  }
-}
-
-void SocketTunnelConnection::OnWriteComplete(int result) {
-  if (result > 0) {
-    current_->DidConsume(result);
-    WriteCurrent();
-  }
-}
-
-void SocketTunnelConnection::ReadNextChunk() {
-  if (!read_buffer_.get()) {
-    read_buffer_ = new net::GrowableIOBuffer();
-    read_buffer_->SetCapacity(kMaxPacketSizeBytes);
-  }
-  // Header of the data packet.
-  *read_buffer_->StartOfBuffer() = index_ + kMinConnectionId;
-  read_buffer_->set_offset(1);
-
-  int result = socket()->Read(
-      read_buffer_.get(),
-      read_buffer_->RemainingCapacity(),
-      base::Bind(&SocketTunnelConnection::OnReadComplete,
-          base::Unretained(this)));
-  if (result == net::ERR_IO_PENDING)
-    return;
-  else
-    OnReadComplete(result);
-}
-
-void SocketTunnelConnection::OnReadComplete(int result) {
-  if (result > 0) {
-    OnDataPacketRead(read_buffer_->StartOfBuffer(),
-                     read_buffer_->offset() + result);
-  } else {
-    OnReadError(result);
-  }
-}
-
-}  // namespace devtools_bridge
diff --git a/components/devtools_bridge/socket_tunnel_connection.h b/components/devtools_bridge/socket_tunnel_connection.h
deleted file mode 100644
index c6638926..0000000
--- a/components/devtools_bridge/socket_tunnel_connection.h
+++ /dev/null
@@ -1,99 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_DEVTOOLS_BRIDGE_SOCKET_TUNNEL_CONNECTION_H_
-#define COMPONENTS_DEVTOOLS_BRIDGE_SOCKET_TUNNEL_CONNECTION_H_
-
-#include <deque>
-#include <string>
-
-#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
-
-namespace net {
-class DrainableIOBuffer;
-class GrowableIOBuffer;
-class IOBufferWithSize;
-class StreamSocket;
-}
-
-namespace devtools_bridge {
-
-/**
- * Abstract base class for SocketTunnelServer/Client connection.
- *
- * Connection binds a pair of net::StreamSocket (or alike) through
- * a data channel. SocketTunnel may handle up to kMaxConnectionCount
- * simultaneous connection (DevTools can keep ~10 connection;
- * other connections hang in unopened state; additional connections
- * could help to deal with data channel latency).
- *
- * Client should create net::StreamListenSocket (or logical equivalent)
- * and listen for incoming connection. When one comes it sends CLIENT_OPEN
- * packet to the server.
- *
- * Server transforms client's packet to calls of net::StreamSocket. On
- * CLIENT_OPEN it creates a socket and connects. If connection succeeds
- * it sends back SERVER_OPEN_ACK. If it fails it sends SERVER_CLOSE.
- *
- * After SERVER_OPEN_ACK server may send SERVER_CLOSE any time (if the socket
- * it connects to has closed on another side). If client closes the connection
- * sending CLIENT_CLOSE server acknowledges it by sending SERVER_CLOSE.
- * Client may reuse connection ID once it received SERVER_CLOSE (because
- * data channel is ordered and reliable).
- */
-class SocketTunnelConnection {
- public:
-  enum ClientOpCode {
-    CLIENT_OPEN = 0,
-    CLIENT_CLOSE = 1
-  };
-
-  enum ServerOpCode {
-    SERVER_OPEN_ACK = 0,
-    SERVER_CLOSE = 1
-  };
-
-  static const int kMaxConnectionCount = 64;
-
-  static const int kMaxPacketSizeBytes = 1024 * 4;
-  static const int kControlPacketSizeBytes = 3;
-
-  static const int kControlConnectionId = 0;
-
-  static const int kMinConnectionId = 1;
-  static const int kMaxConnectionId =
-      kMinConnectionId + kMaxConnectionCount - 1;
-
-  void Write(scoped_refptr<net::IOBufferWithSize> chunk);
-  void ReadNextChunk();
-
- protected:
-  SocketTunnelConnection(int index);
-  ~SocketTunnelConnection();
-
-  const int index_;
-
-  // |buffer| length must be kControlPacketSizeBytes.
-  void BuildControlPacket(char* buffer, int op_code);
-
-  virtual net::StreamSocket* socket() = 0;
-  virtual void OnDataPacketRead(const void* data, size_t length) = 0;
-  virtual void OnReadError(int error) = 0;
-
- private:
-  void WriteCurrent();
-  void OnWriteComplete(int result);
-  void OnReadComplete(int result);
-
-  std::deque<scoped_refptr<net::IOBufferWithSize> > buffer_;
-  scoped_refptr<net::DrainableIOBuffer> current_;
-  scoped_refptr<net::GrowableIOBuffer> read_buffer_;
-
-  DISALLOW_COPY_AND_ASSIGN(SocketTunnelConnection);
-};
-
-}  // namespace devtools_bridge
-
-#endif  // COMPONENTS_DEVTOOLS_BRIDGE_SOCKET_TUNNEL_CONNECTION_H_
diff --git a/components/devtools_bridge/socket_tunnel_packet_handler.cc b/components/devtools_bridge/socket_tunnel_packet_handler.cc
deleted file mode 100644
index ea609ae..0000000
--- a/components/devtools_bridge/socket_tunnel_packet_handler.cc
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/devtools_bridge/socket_tunnel_packet_handler.h"
-
-#include <stdlib.h>
-
-#include "components/devtools_bridge/socket_tunnel_connection.h"
-#include "net/base/io_buffer.h"
-#include "net/base/net_errors.h"
-
-namespace devtools_bridge {
-
-static const int kControlConnectionId =
-    SocketTunnelConnection::kControlConnectionId;
-static const int kMinConnectionId = SocketTunnelConnection::kMinConnectionId;
-static const int kMaxConnectionId = SocketTunnelConnection::kMaxConnectionId;
-static const int kControlPacketSizeBytes =
-    SocketTunnelConnection::kControlPacketSizeBytes;
-
-void SocketTunnelPacketHandler::DecodePacket(const void* data, size_t length) {
-  const unsigned char* bytes = static_cast<const unsigned char*>(data);
-  if (length == 0) {
-    DLOG(ERROR) << "Empty packet";
-    HandleProtocolError();
-    return;
-  }
-  int connection_id = bytes[0];
-  if (connection_id != kControlConnectionId) {
-    if (connection_id < kMinConnectionId ||
-        connection_id > kMaxConnectionId) {
-      DLOG(ERROR) << "Invalid connection ID: " << connection_id;
-      HandleProtocolError();
-      return;
-    }
-
-    int connection_index = connection_id - kMinConnectionId;
-    scoped_refptr<net::IOBufferWithSize> packet(
-        new net::IOBufferWithSize(length - 1));
-    memcpy(packet->data(), bytes + 1, length - 1);
-    HandleDataPacket(connection_index, packet);
-  } else if (length >= kControlPacketSizeBytes) {
-    static_assert(kControlPacketSizeBytes == 3,
-                  "kControlPacketSizeBytes should equal 3");
-
-    int op_code = bytes[1];
-    connection_id = bytes[2];
-    if (connection_id < kMinConnectionId ||
-        connection_id > kMaxConnectionId) {
-      DLOG(ERROR) << "Invalid connection ID: " << connection_id;
-      HandleProtocolError();
-      return;
-    }
-    int connection_index = connection_id - kMinConnectionId;
-    HandleControlPacket(connection_index, op_code);
-  } else {
-    DLOG(ERROR) << "Invalid packet";
-    HandleProtocolError();
-    return;
-  }
-}
-
-}  // namespace devtools_bridge
diff --git a/components/devtools_bridge/socket_tunnel_packet_handler.h b/components/devtools_bridge/socket_tunnel_packet_handler.h
deleted file mode 100644
index dc64f30..0000000
--- a/components/devtools_bridge/socket_tunnel_packet_handler.h
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_DEVTOOLS_BRIDGE_SOCKET_TUNNEL_PACKET_HANDLER_H_
-#define COMPONENTS_DEVTOOLS_BRIDGE_SOCKET_TUNNEL_PACKET_HANDLER_H_
-
-#include "base/memory/ref_counted.h"
-
-namespace net {
-class IOBufferWithSize;
-}
-
-namespace devtools_bridge {
-
-/**
- * Abstract base class for handling SocketTunnelServer/Client messages.
- */
-class SocketTunnelPacketHandler {
- public:
-  virtual void HandleControlPacket(int connection_index, int op_code) = 0;
-  virtual void HandleDataPacket(
-      int connection_index, scoped_refptr<net::IOBufferWithSize> data) = 0;
-  virtual void HandleProtocolError() = 0;
-
-  void DecodePacket(const void* data, size_t length);
-
- protected:
-  SocketTunnelPacketHandler() {}
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(SocketTunnelPacketHandler);
-};
-
-}  // namespace devtools_bridge
-
-#endif  // COMPONENTS_DEVTOOLS_BRIDGE_SOCKET_TUNNEL_PACKET_HANDLER_H_
diff --git a/components/devtools_bridge/socket_tunnel_server.cc b/components/devtools_bridge/socket_tunnel_server.cc
deleted file mode 100644
index afa07a2..0000000
--- a/components/devtools_bridge/socket_tunnel_server.cc
+++ /dev/null
@@ -1,266 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/devtools_bridge/socket_tunnel_server.h"
-
-#include "base/bind.h"
-#include "base/location.h"
-#include "components/devtools_bridge/abstract_data_channel.h"
-#include "components/devtools_bridge/session_dependency_factory.h"
-#include "components/devtools_bridge/socket_tunnel_connection.h"
-#include "components/devtools_bridge/socket_tunnel_packet_handler.h"
-#include "net/base/io_buffer.h"
-#include "net/base/net_errors.h"
-#include "net/socket/unix_domain_client_socket_posix.h"
-
-namespace devtools_bridge {
-
-class SocketTunnelServer::Connection : public SocketTunnelConnection {
- public:
-  class Delegate {
-   public:
-    virtual void RemoveConnection(int index) = 0;
-    virtual void SendPacket(
-        const void* data, size_t length) = 0;
-  };
-
-  Connection(Delegate* delegate, int index, const std::string& socket_name)
-      : SocketTunnelConnection(index),
-        delegate_(delegate),
-        socket_(socket_name, true) {
-  }
-
-  void Connect() {
-    int result = socket()->Connect(base::Bind(
-        &Connection::OnConnectionComplete, base::Unretained(this)));
-    if (result != net::ERR_IO_PENDING)
-      OnConnectionComplete(result);
-  }
-
-  void ClosedByClient() {
-    if (socket()->IsConnected()) {
-      socket()->Disconnect();
-      SendControlPacket(SERVER_CLOSE);
-    }
-    delegate_->RemoveConnection(index_);
-  }
-
- protected:
-  net::StreamSocket* socket() override {
-    return &socket_;
-  }
-
-  void OnDataPacketRead(const void* data, size_t length) override {
-    delegate_->SendPacket(data, length);
-    ReadNextChunk();
-  }
-
-  void OnReadError(int error) override {
-    socket()->Disconnect();
-    SendControlPacket(SERVER_CLOSE);
-    delegate_->RemoveConnection(index_);
-    delegate_ = NULL;
-  }
-
- private:
-  void OnConnectionComplete(int result) {
-    if (result == net::OK) {
-      SendControlPacket(SERVER_OPEN_ACK);
-      ReadNextChunk();
-    } else {
-      SendControlPacket(SERVER_CLOSE);
-      delegate_->RemoveConnection(index_);
-      delegate_ = NULL;
-    }
-  }
-
-  void SendControlPacket(ServerOpCode op_code) {
-    char buffer[kControlPacketSizeBytes];
-    BuildControlPacket(buffer, op_code);
-    delegate_->SendPacket(buffer, kControlPacketSizeBytes);
-  }
-
-  Delegate* delegate_;
-  net::UnixDomainClientSocket socket_;
-};
-
-/**
- * Lives on the IO thread.
- */
-class SocketTunnelServer::ConnectionController
-    : private Connection::Delegate {
- public:
-  ConnectionController(
-      scoped_refptr<base::TaskRunner> io_task_runner,
-      scoped_refptr<AbstractDataChannel::Proxy> data_channel,
-      const std::string& socket_name)
-      : io_task_runner_(io_task_runner),
-        data_channel_(data_channel),
-        socket_name_(socket_name) {
-    DCHECK(data_channel_.get());
-  }
-
-  void HandleControlPacket(int connection_index, int op_code) {
-    DCHECK(connection_index < kMaxConnectionCount);
-    switch (op_code) {
-      case SocketTunnelConnection::CLIENT_OPEN:
-        if (connections_[connection_index].get() != NULL) {
-          DLOG(ERROR) << "Opening connection which already open: "
-                      << connection_index;
-          HandleProtocolError();
-          return;
-        }
-        connections_[connection_index].reset(
-            new Connection(this, connection_index, socket_name_));
-        connections_[connection_index]->Connect();
-        break;
-
-      case SocketTunnelConnection::CLIENT_CLOSE:
-        if (connections_[connection_index].get() == NULL) {
-          // Ignore. Client may close the connection before received
-          // notification from the server.
-          return;
-        }
-        connections_[connection_index]->ClosedByClient();
-        break;
-
-      default:
-        DLOG(ERROR) << "Invalid op_code: " << op_code;
-        HandleProtocolError();
-        return;
-    }
-  }
-
-  void HandleDataPacket(int connection_index,
-                        scoped_refptr<net::IOBufferWithSize> packet) {
-    Connection* connection = connections_[connection_index].get();
-    if (connection != NULL)
-      connection->Write(packet);
-  }
-
-  void HandleProtocolError() {
-    data_channel_->Close();
-  }
-
-  void CloseAllConnections() {
-    for (int i = 0; i < kMaxConnectionCount; i++) {
-      connections_[i].reset();
-    }
-  }
-
- private:
-  static void DeleteConnectionImpl(Connection*) {}
-
-  // Connection::Delegate implementation
-  void RemoveConnection(int connection_index) override {
-    // Remove immediately, delete later to preserve this of the caller.
-    Connection* connection = connections_[connection_index].release();
-    io_task_runner_->PostTask(
-        FROM_HERE, base::Bind(&ConnectionController::DeleteConnectionImpl,
-                              base::Owned(connection)));
-  }
-
-  void SendPacket(const void* data, size_t length) override {
-    data_channel_->SendBinaryMessage(data, length);
-  }
-
-  static const int kMaxConnectionCount =
-      SocketTunnelConnection::kMaxConnectionCount;
-
-  scoped_refptr<base::TaskRunner> io_task_runner_;
-  scoped_refptr<AbstractDataChannel::Proxy> data_channel_;
-  scoped_ptr<Connection> connections_[kMaxConnectionCount];
-  const std::string socket_name_;
-};
-
-class SocketTunnelServer::DataChannelObserver
-    : public AbstractDataChannel::Observer,
-      private SocketTunnelPacketHandler {
- public:
-  DataChannelObserver(scoped_refptr<base::TaskRunner> io_task_runner,
-                      scoped_ptr<ConnectionController> controller)
-      : io_task_runner_(io_task_runner),
-        controller_(controller.Pass()) {
-  }
-
-  ~DataChannelObserver() override {
-    // Deleting on IO thread allows post tasks with base::Unretained
-    // because all of them will be processed before deletion.
-    io_task_runner_->PostTask(
-        FROM_HERE, base::Bind(&DataChannelObserver::DeleteControllerOnIOThread,
-                              base::Passed(&controller_)));
-  }
-
-  void OnOpen() override {
-    // Nothing to do. Activity could only be initiated by a control packet.
-  }
-
-  void OnClose() override {
-    io_task_runner_->PostTask(
-        FROM_HERE, base::Bind(
-            &ConnectionController::CloseAllConnections,
-            base::Unretained(controller_.get())));
-  }
-
-  void OnMessage(const void* data, size_t length) override {
-    DecodePacket(data, length);
-  }
-
- private:
-  static void DeleteControllerOnIOThread(
-      scoped_ptr<ConnectionController> controller) {}
-
-  // SocketTunnelPacketHandler implementation.
-
-  void HandleControlPacket(int connection_index, int op_code) override {
-    io_task_runner_->PostTask(
-        FROM_HERE, base::Bind(
-            &ConnectionController::HandleControlPacket,
-            base::Unretained(controller_.get()),
-            connection_index,
-            op_code));
-  }
-
-  void HandleDataPacket(int connection_index,
-                        scoped_refptr<net::IOBufferWithSize> data) override {
-    io_task_runner_->PostTask(
-        FROM_HERE, base::Bind(
-            &ConnectionController::HandleDataPacket,
-            base::Unretained(controller_.get()),
-            connection_index,
-            data));
-  }
-
-  void HandleProtocolError() override {
-      io_task_runner_->PostTask(
-          FROM_HERE, base::Bind(
-              &ConnectionController::HandleProtocolError,
-              base::Unretained(controller_.get())));
-  }
-
-  const scoped_refptr<base::TaskRunner> io_task_runner_;
-  scoped_ptr<ConnectionController> controller_;
-};
-
-SocketTunnelServer::SocketTunnelServer(SessionDependencyFactory* factory,
-                                       AbstractDataChannel* data_channel,
-                                       const std::string& socket_name)
-    : data_channel_(data_channel) {
-  scoped_ptr<ConnectionController> controller(
-      new ConnectionController(factory->io_thread_task_runner(),
-                               data_channel->proxy(),
-                               socket_name));
-
-  scoped_ptr<DataChannelObserver> data_channel_observer(
-      new DataChannelObserver(factory->io_thread_task_runner(),
-                              controller.Pass()));
-
-  data_channel_->RegisterObserver(data_channel_observer.Pass());
-}
-
-SocketTunnelServer::~SocketTunnelServer() {
-  data_channel_->UnregisterObserver();
-}
-
-}  // namespace devtools_bridge
diff --git a/components/devtools_bridge/socket_tunnel_server.h b/components/devtools_bridge/socket_tunnel_server.h
deleted file mode 100644
index 1dd3f4c..0000000
--- a/components/devtools_bridge/socket_tunnel_server.h
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_DEVTOOLS_BRIDGE_SOCKET_TUNNEL_SERVER_H_
-#define COMPONENTS_DEVTOOLS_BRIDGE_SOCKET_TUNNEL_SERVER_H_
-
-#include <map>
-#include <string>
-
-#include "base/memory/scoped_ptr.h"
-
-namespace net {
-class StreamSocket;
-}
-
-namespace devtools_bridge {
-
-class AbstractDataChannel;
-class SessionDependencyFactory;
-
-class SocketTunnelServer {
- public:
-  SocketTunnelServer(SessionDependencyFactory* factory,
-                     AbstractDataChannel* data_channel,
-                     const std::string& socket_name);
-  ~SocketTunnelServer();
-
- private:
-  class Connection;
-  class ConnectionController;
-  class DataChannelObserver;
-
-  AbstractDataChannel* const data_channel_;
-
-  DISALLOW_COPY_AND_ASSIGN(SocketTunnelServer);
-};
-
-}  // namespace devtools_bridge
-
-#endif  // COMPONENTS_DEVTOOLS_BRIDGE_SOCKET_TUNNEL_SERVER_H_
diff --git a/components/devtools_bridge/test/android/javatests/jni/jni_onload.cc b/components/devtools_bridge/test/android/javatests/jni/jni_onload.cc
deleted file mode 100644
index 4238dec..0000000
--- a/components/devtools_bridge/test/android/javatests/jni/jni_onload.cc
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/android/base_jni_onload.h"
-#include "base/android/base_jni_registrar.h"
-#include "base/android/jni_android.h"
-#include "base/bind.h"
-#include "components/devtools_bridge/android/apiary_client_factory.h"
-#include "components/devtools_bridge/android/session_dependency_factory_android.h"
-
-namespace {
-
-using namespace devtools_bridge::android;
-
-bool RegisterJNI(JNIEnv* env) {
-  return base::android::RegisterJni(env) &&
-      SessionDependencyFactoryAndroid::RegisterNatives(env) &&
-      ApiaryClientFactory::RegisterNatives(env);
-}
-
-bool Init() {
-  return devtools_bridge::SessionDependencyFactory::InitializeSSL();
-}
-
-}  // namespace
-
-JNI_EXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
-  std::vector<base::android::RegisterCallback> register_callbacks;
-  register_callbacks.push_back(base::Bind(&RegisterJNI));
-  std::vector<base::android::InitCallback> init_callbacks;
-  init_callbacks.push_back(base::Bind(&Init));
-  if (!base::android::OnJNIOnLoadRegisterJNI(vm, register_callbacks) ||
-      !base::android::OnJNIOnLoadInit(init_callbacks)) {
-    return -1;
-  }
-  return JNI_VERSION_1_4;
-}
diff --git a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/ClientSession.java b/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/ClientSession.java
deleted file mode 100644
index dfc16484..0000000
--- a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/ClientSession.java
+++ /dev/null
@@ -1,248 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge;
-
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Client session. Creates client socket tunnel for clientSocketName as a default tunnel.
- * See SessionBase for details.
- */
-public class ClientSession extends SessionBase {
-    private final ServerSessionInterface mServer;
-    private RTCConfiguration mConfig;
-    private Cancellable mIceExchangeTask;
-    private boolean mIceExchangeRequested = false;
-    private IceExchangeHandler mPendingIceExchangeRequest;
-
-    private int mExchangeDelayMs = -1;
-
-    protected int mInitialIceExchangeDelayMs = 200;
-    protected int mMaxIceExchangeDelayMs = 5000;
-
-    private final Map<Integer, SocketTunnelClient> mPendingTunnel =
-            new HashMap<Integer, SocketTunnelClient>();
-
-    public ClientSession(SessionDependencyFactory factory,
-                         Executor executor,
-                         ServerSessionInterface server,
-                         String clientSocketName) throws IOException {
-        super(factory, executor, new SocketTunnelClient(clientSocketName));
-        mServer = server;
-    }
-
-    public void start(RTCConfiguration config) {
-        checkCalledOnSessionThread();
-
-        super.start(config, new ServerMessageHandler());
-        mConfig = config;
-
-        for (Map.Entry<Integer, SocketTunnelClient> entry : mPendingTunnel.entrySet()) {
-            int channelId = entry.getKey();
-            entry.getValue().bind(connection().createDataChannel(channelId));
-        }
-
-        connection().createAndSetLocalDescription(
-                AbstractPeerConnection.SessionDescriptionType.OFFER);
-    }
-
-    @Override
-    public void stop() {
-        for (SocketTunnelClient tunnel : mPendingTunnel.values())
-            tunnel.unbind().dispose();
-
-        if (mIceExchangeTask != null)
-            mIceExchangeTask.cancel();
-
-        super.stop();
-    }
-
-    @Override
-    protected void onLocalDescriptionCreatedAndSet(
-            AbstractPeerConnection.SessionDescriptionType type, String offer) {
-        assert type == AbstractPeerConnection.SessionDescriptionType.OFFER;
-        mServer.startSession(mConfig, offer, new CreateSessionHandler());
-        mConfig = null;
-    }
-
-    private void onAnswerReceived(String answer) {
-        connection().setRemoteDescription(
-                AbstractPeerConnection.SessionDescriptionType.ANSWER, answer);
-    }
-
-    @Override
-    protected void onRemoteDescriptionSet() {
-        onSessionNegotiated();
-    }
-
-    protected void onSessionNegotiated() {
-        assert !isIceExchangeStarted();
-        updateIceExchangeStatus();
-        assert isIceExchangeStarted();
-    }
-
-    @Override
-    protected void onControlChannelOpened() {
-        assert isIceExchangeStarted();
-        updateIceExchangeStatus();
-    }
-
-    @Override
-    protected void onIceConnectionChange() {
-        super.onIceConnectionChange();
-        updateIceExchangeStatus();
-    }
-
-    private void updateIceExchangeStatus() {
-        boolean needed = !isConnected() || !isControlChannelOpened();
-        if (needed == isIceExchangeStarted())
-            return;
-        if (needed)
-            startIceExchange();
-        else
-            stopIceExchange();
-    }
-
-    private boolean isIceExchangeStarted() {
-        return mExchangeDelayMs >= 0;
-    }
-
-    private void startIceExchange() {
-        assert !isIceExchangeStarted();
-        mExchangeDelayMs = mInitialIceExchangeDelayMs;
-        startAutoCloseTimer();
-
-        if (!isIceExchangeScheduledOrPending()) {
-            scheduleIceExchange(mExchangeDelayMs);
-        }
-
-        assert isIceExchangeScheduledOrPending();
-        assert isIceExchangeStarted();
-    }
-
-    private void stopIceExchange() {
-        assert isIceExchangeStarted();
-        mExchangeDelayMs = -1;
-        stopAutoCloseTimer();
-
-        // Last exchange will happen, not more will be scheduled (unless mIceExchangeRequested).
-        assert isIceExchangeScheduledOrPending();
-        assert !isIceExchangeStarted();
-    }
-
-    private void scheduleIceExchange(int delay) {
-        assert mIceExchangeTask == null;
-        mIceExchangeTask = postOnSessionThread(delay, new Runnable() {
-            @Override
-            public void run() {
-                mIceExchangeTask = null;
-
-                mServer.iceExchange(takeIceCandidates(), new IceExchangeHandler());
-                mIceExchangeRequested = false;
-            }
-        });
-    }
-
-    private boolean isIceExchangeScheduledOrPending() {
-        return mIceExchangeTask != null || mPendingIceExchangeRequest != null;
-    }
-
-    private void onServerCandidates(List<String> serverCandidates) {
-        addIceCandidates(serverCandidates);
-
-        if (isIceExchangeStarted()) {
-            mExchangeDelayMs *= 2;
-            if (mExchangeDelayMs > mMaxIceExchangeDelayMs) {
-                mExchangeDelayMs = mMaxIceExchangeDelayMs;
-            }
-
-            scheduleIceExchange(mExchangeDelayMs);
-        } else if (mIceExchangeRequested) {
-            scheduleIceExchange(mInitialIceExchangeDelayMs);
-        }
-    }
-
-    /**
-     * Queries single ICE eqchange cycle regardless of ICE exchange process.
-     */
-    private void queryIceExchange() {
-        mIceExchangeRequested = true;
-        if (mIceExchangeTask == null && mPendingIceExchangeRequest != null) {
-            assert !isIceExchangeStarted();
-            scheduleIceExchange(mInitialIceExchangeDelayMs);
-        }
-    }
-
-    private final class CreateSessionHandler implements NegotiationCallback {
-        @Override
-        public void onSuccess(String answer) {
-            checkCalledOnSessionThread();
-
-            onAnswerReceived(answer);
-        }
-
-        @Override
-        public void onFailure(String message) {
-            checkCalledOnSessionThread();
-
-            ClientSession.this.onFailure(message);
-        }
-    }
-
-    private final class IceExchangeHandler implements IceExchangeCallback {
-        public IceExchangeHandler() {
-            assert mPendingIceExchangeRequest == null;
-            mPendingIceExchangeRequest = this;
-        }
-
-        @Override
-        public void onSuccess(List<String> serverCandidates) {
-            checkCalledOnSessionThread();
-
-            mPendingIceExchangeRequest = null;
-            if (isStarted()) {
-                onServerCandidates(serverCandidates);
-            }
-        }
-
-        @Override
-        public void onFailure(String message) {
-            checkCalledOnSessionThread();
-
-            mPendingIceExchangeRequest = null;
-            if (isStarted()) {
-                ClientSession.this.onFailure(message);
-            }
-        }
-    }
-
-    private final class ServerMessageHandler extends SessionControlMessages.ServerMessageHandler {
-        @Override
-        protected void onMessage(SessionControlMessages.ServerMessage message) {
-            switch (message.type) {
-                case ICE_EXCHANGE:
-                    queryIceExchange();
-                    break;
-
-                case UNKNOWN_RESPONSE:
-                    onUnknownResponse((SessionControlMessages.UnknownResponseMessage) message);
-                    break;
-            }
-        }
-    }
-
-    private void onUnknownResponse(SessionControlMessages.UnknownResponseMessage message) {
-        // TODO(serya): Handle server version incompatibility.
-    }
-
-    @Override
-    protected void sendControlMessage(SessionControlMessages.Message<?> message) {
-        assert message instanceof SessionControlMessages.ClientMessage;
-        super.sendControlMessage(message);
-    }
-}
diff --git a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/ClientSessionTestingHost.java b/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/ClientSessionTestingHost.java
deleted file mode 100644
index 441353a8..0000000
--- a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/ClientSessionTestingHost.java
+++ /dev/null
@@ -1,91 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge;
-
-import android.util.Log;
-
-import java.io.IOException;
-
-/**
- * Helper class which handles a client session in tests. Having direct reference to
- * the server it runs its client session on a dedicated thread and proxies all call
- * between them to satisfy theading requirements.
- */
-public class ClientSessionTestingHost {
-    private static final String TAG = "ClientSessionTestingHost";
-
-    private final SignalingReceiver mTarget;
-    private final SessionBase.Executor mTargetExecutor;
-    private final LocalSessionBridge.ThreadedExecutor mClientExecutor;
-    private final String mSessionId;
-    private final ClientSession mClientSession;
-
-    public ClientSessionTestingHost(
-            SessionDependencyFactory factory,
-            SignalingReceiver target, SessionBase.Executor targetExecutor,
-            String sessionId, String clientSocketName)
-            throws IOException {
-        mTarget = target;
-        mTargetExecutor = targetExecutor;
-        mClientExecutor = new LocalSessionBridge.ThreadedExecutor();
-
-        mSessionId = sessionId;
-
-        SignalingReceiverProxy proxy = new SignalingReceiverProxy(
-                mTargetExecutor, mClientExecutor, target, 0);
-
-        mClientSession = new ClientSession(
-                factory,
-                mClientExecutor,
-                proxy.asServerSession(mSessionId),
-                clientSocketName) {
-            @Override
-            protected void closeSelf() {
-                Log.d(TAG, "Closed self");
-                super.closeSelf();
-            }
-
-            @Override
-            protected void onControlChannelOpened() {
-                Log.d(TAG, "Control channel opened");
-                super.onControlChannelOpened();
-            }
-
-            @Override
-            protected void onControlChannelClosed() {
-                Log.d(TAG, "Control channel closed");
-                super.onControlChannelClosed();
-            }
-
-            @Override
-            protected void onFailure(String message) {
-                Log.e(TAG, "Failure: " + message);
-                super.onFailure(message);
-            }
-        };
-    }
-
-    public void dispose() {
-        mClientExecutor.runSynchronously(new Runnable() {
-            @Override
-            public void run() {
-                mClientSession.dispose();
-            }
-        });
-    }
-
-    public void start() {
-        start(new RTCConfiguration());
-    }
-
-    public void start(final RTCConfiguration config) {
-        mClientExecutor.runSynchronously(new Runnable() {
-            @Override
-            public void run() {
-                mClientSession.start(config);
-            }
-        });
-    }
-}
diff --git a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/DataChannelMock.java b/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/DataChannelMock.java
deleted file mode 100644
index 59a1679..0000000
--- a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/DataChannelMock.java
+++ /dev/null
@@ -1,135 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge;
-
-import junit.framework.Assert;
-
-import java.nio.ByteBuffer;
-import java.util.concurrent.LinkedBlockingQueue;
-
-/**
- * Mock of AbstractDataChannel tests. Also base class for DataPipe channels.
- */
-public class DataChannelMock extends AbstractDataChannel {
-    private final SignalingThreadMock mSignalingThread;
-    private Observer mObserver;
-    private boolean mOpen = false;
-    private final LinkedBlockingQueue<ByteBuffer> mQueue = new LinkedBlockingQueue<ByteBuffer>();
-
-    // |signalingThread| will be disposed in the |dispose| method. If successor needs
-    // to control it's lifetime it must override |disposeSignalingThread| and not to invoke super's
-    // implementation.
-    protected DataChannelMock(SignalingThreadMock signalingThread) {
-        mSignalingThread = signalingThread;
-    }
-
-    public DataChannelMock() {
-        this(new SignalingThreadMock());
-    }
-
-    public void open() {
-        onStateChange(AbstractDataChannel.State.OPEN);
-    }
-
-    @Override
-    public void close() {
-        onStateChange(AbstractDataChannel.State.CLOSED);
-    }
-
-    private void onStateChange(final State state) {
-        mSignalingThread.invoke(new Runnable() {
-            @Override
-            public void run() {
-                mObserver.onStateChange(state);
-            }
-        });
-    }
-
-    // Sends onMessage to the observer.
-    public void notifyMessage(ByteBuffer data) {
-        final byte[] bytes = toByteArray(data);
-        mSignalingThread.invoke(new Runnable() {
-            @Override
-            public void run() {
-                notifyMessageOnSignalingThread(ByteBuffer.wrap(bytes));
-            }
-        });
-    }
-
-    protected void notifyMessageOnSignalingThread(ByteBuffer buffer) {
-        mObserver.onMessage(buffer);
-    }
-
-    // Blocks until message received. Removes it from the queue and returns.
-    public ByteBuffer receive() {
-        try {
-            return mQueue.take();
-        } catch (InterruptedException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    @Override
-    public void registerObserver(final Observer observer) {
-        mSignalingThread.invoke(new Runnable() {
-            @Override
-            public void run() {
-                Assert.assertNull(mObserver);
-                mObserver = observer;
-                Assert.assertNotNull(mObserver);
-            }
-        });
-    }
-
-    @Override
-    public void unregisterObserver() {
-        mSignalingThread.invoke(new Runnable() {
-            @Override
-            public void run() {
-                Assert.assertNotNull(mObserver);
-                mObserver = null;
-            }
-        });
-    }
-
-    private byte[] toByteArray(ByteBuffer data) {
-        final byte[] result = new byte[data.remaining()];
-        data.get(result);
-        return result;
-    }
-
-    @Override
-    public void send(ByteBuffer message, MessageType type) {
-        final byte[] data = toByteArray(message);
-        assert data.length > 0;
-        mSignalingThread.post(new Runnable() {
-            @Override
-            public void run() {
-                sendOnSignalingThread(ByteBuffer.wrap(data));
-                android.util.Log.d("DataChannelMock", "Packet sent.");
-            }
-        });
-    }
-
-    protected void sendOnSignalingThread(ByteBuffer message) {
-        boolean success = mQueue.offer(message);
-        assert success;
-    }
-
-    @Override
-    public void dispose() {
-        mSignalingThread.invoke(new Runnable() {
-            @Override
-            public void run() {
-                Assert.assertNull(mObserver);
-            }
-        });
-        disposeSignalingThread();
-    }
-
-    protected void disposeSignalingThread() {
-        mSignalingThread.dispose();
-    }
-}
diff --git a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/DataChannelObserverMock.java b/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/DataChannelObserverMock.java
deleted file mode 100644
index 68972da..0000000
--- a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/DataChannelObserverMock.java
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge;
-
-import java.nio.ByteBuffer;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.LinkedBlockingDeque;
-
-/**
- * Mock for AbstractDataChannel.Observer.
- */
-public class DataChannelObserverMock implements AbstractDataChannel.Observer {
-    public final CountDownLatch opened = new CountDownLatch(1);
-    public final CountDownLatch closed = new CountDownLatch(1);
-    public final LinkedBlockingDeque<byte[]> received = new LinkedBlockingDeque<byte[]>();
-
-    public void onStateChange(AbstractDataChannel.State state) {
-        switch (state) {
-            case OPEN:
-                opened.countDown();
-                break;
-
-            case CLOSED:
-                closed.countDown();
-                break;
-        }
-    }
-
-    public void onMessage(ByteBuffer message) {
-        byte[] bytes = new byte[message.remaining()];
-        message.get(bytes);
-        received.add(bytes);
-    }
-}
diff --git a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/DataPipe.java b/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/DataPipe.java
deleted file mode 100644
index 7283047..0000000
--- a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/DataPipe.java
+++ /dev/null
@@ -1,120 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge;
-
-import java.nio.ByteBuffer;
-
-/**
- * Represents a pair of connected AbstractDataChannel's. Sends to one channel
- * come to another and vice versa.
- */
-public class DataPipe {
-    private static final int DATA_CHANNEL_ID = 0;
-
-    final PeerConnectionObserverMock mObserver1 = new PeerConnectionObserverMock();
-    final PeerConnectionObserverMock mObserver2 = new PeerConnectionObserverMock();
-
-    DataChannelObserverMock mDataChannelObserverMock1 = new DataChannelObserverMock();
-    DataChannelObserverMock mDataChannelObserverMock2 = new DataChannelObserverMock();
-
-    final AbstractPeerConnection mConnection1;
-    final AbstractPeerConnection mConnection2;
-
-    final AbstractDataChannel mDataChannel1;
-    final AbstractDataChannel mDataChannel2;
-
-    DataPipe(SessionDependencyFactory factory) {
-        RTCConfiguration config = new RTCConfiguration();
-        mConnection1 = factory.createPeerConnection(config, mObserver1);
-        mConnection2 = factory.createPeerConnection(config, mObserver2);
-
-        mObserver1.iceCandidatesSink = mConnection2;
-        mObserver2.iceCandidatesSink = mConnection1;
-
-        mDataChannel1 = mConnection1.createDataChannel(DATA_CHANNEL_ID);
-        mDataChannel2 = mConnection2.createDataChannel(DATA_CHANNEL_ID);
-    }
-
-    void dispose() {
-        mDataChannel1.dispose();
-        mDataChannel2.dispose();
-        mConnection1.dispose();
-        mConnection2.dispose();
-    }
-
-    void negotiate() throws Exception {
-        mConnection1.createAndSetLocalDescription(
-                AbstractPeerConnection.SessionDescriptionType.OFFER);
-        mObserver1.localDescriptionAvailable.await();
-
-        mConnection2.setRemoteDescription(
-                AbstractPeerConnection.SessionDescriptionType.OFFER,
-                mObserver1.localDescription);
-        mObserver2.remoteDescriptionSet.await();
-
-        mConnection2.createAndSetLocalDescription(
-                AbstractPeerConnection.SessionDescriptionType.ANSWER);
-        mObserver2.localDescriptionAvailable.await();
-
-        mConnection1.setRemoteDescription(
-                AbstractPeerConnection.SessionDescriptionType.ANSWER,
-                mObserver2.localDescription);
-        mObserver1.remoteDescriptionSet.await();
-    }
-
-    void awaitConnected() throws Exception {
-        mObserver1.connected.await();
-        mObserver2.connected.await();
-    }
-
-    void send(int channelIndex, String data) {
-        byte[] bytes = data.getBytes();
-        ByteBuffer rawMessage = ByteBuffer.allocateDirect(bytes.length);
-        rawMessage.put(bytes);
-        rawMessage.limit(rawMessage.position());
-        rawMessage.position(0);
-        dataChannel(channelIndex).send(rawMessage, AbstractDataChannel.MessageType.TEXT);
-    }
-
-    void send(int channelIndex, ByteBuffer rawMessage) {
-        dataChannel(channelIndex).send(rawMessage, AbstractDataChannel.MessageType.BINARY);
-    }
-
-    AbstractDataChannel dataChannel(int channelIndex) {
-        switch (channelIndex) {
-            case 0:
-                return mDataChannel1;
-
-            case 1:
-                return mDataChannel2;
-
-            default:
-                throw new ArrayIndexOutOfBoundsException();
-        }
-    }
-
-    DataChannelObserverMock dataChannelObserver(int channelIndex) {
-        switch (channelIndex) {
-            case 0:
-                return mDataChannelObserverMock1;
-
-            case 1:
-                return mDataChannelObserverMock2;
-
-            default:
-                throw new ArrayIndexOutOfBoundsException();
-        }
-    }
-
-    void registerDatatChannelObservers() {
-        mDataChannel1.registerObserver(mDataChannelObserverMock1);
-        mDataChannel2.registerObserver(mDataChannelObserverMock2);
-    }
-
-    void unregisterDatatChannelObservers() {
-        mDataChannel1.unregisterObserver();
-        mDataChannel2.unregisterObserver();
-    }
-}
diff --git a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/DevToolsBridgeServerSandbox.java b/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/DevToolsBridgeServerSandbox.java
deleted file mode 100644
index 7364e0cc..0000000
--- a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/DevToolsBridgeServerSandbox.java
+++ /dev/null
@@ -1,96 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge;
-
-import android.content.Context;
-import android.os.Process;
-import android.util.Log;
-
-import org.chromium.components.devtools_bridge.util.LooperExecutor;
-
-import java.io.IOException;
-
-/**
- * Sandbox for manual testing {@link DevToolsBridgeServer}
- */
-public class DevToolsBridgeServerSandbox {
-    private static final String TAG = "DevToolsBridgeServerSandbox";
-    private static final String SERVER_SOCKET_NAME = "chrome_shell_devtools_remote";
-
-    private Context mContext;
-    private LooperExecutor mExecutor;
-    private DevToolsBridgeServer mServer;
-    private SessionDependencyFactory mFactory;
-    private ClientSessionTestingHost mClientSession1;
-    private ClientSessionTestingHost mClientSession2;
-
-    public void start(Context context) {
-        assert mContext == null;
-        mContext = context;
-        mExecutor = LooperExecutor.newInstanceForMainLooper(mContext);
-        mServer = new DevToolsBridgeServer(new ServerDelegate(context));
-
-        mFactory = SessionDependencyFactory.newInstance();
-        mClientSession1 = createSession("Session 1", "webview_devtools_remote_" + Process.myPid());
-        mClientSession2 = createSession("Session 2", "chrome_devtools_remote_" + Process.myPid());
-
-        mClientSession1.start();
-        mClientSession2.start();
-    }
-
-    public void stop() {
-        mClientSession1.dispose();
-        mClientSession2.dispose();
-        mFactory.dispose();
-        mClientSession1 = null;
-        mClientSession2 = null;
-        mFactory = null;
-        mServer.dispose();
-        mServer = null;
-        mContext = null;
-    }
-
-    private ClientSessionTestingHost createSession(String sessionId, String socketName) {
-        try {
-            return new ClientSessionTestingHost(
-                    mFactory, mServer, mExecutor, sessionId, socketName);
-        } catch (IOException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    private void stopInternal() {
-        Log.d(TAG, "Service disconnected. Stopping client sessions");
-        mClientSession1.dispose();
-        mClientSession2.dispose();
-        mFactory.dispose();
-        mClientSession1 = null;
-        mClientSession2 = null;
-        mFactory = null;
-    }
-
-    private static class ServerDelegate implements DevToolsBridgeServer.Delegate {
-        private Context mContext;
-
-        public ServerDelegate(Context context) {
-            mContext = context;
-        }
-
-        @Override
-        public Context getContext() {
-            return mContext;
-        }
-
-        @Override
-        public void onSessionCountChange(int sessionCount) {
-            Log.i(TAG, sessionCount + " active session");
-        }
-
-        @Override
-        public void querySocketName(DevToolsBridgeServer.QuerySocketCallback callback) {
-            callback.onSuccess(SERVER_SOCKET_NAME);
-        }
-    }
-}
diff --git a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/GCDClientSessionTestingHost.java b/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/GCDClientSessionTestingHost.java
deleted file mode 100644
index c3fd83a..0000000
--- a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/GCDClientSessionTestingHost.java
+++ /dev/null
@@ -1,101 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge;
-
-import android.util.Log;
-
-import org.chromium.components.devtools_bridge.apiary.TestApiaryClientFactory;
-import org.chromium.components.devtools_bridge.commands.Command;
-import org.chromium.components.devtools_bridge.commands.CommandSender;
-
-import java.io.IOException;
-import java.util.Random;
-
-/**
- * Helper class which handles a client session in manual tests. Connects to a
- * remote server with GCD.
- */
-public class GCDClientSessionTestingHost {
-    private static final String TAG = "GCDClientSessionTestingHost";
-    private static final Random sRandom = new Random();
-
-    private final TestApiaryClientFactory mClientFactory;
-    private final SessionDependencyFactory mFactory;
-    private final LocalSessionBridge.ThreadedExecutor mIOExecutor;
-    private final ClientSessionTestingHost mBase;
-    private final String mOAuthToken;
-    private final String mRemoteInstanceId;
-
-    private volatile boolean mStarted;
-
-    public GCDClientSessionTestingHost(
-            String oAuthToken, String socketName, String remoteInstanceId) throws IOException {
-        mClientFactory = new TestApiaryClientFactory();
-        mFactory = SessionDependencyFactory.newInstance();
-        mIOExecutor = new LocalSessionBridge.ThreadedExecutor();
-
-        String sessionId = Integer.toString(sRandom.nextInt());
-
-        mBase = new ClientSessionTestingHost(
-                mFactory, new ServerProxy(remoteInstanceId), mIOExecutor, sessionId, socketName);
-
-        mOAuthToken = oAuthToken;
-        mRemoteInstanceId = remoteInstanceId;
-    }
-
-    public boolean isStarted() {
-        return mStarted;
-    }
-
-    public void start(final Runnable completionCallback) {
-        mIOExecutor.postOnSessionThread(0, new Runnable() {
-                    @Override
-                    public void run() {
-                        try {
-                            mBase.start(mClientFactory.newConfigClient().fetch());
-                            mStarted = true;
-                        } catch (IOException e) {
-                            Log.e(TAG, "Failed to start", e);
-                        } finally {
-                            completionCallback.run();
-                        }
-                    }
-
-                });
-    }
-
-    public void dispose() {
-        mBase.dispose();
-        mIOExecutor.runSynchronously(new Runnable() {
-            @Override
-            public void run() {
-                // All previously scheduled operations have completed.
-                mClientFactory.close();
-            }
-        });
-        mIOExecutor.dispose();
-    }
-
-    private class ServerProxy extends CommandSender {
-        private final String mInstanceId;
-
-        public ServerProxy(String instanceId) {
-            mInstanceId = instanceId;
-        }
-
-        protected void send(Command command, Runnable completionCallback) {
-            assert mIOExecutor.isCalledOnSessionThread();
-
-            try {
-                mClientFactory.newTestGCDClient(mOAuthToken).send(mRemoteInstanceId, command);
-            } catch (IOException e) {
-                Log.e(TAG, "Exception when sending a command", e);
-                command.setFailure("IOException: " + e.getMessage());
-            } finally {
-                completionCallback.run();
-            }
-        }
-    }
-}
diff --git a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/LocalSessionBridge.java b/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/LocalSessionBridge.java
deleted file mode 100644
index 13f24181..0000000
--- a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/LocalSessionBridge.java
+++ /dev/null
@@ -1,303 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge;
-
-import android.util.Log;
-
-import java.io.IOException;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ScheduledFuture;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicReference;
-
-/**
- * Helper class designated for automatic and manual testing. Creates a pair of ClientSession and
- * ServerSession on separate and threads binds them through and adapters that makes call the calls
- * on correct threads (no serialization needed for communication).
- */
-public class LocalSessionBridge {
-    private static final String TAG = "LocalSessionBridge";
-
-    private volatile int mDelayMs = 0;
-
-    private final SessionDependencyFactory mFactory = SessionDependencyFactory.newInstance();
-
-    private final ThreadedExecutor mServerExecutor = new ThreadedExecutor();
-    private final ThreadedExecutor mClientExecutor = new ThreadedExecutor();
-
-    private final ServerSessionMock mServerSession;
-    private final ClientSessionMock mClientSession;
-
-    private boolean mStarted = false;
-
-    private final CountDownLatch mNegotiated = new CountDownLatch(2);
-    private final CountDownLatch mControlChannelOpened = new CountDownLatch(2);
-    private final CountDownLatch mClientAutoClosed = new CountDownLatch(1);
-    private final CountDownLatch mServerAutoClosed = new CountDownLatch(1);
-    private final CountDownLatch mTunnelConfirmed = new CountDownLatch(1);
-
-    private int mServerAutoCloseTimeoutMs = -1;
-    private int mClientAutoCloseTimeoutMs = -1;
-
-    public LocalSessionBridge(String serverSocketName, String clientSocketName) throws IOException {
-        mServerSession = new ServerSessionMock(serverSocketName);
-        mClientSession = new ClientSessionMock(mServerSession, clientSocketName);
-    }
-
-    public void setMessageDeliveryDelayMs(int value) {
-        mDelayMs = value;
-    }
-
-    void setClientAutoCloseTimeoutMs(int value) {
-        assert !isStarted();
-
-        mClientAutoCloseTimeoutMs = value;
-    }
-
-    void setServerAutoCloseTimeoutMs(int value) {
-        assert !isStarted();
-
-        mServerAutoCloseTimeoutMs = value;
-    }
-
-    public void dispose() {
-        mServerExecutor.runSynchronously(new Runnable() {
-            @Override
-            public void run() {
-                mServerSession.dispose();
-            }
-        });
-        mClientExecutor.runSynchronously(new Runnable() {
-            @Override
-            public void run() {
-                mClientSession.dispose();
-            }
-        });
-
-        mServerExecutor.dispose();
-        mClientExecutor.dispose();
-        mFactory.dispose();
-    }
-
-    public void start() {
-        start(new RTCConfiguration());
-    }
-
-    public void start(final RTCConfiguration config) {
-        if (mServerAutoCloseTimeoutMs >= 0)
-            mServerSession.setAutoCloseTimeoutMs(mServerAutoCloseTimeoutMs);
-        if (mClientAutoCloseTimeoutMs >= 0)
-            mClientSession.setAutoCloseTimeoutMs(mClientAutoCloseTimeoutMs);
-        mClientExecutor.runSynchronously(new Runnable() {
-            @Override
-            public void run() {
-                mClientSession.start(config);
-            }
-        });
-        mStarted = true;
-    }
-
-    private boolean isStarted() {
-        return mStarted;
-    }
-
-    public void stop() {
-        assert mStarted;
-
-        mServerExecutor.runSynchronously(new Runnable() {
-            @Override
-            public void run() {
-                mServerSession.stop();
-            }
-        });
-        mClientExecutor.runSynchronously(new Runnable() {
-            @Override
-            public void run() {
-                mClientSession.stop();
-            }
-        });
-        mStarted = false;
-    }
-
-    public void awaitNegotiated() throws InterruptedException {
-        mNegotiated.await();
-    }
-
-    public void awaitControlChannelOpened() throws InterruptedException {
-        mControlChannelOpened.await();
-    }
-
-    public void awaitClientAutoClosed() throws InterruptedException {
-        mClientAutoClosed.await();
-    }
-
-    public void awaitServerAutoClosed() throws InterruptedException {
-        mServerAutoClosed.await();
-    }
-
-    private class ServerSessionMock extends ServerSession {
-        public ServerSessionMock(String serverSocketName) {
-            super(LocalSessionBridge.this.mFactory, mServerExecutor, serverSocketName);
-        }
-
-        public void setAutoCloseTimeoutMs(int value) {
-            mAutoCloseTimeoutMs = value;
-        }
-
-        @Override
-        protected void onSessionNegotiated() {
-            Log.d(TAG, "Server negotiated");
-            mNegotiated.countDown();
-            super.onSessionNegotiated();
-        }
-
-        @Override
-        protected void onControlChannelOpened() {
-            Log.d(TAG, "Server's control channel opened");
-            super.onControlChannelOpened();
-            mControlChannelOpened.countDown();
-        }
-
-        @Override
-        protected void onIceCandidate(String candidate) {
-            Log.d(TAG, "Server's ICE candidate: " + candidate);
-            super.onIceCandidate(candidate);
-        }
-
-        @Override
-        protected void closeSelf() {
-            Log.d(TAG, "Server autoclosed");
-            super.closeSelf();
-            mServerAutoClosed.countDown();
-        }
-
-        @Override
-        protected SocketTunnel newSocketTunnelServer(String serverSocketName) {
-            SocketTunnel tunnel = super.newSocketTunnelServer(serverSocketName);
-            Log.d(TAG, "Server tunnel created on " + serverSocketName);
-            return tunnel;
-        }
-    }
-
-    private class ClientSessionMock extends ClientSession {
-        public ClientSessionMock(ServerSession serverSession, String clientSocketName)
-                throws IOException {
-            super(LocalSessionBridge.this.mFactory,
-                  mClientExecutor,
-                  createServerSessionProxy(serverSession),
-                  clientSocketName);
-        }
-
-        public void setAutoCloseTimeoutMs(int value) {
-            mAutoCloseTimeoutMs = value;
-        }
-
-        @Override
-        protected void onSessionNegotiated() {
-            Log.d(TAG, "Client negotiated");
-            mNegotiated.countDown();
-            super.onSessionNegotiated();
-        }
-
-        @Override
-        protected void onControlChannelOpened() {
-            Log.d(TAG, "Client's control channel opened");
-            super.onControlChannelOpened();
-            mControlChannelOpened.countDown();
-        }
-
-        @Override
-        protected void onIceCandidate(String candidate) {
-            Log.d(TAG, "Client's ICE candidate: " + candidate);
-            super.onIceCandidate(candidate);
-        }
-
-        @Override
-        protected void closeSelf() {
-            Log.d(TAG, "Client autoclosed");
-            super.closeSelf();
-            mClientAutoClosed.countDown();
-        }
-    }
-
-    /**
-     * Implementation of SessionBase.Executor on top of ScheduledExecutorService.
-     */
-    public static final class ThreadedExecutor implements SessionBase.Executor {
-        private final ScheduledExecutorService mExecutor =
-                Executors.newSingleThreadScheduledExecutor();
-        private final AtomicReference<Thread> mSessionThread = new AtomicReference<Thread>();
-
-        @Override
-        public SessionBase.Cancellable postOnSessionThread(int delayMs, Runnable runnable) {
-            return new CancellableFuture(mExecutor.schedule(
-                    new SessionThreadRunner(runnable), delayMs, TimeUnit.MILLISECONDS));
-        }
-
-        @Override
-        public boolean isCalledOnSessionThread() {
-            return Thread.currentThread() == mSessionThread.get();
-        }
-
-        public void runSynchronously(Runnable runnable) {
-            try {
-                mExecutor.submit(new SessionThreadRunner(runnable)).get();
-            } catch (InterruptedException e) {
-                Thread.currentThread().interrupt();
-            } catch (ExecutionException e) {
-                throw new RuntimeException(e);
-            }
-        }
-
-        public void dispose() {
-            mExecutor.shutdownNow();
-        }
-
-        private class SessionThreadRunner implements Runnable {
-            private final Runnable mRunnable;
-
-            public SessionThreadRunner(Runnable runnable) {
-                mRunnable = runnable;
-            }
-
-            @Override
-            public void run() {
-                Thread thread = mSessionThread.getAndSet(Thread.currentThread());
-                assert thread == null;
-                try {
-                    mRunnable.run();
-                } finally {
-                    thread = mSessionThread.getAndSet(null);
-                }
-                assert thread == Thread.currentThread();
-            }
-        }
-    }
-
-    private static final class CancellableFuture implements SessionBase.Cancellable {
-        private final ScheduledFuture<?> mFuture;
-
-        public CancellableFuture(ScheduledFuture<?> future) {
-            mFuture = future;
-        }
-
-        @Override
-        public void cancel() {
-            mFuture.cancel(false);
-        }
-    }
-
-    private SessionBase.ServerSessionInterface createServerSessionProxy(
-            SessionBase.ServerSessionInterface serverSession) {
-        String sessionId = "";
-
-        return new SignalingReceiverProxy(
-                mServerExecutor, mClientExecutor, serverSession, sessionId, mDelayMs)
-                .asServerSession(sessionId);
-    }
-}
diff --git a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/PacketDecoder.java b/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/PacketDecoder.java
deleted file mode 100644
index d8e0dff5..0000000
--- a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/PacketDecoder.java
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge;
-
-import java.nio.ByteBuffer;
-
-/**
- * Decodes data packets of SocketTunnelClient and SocketTunnelServer for tests.
- */
-public final class PacketDecoder extends SocketTunnelBase.PacketDecoderBase {
-    private boolean mControlPacket = false;
-    private boolean mDataPacket;
-    private int mOpCode;
-    private int mConnectionId;
-    private byte[] mData;
-
-    protected void onReceivedDataPacket(int connectionId, byte[] data) {
-        mDataPacket = true;
-        mConnectionId = connectionId;
-        mData = data;
-    }
-
-    @Override
-    protected void onReceivedControlPacket(int connectionId, byte opCode) {
-        mControlPacket = true;
-        mOpCode = opCode;
-        mConnectionId = connectionId;
-    }
-
-    public static PacketDecoder tryDecode(ByteBuffer packet) throws SocketTunnelBase.ProtocolError {
-        PacketDecoder decoder = new PacketDecoder();
-        decoder.decodePacket(packet);
-        return decoder;
-    }
-
-    public static PacketDecoder decode(ByteBuffer packet) {
-        try {
-            return tryDecode(packet);
-        } catch (SocketTunnelBase.ProtocolError e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    public boolean isControlPacket() {
-        return mControlPacket;
-    }
-
-    public boolean isDataPacket() {
-        return mDataPacket;
-    }
-
-    public int opCode() {
-        assert isControlPacket();
-        return mOpCode;
-    }
-
-    public int connectionId() {
-        return mConnectionId;
-    }
-
-    public byte[] data() {
-        assert isDataPacket();
-        return mData.clone();
-    }
-}
diff --git a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/PeerConnectionObserverMock.java b/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/PeerConnectionObserverMock.java
deleted file mode 100644
index fc1fdd4..0000000
--- a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/PeerConnectionObserverMock.java
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge;
-
-import org.chromium.base.annotations.SuppressFBWarnings;
-
-import java.util.concurrent.CountDownLatch;
-
-/**
- * Mock for AbstractPeerConnection.Observer.
- */
-@SuppressFBWarnings("URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-public class PeerConnectionObserverMock implements AbstractPeerConnection.Observer {
-    public AbstractPeerConnection.SessionDescriptionType localDescriptionType;
-    public String localDescription;
-
-    public final CountDownLatch localDescriptionAvailable = new CountDownLatch(1);
-    public final CountDownLatch failureAvailable = new CountDownLatch(1);
-    public final CountDownLatch remoteDescriptionSet = new CountDownLatch(1);
-    public final CountDownLatch connected = new CountDownLatch(1);
-
-    public AbstractPeerConnection iceCandidatesSink;
-
-    @Override
-    public void onFailure(String description) {
-        failureAvailable.countDown();
-    }
-
-    @Override
-    public void onLocalDescriptionCreatedAndSet(
-            AbstractPeerConnection.SessionDescriptionType type, String description) {
-        localDescriptionType = type;
-        localDescription = description;
-        localDescriptionAvailable.countDown();
-    }
-
-    @Override
-    public void onRemoteDescriptionSet() {
-        remoteDescriptionSet.countDown();
-    }
-
-    @Override
-    public void onIceCandidate(String iceCandidate) {
-        if (iceCandidatesSink != null)
-            iceCandidatesSink.addIceCandidate(iceCandidate);
-    }
-
-    @Override
-    public void onIceConnectionChange(boolean connected) {
-        this.connected.countDown();
-    }
-}
diff --git a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/SignalingReceiverMock.java b/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/SignalingReceiverMock.java
deleted file mode 100644
index 6d1fb25..0000000
--- a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/SignalingReceiverMock.java
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge;
-
-import org.chromium.base.annotations.SuppressFBWarnings;
-
-import java.util.List;
-
-/**
- * Mock of SignalingReceiver.
- */
-@SuppressFBWarnings("URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-public class SignalingReceiverMock implements SignalingReceiver {
-    public String sessionId;
-    public String offer;
-    public SessionBase.NegotiationCallback negotiationCallback;
-    public SessionBase.IceExchangeCallback iceExchangeCallback;
-
-    @Override
-    public void startSession(
-            String sessionId,
-            RTCConfiguration config,
-            String offer,
-            SessionBase.NegotiationCallback callback) {
-        this.sessionId = sessionId;
-        this.offer = offer;
-        this.negotiationCallback = callback;
-    }
-
-    @Override
-    public void renegotiate(
-            String sessionId,
-            String offer,
-            SessionBase.NegotiationCallback callback) {
-        this.sessionId = sessionId;
-        this.offer = offer;
-        this.negotiationCallback = callback;
-    }
-
-    @Override
-    public void iceExchange(
-            String sessionId,
-            List<String> clientCandidates,
-            SessionBase.IceExchangeCallback callback) {
-        this.sessionId = sessionId;
-        this.iceExchangeCallback = callback;
-    }
-}
diff --git a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/SignalingReceiverProxy.java b/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/SignalingReceiverProxy.java
deleted file mode 100644
index f57637b..0000000
--- a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/SignalingReceiverProxy.java
+++ /dev/null
@@ -1,137 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge;
-
-import org.chromium.components.devtools_bridge.commands.Command;
-import org.chromium.components.devtools_bridge.commands.CommandReceiver;
-import org.chromium.components.devtools_bridge.commands.CommandSender;
-
-import java.util.List;
-
-/**
- * Helper proxy that binds client and server sessions living on different executors.
- */
-final class SignalingReceiverProxy extends CommandSender {
-    private final CommandReceiver mReceiver;
-    private final SessionBase.Executor mServerExecutor;
-    private final SessionBase.Executor mClientExecutor;
-    private final int mDelayMs;
-
-    public SignalingReceiverProxy(
-            SessionBase.Executor serverExecutor,
-            SessionBase.Executor clientExecutor,
-            SignalingReceiver server,
-            int delayMs) {
-        mServerExecutor = serverExecutor;
-        mClientExecutor = clientExecutor;
-        mReceiver = new CommandReceiver(server);
-        mDelayMs = delayMs;
-    }
-
-    public SignalingReceiverProxy(
-            SessionBase.Executor serverExecutor,
-            SessionBase.Executor clientExecutor,
-            SessionBase.ServerSessionInterface serverSession,
-            String sessionId,
-            int delayMs) {
-        this(serverExecutor, clientExecutor,
-                new SignalingReceiverAdaptor(serverSession, sessionId),
-                delayMs);
-    }
-
-    public SessionBase.Executor serverExecutor() {
-        return mServerExecutor;
-    }
-
-    public SessionBase.Executor clientExecutor() {
-        return mClientExecutor;
-    }
-
-    @Override
-    protected void send(final Command command, final Runnable completionCallback) {
-        assert mClientExecutor.isCalledOnSessionThread();
-
-        mServerExecutor.postOnSessionThread(mDelayMs, new Runnable() {
-                    @Override
-                    public void run() {
-                        mReceiver.receive(command, new Runnable() {
-                            @Override
-                            public void run() {
-                                assert mServerExecutor.isCalledOnSessionThread();
-                                mClientExecutor.postOnSessionThread(mDelayMs, completionCallback);
-                            }
-                        });
-                    }
-                });
-    }
-
-    public SessionBase.ServerSessionInterface asServerSession(String sessionId) {
-        return new ServerSessionAdapter(this, sessionId);
-    }
-
-    private static final class ServerSessionAdapter implements SessionBase.ServerSessionInterface {
-        private final SignalingReceiver mAdaptee;
-        private final String mSessionId;
-
-        public ServerSessionAdapter(SignalingReceiver adaptee, String sessionId) {
-            mAdaptee = adaptee;
-            mSessionId = sessionId;
-        }
-
-        @Override
-        public void startSession(
-                RTCConfiguration config, String offer, SessionBase.NegotiationCallback callback) {
-            mAdaptee.startSession(mSessionId, config, offer, callback);
-        }
-
-        @Override
-        public void renegotiate(String offer, SessionBase.NegotiationCallback callback) {
-            mAdaptee.renegotiate(mSessionId, offer, callback);
-        }
-
-        @Override
-        public void iceExchange(
-                List<String> clientCandidates, SessionBase.IceExchangeCallback callback) {
-            mAdaptee.iceExchange(mSessionId, clientCandidates, callback);
-        }
-    }
-
-    private static final class SignalingReceiverAdaptor implements SignalingReceiver {
-        private final SessionBase.ServerSessionInterface mAdaptee;
-        private final String mSessionId;
-
-        public SignalingReceiverAdaptor(
-                SessionBase.ServerSessionInterface adaptee, String sessionId) {
-            mAdaptee = adaptee;
-            mSessionId = sessionId;
-        }
-
-        @Override
-        public void startSession(
-                String sessionId, RTCConfiguration config, String offer,
-                SessionBase.NegotiationCallback callback) {
-            if (mSessionId.equals(sessionId)) {
-                mAdaptee.startSession(config, offer, callback);
-            }
-        }
-
-        @Override
-        public void renegotiate(
-                String sessionId, String offer, SessionBase.NegotiationCallback callback) {
-            if (mSessionId.equals(sessionId)) {
-                mAdaptee.renegotiate(offer, callback);
-            }
-        }
-
-        @Override
-        public void iceExchange(
-                String sessionId, List<String> clientCandidates,
-                SessionBase.IceExchangeCallback callback) {
-            if (mSessionId.equals(sessionId)) {
-                mAdaptee.iceExchange(clientCandidates, callback);
-            }
-        }
-    }
-}
diff --git a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/SignalingThreadMock.java b/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/SignalingThreadMock.java
deleted file mode 100644
index 8d62f78..0000000
--- a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/SignalingThreadMock.java
+++ /dev/null
@@ -1,162 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge;
-
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.LinkedBlockingDeque;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ScheduledFuture;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicInteger;
-
-/**
- * Convinience class for tests. Like WebRTC threads supports posts
- * and synchronous invokes.
- */
-class SignalingThreadMock {
-    // TODO: use scaleTimeout when natives for org.chromium.base get available.
-    private static final int EXECUTION_TIME_LIMIT_MS = 5000;
-
-    private final AtomicInteger mInvokationCounter = new AtomicInteger(0);
-    private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();
-    private final ScheduledExecutorService mWatchDogExecutor =
-            Executors.newSingleThreadScheduledExecutor();
-    private ScheduledFuture<?> mWatchDogFuture;
-    private final Thread mThread;
-    private final BlockingQueue<Runnable> mExecutionQueue = new LinkedBlockingDeque<Runnable>();
-
-    public SignalingThreadMock() {
-        mThread = new Thread() {
-            @Override
-            public void run() {
-                try {
-                    runExecutionLoop();
-                } catch (InterruptedException e) {
-                    // Normal finish.
-                }
-            }
-        };
-        mThread.start();
-    }
-
-    private void runExecutionLoop() throws InterruptedException {
-        while (true) {
-            mExecutionQueue.take().run();
-        }
-    }
-
-    public void invoke(final Runnable runnable) {
-        try {
-            invoke(new TestUtils.RunnableAdapter(runnable));
-        } catch (Exception e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    public <T> T invoke(final Callable<T> callable) throws Exception {
-        if (isOnThread()) return callable.call();
-
-        try {
-            return new InvokeWrapper<T>(callable).invoke();
-        } catch (InterruptedException e) {
-            throw new RuntimeException(e);
-        } catch (ExecutionException e) {
-            throw (Exception) e.getCause();
-        }
-    }
-
-    public void post(Runnable runnable) {
-        boolean success = mExecutionQueue.offer(new PostWrapper(runnable));
-        assert success;
-    }
-
-    public void dispose() {
-        mWatchDogExecutor.shutdown();
-        mThread.interrupt();
-        try {
-            mThread.join();
-        } catch (InterruptedException e) {
-            Thread.currentThread().interrupt();
-        }
-    }
-
-    public boolean isOnThread() {
-        return Thread.currentThread() == mThread;
-    }
-
-    private void onStartedExecution(final int index, final Exception timeoutException) {
-        mWatchDogFuture = mWatchDogExecutor.schedule(new Runnable() {
-            @Override
-            public void run() {
-                throw new RuntimeException(
-                        "Time limit on " + Integer.toString(index) + " invocation",
-                        timeoutException);
-            }
-        }, EXECUTION_TIME_LIMIT_MS, TimeUnit.MILLISECONDS);
-    }
-
-    private void onFinishedExecution() {
-        mWatchDogFuture.cancel(false);
-    }
-
-    private abstract class WrapperBase implements Runnable {
-        private final int mIndex;
-        private final Exception mTimeoutException;
-
-        protected WrapperBase() {
-            mIndex = mInvokationCounter.incrementAndGet();
-            mTimeoutException = new Exception("Timeout exception");
-        }
-
-        @Override
-        public final void run() {
-            onStartedExecution(mIndex, mTimeoutException);
-            try {
-                runWrapped();
-            } finally {
-                onFinishedExecution();
-            }
-        }
-
-        protected abstract void runWrapped();
-    }
-
-    private class InvokeWrapper<T> extends WrapperBase {
-        private final Callable<T> mWrapped;
-        private final TestUtils.InvokeHelper<T> mHelper = new TestUtils.InvokeHelper<T>();
-
-        public InvokeWrapper(Callable<T> wrapped) {
-            mWrapped = wrapped;
-        }
-
-        @Override
-        protected void runWrapped() {
-            mHelper.runOnTargetThread(mWrapped);
-        }
-
-        public T invoke() throws Exception {
-            boolean success = mExecutionQueue.offer(this);
-            assert success;
-            return mHelper.takeResult();
-        }
-    }
-
-    private class PostWrapper extends WrapperBase {
-        private final Runnable mWrapped;
-
-        public PostWrapper(Runnable wrapped) {
-            mWrapped = wrapped;
-        }
-
-        @Override
-        protected void runWrapped() {
-            mWrapped.run();
-        }
-    }
-}
diff --git a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/SocketTunnelBase.java b/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/SocketTunnelBase.java
deleted file mode 100644
index bc15d76e..0000000
--- a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/SocketTunnelBase.java
+++ /dev/null
@@ -1,399 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge;
-
-import android.net.LocalSocket;
-import android.net.LocalSocketAddress;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicReference;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReadWriteLock;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-
-/**
- * Base class for client and server that tunnels DevToolsServer's UNIX socket
- * over WebRTC data channel.
- *
- * Server runs on a android device with Chromium (or alike). Client runs where socket
- * needed to be accesses (it could be the same device if socket names are different; this
- * configuration useful for testing).
- *
- * Client listens LocalServerSocket and each time it receives connection it forwards
- * CLIENT_OPEN packet to the server with newly assigned connection id. On receiving this packet
- * server tries to connect to DevToolsServer socket. If succeeded it sends back SERVER_OPEN_ACK
- * with the same connection id. If failed it sends SERVER_CLOSE.
- *
- * When input stream on client shuts down it sends CLIENT_CLOSE. The same with SERVER_CLOSE
- * on the server side (only if SERVER_OPEN_ACK had sent). Between CLIENT_OPEN and CLIENT_CLOSE
- * any amount of data packets may be transferred (the same for SERVER_OPEN_ACK/SERVER_CLOSE
- * on the server side).
- *
- * Since all communication is reliable and ordered it's safe for client to assume that
- * if CLIENT_CLOSE has sent and SERVER_CLOSE has received with the same connection ID this
- * ID is safe to be reused.
- */
-public abstract class SocketTunnelBase implements SocketTunnel {
-    // Data channel is threadsafe but access to the reference needs synchronization.
-    private final ReadWriteLock mDataChanneliReferenceLock = new ReentrantReadWriteLock();
-    private volatile AbstractDataChannel mDataChannel;
-
-    // Packet structure encapsulated in buildControlPacket, buildDataPacket and PacketDecoderBase.
-    // Structure of control packet:
-    // 1-st byte: CONTROL_CONNECTION_ID.
-    // 2-d byte: op code.
-    // 3-d byte: connection id.
-    //
-    // Structure of data packet:
-    // 1-st byte: connection id.
-    // 2..n: data.
-
-    private static final int CONTROL_PACKET_SIZE = 3;
-
-    // Client to server control packets.
-    protected static final byte CLIENT_OPEN = (byte) 0;
-    protected static final byte CLIENT_CLOSE = (byte) 1;
-
-    // Server to client control packets.
-    protected static final byte SERVER_OPEN_ACK = (byte) 0;
-    protected static final byte SERVER_CLOSE = (byte) 1;
-
-    // Must not exceed WebRTC limit. Exceeding it closes
-    // data channel automatically. TODO(serya): WebRTC limit supposed to be removed.
-    static final int READING_BUFFER_SIZE = 4 * 1024;
-
-    private static final int CONTROL_CONNECTION_ID = 0;
-
-    // DevTools supports up to ~10 connections at the time. A few extra IDs usefull for
-    // delays in closing acknowledgement.
-    protected static final int MIN_CONNECTION_ID = 1;
-    protected static final int MAX_CONNECTION_ID = 64;
-
-    // Signaling thread isn't accessible via API. Assumes that first caller
-    // checkCalledOnSignalingThread is called on it indeed. It also works well for tests.
-    private final AtomicReference<Thread> mSignalingThread = new AtomicReference<Thread>();
-
-    // For writing in socket without blocking signaling thread.
-    private final ExecutorService mWritingThread = Executors.newSingleThreadExecutor();
-
-    @Override
-    public boolean isBound() {
-        final Lock lock = mDataChanneliReferenceLock.readLock();
-        lock.lock();
-        try {
-            return mDataChannel != null;
-        } finally {
-            lock.unlock();
-        }
-    }
-
-    /**
-     * Binds the tunnel to the data channel. Tunnel starts its activity when data channel
-     * open.
-     */
-    @Override
-    public void bind(AbstractDataChannel dataChannel) {
-        // Observer registrution must not be done in constructor.
-        final Lock lock = mDataChanneliReferenceLock.writeLock();
-        lock.lock();
-        try {
-            mDataChannel = dataChannel;
-        } finally {
-            lock.unlock();
-        }
-        dataChannel.registerObserver(new DataChannelObserver());
-    }
-
-    /**
-     * Stops all tunnel activity and returns the prevously bound data channel.
-     * It's safe to dispose the data channel after it.
-     */
-    @Override
-    public AbstractDataChannel unbind() {
-        final Lock lock = mDataChanneliReferenceLock.writeLock();
-        lock.lock();
-        final AbstractDataChannel dataChannel;
-        try {
-            dataChannel = mDataChannel;
-            mDataChannel = null;
-        } finally {
-            lock.unlock();
-        }
-        dataChannel.unregisterObserver();
-        mSignalingThread.set(null);
-        mWritingThread.shutdownNow();
-        return dataChannel;
-    }
-
-    protected void checkCalledOnSignalingThread() {
-        if (!mSignalingThread.compareAndSet(null, Thread.currentThread())) {
-            if (mSignalingThread.get() != Thread.currentThread()) {
-                throw new RuntimeException("Must be called on signaling thread");
-            }
-        }
-    }
-
-    protected static void checkConnectionId(int connectionId) throws ProtocolError {
-        if (connectionId < MIN_CONNECTION_ID || connectionId > MAX_CONNECTION_ID) {
-            throw new ProtocolError("Invalid connection id: " + Integer.toString(connectionId));
-        }
-    }
-
-    protected void onProtocolError(ProtocolError e) {
-        checkCalledOnSignalingThread();
-
-        // When integrity of data channel is broken then best way to survive is to close it.
-        final Lock lock = mDataChanneliReferenceLock.readLock();
-        lock.lock();
-        try {
-            mDataChannel.close();
-        } finally {
-            lock.unlock();
-        }
-    }
-
-    protected abstract void onReceivedDataPacket(int connectionId, byte[] data)
-            throws ProtocolError;
-    protected abstract void onReceivedControlPacket(int connectionId, byte opCode)
-            throws ProtocolError;
-    protected void onSocketException(IOException e, int connectionId) {}
-    protected void onDataChannelOpened() {}
-    protected void onDataChannelClosed() {}
-
-    static ByteBuffer buildControlPacket(int connectionId, byte opCode) {
-        ByteBuffer packet = ByteBuffer.allocateDirect(CONTROL_PACKET_SIZE);
-        packet.put((byte) CONTROL_CONNECTION_ID);
-        packet.put(opCode);
-        packet.put((byte) connectionId);
-        return packet;
-    }
-
-    static ByteBuffer buildDataPacket(int connectionId, byte[] buffer, int count) {
-        ByteBuffer packet = ByteBuffer.allocateDirect(count + 1);
-        packet.put((byte) connectionId);
-        packet.put(buffer, 0, count);
-        return packet;
-    }
-
-    protected void sendToDataChannel(ByteBuffer packet) {
-        packet.limit(packet.position());
-        packet.position(0);
-        final Lock lock = mDataChanneliReferenceLock.readLock();
-        lock.lock();
-        try {
-            if (mDataChannel != null) {
-                mDataChannel.send(packet, AbstractDataChannel.MessageType.BINARY);
-            }
-        } finally {
-            lock.unlock();
-        }
-    }
-
-    /**
-     * Packet decoding exposed for tests.
-     */
-    abstract static class PacketDecoderBase {
-        protected void decodePacket(ByteBuffer packet) throws ProtocolError {
-            if (packet.remaining() == 0) {
-                throw new ProtocolError("Empty packet");
-            }
-
-            int connectionId = packet.get();
-            if (connectionId != CONTROL_CONNECTION_ID) {
-                checkConnectionId(connectionId);
-                byte[] data = new byte[packet.remaining()];
-                packet.get(data);
-                onReceivedDataPacket(connectionId, data);
-            } else {
-                if (packet.remaining() != CONTROL_PACKET_SIZE - 1) {
-                    throw new ProtocolError("Invalid control packet size");
-                }
-
-                byte opCode = packet.get();
-                connectionId = packet.get();
-                checkConnectionId(connectionId);
-                onReceivedControlPacket(connectionId, opCode);
-            }
-        }
-
-        protected abstract void onReceivedDataPacket(int connectionId, byte[] data)
-                throws ProtocolError;
-        protected abstract void onReceivedControlPacket(int connectionId, byte opcode)
-                throws ProtocolError;
-    }
-
-    private final class DataChannelObserver
-            extends PacketDecoderBase implements AbstractDataChannel.Observer {
-        @Override
-        public void onStateChange(AbstractDataChannel.State state) {
-            checkCalledOnSignalingThread();
-
-            if (state == AbstractDataChannel.State.OPEN) {
-                onDataChannelOpened();
-            } else {
-                onDataChannelClosed();
-            }
-        }
-
-        @Override
-        public void onMessage(ByteBuffer message) {
-            checkCalledOnSignalingThread();
-
-            try {
-                decodePacket(message);
-            } catch (ProtocolError e) {
-                onProtocolError(e);
-            }
-        }
-
-        @Override
-        protected void onReceivedDataPacket(int connectionId, byte[] data) throws ProtocolError {
-            checkCalledOnSignalingThread();
-
-            SocketTunnelBase.this.onReceivedDataPacket(connectionId, data);
-        }
-
-        @Override
-        protected void onReceivedControlPacket(int connectionId, byte opCode) throws ProtocolError {
-            checkCalledOnSignalingThread();
-
-            SocketTunnelBase.this.onReceivedControlPacket(connectionId, opCode);
-        }
-    }
-
-    /**
-     * Any problem happened while handling incoming message that breaks state integrity.
-     */
-    static class ProtocolError extends Exception {
-        public ProtocolError(String description) {
-            super(description);
-        }
-    }
-
-    /**
-     * Base utility class for client and server connections.
-     */
-    protected abstract class ConnectionBase {
-        protected final int mId;
-        protected final LocalSocket mSocket;
-        private final AtomicInteger mOpenedStreams = new AtomicInteger(2); // input and output.
-        private volatile boolean mConnected;
-        private byte[] mBuffer;
-
-        private ConnectionBase(int id, LocalSocket socket, boolean preconnected) {
-            mId = id;
-            mSocket = socket;
-            mConnected = preconnected;
-        }
-
-        protected ConnectionBase(int id, LocalSocket socket) {
-            this(id, socket, true);
-        }
-
-        protected ConnectionBase(int id) {
-            this(id, new LocalSocket(), false);
-        }
-
-        protected boolean connect(LocalSocketAddress address) {
-            assert !mConnected;
-            try {
-                mSocket.connect(address);
-                mConnected = true;
-                return true;
-            } catch (IOException e) {
-                onSocketException(e, mId);
-                return false;
-            }
-        }
-
-        protected void runReadingLoop() {
-            mBuffer = new byte[READING_BUFFER_SIZE];
-            try {
-                boolean open;
-                do {
-                    open = pump();
-                } while (open);
-            } catch (IOException e) {
-                onSocketException(e, mId);
-            } finally {
-                mBuffer = null;
-            }
-        }
-
-        private boolean pump() throws IOException {
-            int count = mSocket.getInputStream().read(mBuffer);
-            if (count <= 0)
-                return false;
-            sendToDataChannel(buildDataPacket(mId, mBuffer, count));
-            return true;
-        }
-
-        protected void writeData(byte[] data) {
-            // Called on writing thread.
-            try {
-                mSocket.getOutputStream().write(data);
-            } catch (IOException e) {
-                onSocketException(e, mId);
-            }
-        }
-
-        public void onReceivedDataPacket(final byte[] data) {
-            mWritingThread.execute(new Runnable() {
-                @Override
-                public void run() {
-                    writeData(data);
-                }
-            });
-        }
-
-        public void terminate() {
-            close();
-        }
-
-        protected void shutdownOutput() {
-            // Shutdown output on writing thread to make sure all pending writes finished.
-            mWritingThread.execute(new Runnable() {
-                @Override
-                public void run() {
-                    shutdownOutputOnWritingThread();
-                }
-            });
-        }
-
-        private void shutdownOutputOnWritingThread() {
-            try {
-                if (mConnected) mSocket.shutdownOutput();
-            } catch (IOException e) {
-                onSocketException(e, mId);
-            }
-            releaseStream();
-        }
-
-        protected void shutdownInput() {
-            try {
-                if (mConnected) mSocket.shutdownInput();
-            } catch (IOException e) {
-                onSocketException(e, mId);
-            }
-            releaseStream();
-        }
-
-        private void releaseStream() {
-            if (mOpenedStreams.decrementAndGet() == 0) close();
-        }
-
-        protected void close() {
-            try {
-                mSocket.close();
-            } catch (IOException e) {
-                onSocketException(e, mId);
-            }
-        }
-    }
-}
diff --git a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/SocketTunnelClient.java b/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/SocketTunnelClient.java
deleted file mode 100644
index 97e7c327..0000000
--- a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/SocketTunnelClient.java
+++ /dev/null
@@ -1,314 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge;
-
-import android.net.LocalServerSocket;
-import android.net.LocalSocket;
-import android.util.Log;
-
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.atomic.AtomicReference;
-
-/**
- * Listens LocalServerSocket and tunnels all connections to the SocketTunnelServer.
- */
-public class SocketTunnelClient extends SocketTunnelBase {
-    private static final String TAG = "SocketTunnelClient";
-
-    private enum State {
-        INITIAL, RUNNING, STOPPED
-    }
-
-    private final AtomicReference<State> mState = new AtomicReference<State>(State.INITIAL);
-
-    private final LocalServerSocket mSocket;
-    private final ExecutorService mThreadPool = Executors.newCachedThreadPool();
-
-    // Connections with opened server to client stream. Always accesses on signaling thread.
-    private final Map<Integer, Connection> mServerConnections =
-            new HashMap<Integer, Connection>();
-
-    // Accepted connections are kept here until server returns SERVER_OPEN_ACK or SERVER_CLOSE.
-    // New connections are added in the listening loop, checked and removed on signaling thread.
-    // So add/read/remove synchronized through message round trip.
-    private final ConcurrentMap<Integer, Connection> mPendingConnections =
-            new ConcurrentHashMap<Integer, Connection>();
-
-    private final IdRegistry mIdRegistry = new IdRegistry(MIN_CONNECTION_ID, MAX_CONNECTION_ID, 2);
-
-    /**
-     * This class responsible for generating valid connection IDs. It count usage of connection:
-     * one user for client to server stream and one for server to client one. When both are closed
-     * it's safe to reuse ID.
-     */
-    private static final class IdRegistry {
-        private final int[] mLocks;
-        private final int mMin;
-        private final int mMax;
-        private final int mMaxLocks;
-        private final Object mLock = new Object();
-
-        public IdRegistry(int minId, int maxId, int maxLocks) {
-            assert minId < maxId;
-            assert maxLocks > 0;
-
-            mMin = minId;
-            mMax = maxId;
-            mMaxLocks = maxLocks;
-            mLocks = new int[maxId - minId + 1];
-        }
-
-        public void lock(int id) {
-            synchronized (mLock) {
-                int index = toIndex(id);
-                if (mLocks[index] == 0 || mLocks[index] == mMaxLocks) {
-                    throw new RuntimeException();
-                }
-                mLocks[index]++;
-            }
-        }
-
-        public void release(int id) {
-            synchronized (mLock) {
-                int index = toIndex(id);
-                if (mLocks[index] == 0) {
-                    throw new RuntimeException("Releasing unlocked id " + Integer.toString(id));
-                }
-                mLocks[index]--;
-            }
-        }
-
-        public boolean isLocked(int id) {
-            synchronized (mLock) {
-                return mLocks[toIndex(id)] > 0;
-            }
-        }
-
-        public int generate() throws NoIdAvailableException {
-            synchronized (mLock) {
-                for (int id = mMin; id != mMax; id++) {
-                    int index = toIndex(id);
-                    if (mLocks[index] == 0) {
-                        mLocks[index] = 1;
-                        return id;
-                    }
-                }
-            }
-            throw new NoIdAvailableException();
-        }
-
-        private int toIndex(int id) {
-            if (id < mMin || id > mMax) {
-                throw new RuntimeException();
-            }
-            return id - mMin;
-        }
-    }
-
-    private static class NoIdAvailableException extends Exception {}
-
-    public SocketTunnelClient(String socketName) throws IOException {
-        mSocket = new LocalServerSocket(socketName);
-    }
-
-    public boolean hasConnections() {
-        return mServerConnections.size() + mPendingConnections.size() > 0;
-    }
-
-    @Override
-    public AbstractDataChannel unbind() {
-        AbstractDataChannel dataChannel = super.unbind();
-        if (mState.compareAndSet(State.RUNNING, State.STOPPED)) {
-            terminateAllConnections();
-            closeSocket();
-        }
-        return dataChannel;
-    }
-
-    @Override
-    public void dispose() {
-        if (mState.compareAndSet(State.INITIAL, State.STOPPED)) {
-            closeSocket();
-        }
-        assert mState.get() == State.STOPPED;
-        mThreadPool.shutdown();
-    }
-
-    @Override
-    protected void onReceivedDataPacket(int connectionId, byte[] data) throws ProtocolError {
-        checkCalledOnSignalingThread();
-
-        if (!mServerConnections.containsKey(connectionId))
-            throw new ProtocolError("Unknows connection id");
-
-        mServerConnections.get(connectionId).onReceivedDataPacket(data);
-    }
-
-    @Override
-    protected void onReceivedControlPacket(int connectionId, byte opCode) throws ProtocolError {
-        switch (opCode) {
-            case SERVER_OPEN_ACK:
-                onServerOpenAck(connectionId);
-                break;
-
-            case SERVER_CLOSE:
-                onServerClose(connectionId);
-                break;
-
-            default:
-                throw new ProtocolError("Invalid opCode");
-        }
-    }
-
-    private void onServerOpenAck(int connectionId) throws ProtocolError {
-        checkCalledOnSignalingThread();
-
-        if (mServerConnections.containsKey(connectionId)) {
-            throw new ProtocolError("Connection already acknowledged");
-        }
-
-        if (!mPendingConnections.containsKey(connectionId)) {
-            throw new ProtocolError("Unknow connection id");
-        }
-
-        // Check/get is safe since it can be only removed on this thread.
-        Connection connection = mPendingConnections.get(connectionId);
-        mPendingConnections.remove(connectionId);
-
-        mServerConnections.put(connectionId, connection);
-
-        // Lock for client to server stream.
-        mIdRegistry.lock(connectionId);
-        mThreadPool.execute(connection);
-    }
-
-    private void onServerClose(int connectionId) throws ProtocolError {
-        checkCalledOnSignalingThread();
-
-        if (mServerConnections.containsKey(connectionId)) {
-            Connection connection = mServerConnections.get(connectionId);
-            mServerConnections.remove(connectionId);
-            mIdRegistry.release(connectionId); // Release sever to client stream.
-            connection.closedByServer();
-        } else if (mPendingConnections.containsKey(connectionId)) {
-            Connection connection = mPendingConnections.get(connectionId);
-            mPendingConnections.remove(connectionId);
-            connection.closedByServer();
-            sendToDataChannel(buildControlPacket(connectionId, CLIENT_CLOSE));
-            mIdRegistry.release(connectionId); // Release sever to client stream.
-        } else {
-            throw new ProtocolError("Closing unknown connection");
-        }
-    }
-
-    @Override
-    protected void onDataChannelOpened() {
-        if (!mState.compareAndSet(State.INITIAL, State.RUNNING)) {
-            throw new InvalidStateException();
-        }
-
-        mThreadPool.execute(new Runnable() {
-            @Override
-            public void run() {
-                runListenLoop();
-            }
-        });
-    }
-
-    @Override
-    protected void onDataChannelClosed() {
-        // All new connections will be rejected.
-        if (!mState.compareAndSet(State.RUNNING, State.STOPPED)) {
-            throw new InvalidStateException();
-        }
-
-        closeSocket();
-    }
-
-    private void terminateAllConnections() {
-
-        for (Connection connection : mServerConnections.values()) {
-            connection.terminate();
-        }
-
-        for (Connection connection : mPendingConnections.values()) {
-            connection.terminate();
-        }
-
-        closeSocket();
-    }
-
-    private void closeSocket() {
-        try {
-            mSocket.close();
-        } catch (IOException e) {
-            Log.d(TAG, "Failed to close socket: " + e);
-            onSocketException(e, -1);
-        }
-    }
-
-    private void runListenLoop() {
-        try {
-            while (true) {
-                LocalSocket socket = mSocket.accept();
-                State state = mState.get();
-                if (mState.get() == State.RUNNING) {
-                    // Make sure no socket processed when stopped.
-                    clientOpenConnection(socket);
-                } else {
-                    socket.close();
-                }
-            }
-        } catch (IOException e) {
-            if (mState.get() != State.RUNNING) {
-                onSocketException(e, -1);
-            }
-            // Else exception expected (socket closed).
-        }
-    }
-
-    private void clientOpenConnection(LocalSocket socket) throws IOException {
-        try {
-            int id = mIdRegistry.generate();  // id generated locked for server to client stream.
-            Connection connection = new Connection(id, socket);
-            mPendingConnections.put(id, connection);
-            sendToDataChannel(buildControlPacket(id, CLIENT_OPEN));
-        } catch (NoIdAvailableException e) {
-            socket.close();
-        }
-    }
-
-    private final class Connection extends ConnectionBase implements Runnable {
-        public Connection(int id, LocalSocket socket) {
-            super(id, socket);
-        }
-
-        public void closedByServer() {
-            shutdownOutput();
-        }
-
-        @Override
-        public void run() {
-            assert mIdRegistry.isLocked(mId);
-
-            runReadingLoop();
-
-            shutdownInput();
-            sendToDataChannel(buildControlPacket(mId, CLIENT_CLOSE));
-            mIdRegistry.release(mId);  // Unlock for client to server stream.
-        }
-    }
-
-    /**
-     * Method called in inappropriate state.
-     */
-    public static class InvalidStateException extends RuntimeException {}
-}
diff --git a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/TestDevToolsBridgeService.java b/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/TestDevToolsBridgeService.java
deleted file mode 100644
index 39c8a03..0000000
--- a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/TestDevToolsBridgeService.java
+++ /dev/null
@@ -1,87 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge;
-
-import android.app.Notification;
-import android.app.PendingIntent;
-import android.content.Intent;
-import android.widget.Toast;
-
-import com.google.ipc.invalidation.external.client.contrib.MultiplexingGcmListener;
-
-/**
- * Service for manual testing DevToolsBridgeServer with GCD signaling.
- */
-public final class TestDevToolsBridgeService extends DevToolsBridgeServiceBase {
-    private static final String SOCKET_NAME = "chrome_shell_devtools_remote";
-    public final int NOTIFICATION_ID = 1;
-    public final String DISCONNECT_ALL_CLIENTS_ACTION =
-            "action.DISCONNECT_ALL_CLIENTS_ACTION";
-    public final String UPDATE_GCM_CHANNEL_ID_ACTION =
-            "action.UPDATE_GCM_CHANNEL_ID";
-
-    /**
-     * Redirects intents to the TestDevToolsBridgeService.
-     */
-    public static final class Receiver extends ReceiverBase {
-        public Receiver() {
-            super(TestDevToolsBridgeService.class);
-        }
-    }
-
-    @Override
-    protected void querySocketName(DevToolsBridgeServer.QuerySocketCallback callback) {
-        callback.onSuccess(SOCKET_NAME);
-    }
-
-    @Override
-    protected void onFirstSessionStarted() {
-        startForeground(NOTIFICATION_ID, newForegroundNotification());
-    }
-
-    @Override
-    protected void onLastSessionStopped() {
-        stopForeground(true);
-    }
-
-    @Override
-    protected void onHandleIntent(Intent intent) {
-        if (DISCONNECT_ALL_CLIENTS_ACTION.equals(intent.getAction())) {
-            server().closeAllSessions();
-        } else if (UPDATE_GCM_CHANNEL_ID_ACTION.equals(intent.getAction())) {
-            String channelId = MultiplexingGcmListener.initializeGcm(this);
-            if (channelId.isEmpty()) {
-                Toast.makeText(this, "Not registered", Toast.LENGTH_SHORT).show();
-            } else {
-                server().updateCloudMessagesId(channelId, startTask());
-                Toast.makeText(this, "Updating. See log for results.", Toast.LENGTH_SHORT).show();
-            }
-        }
-    }
-
-    private PendingIntent newPendingIntent(String action) {
-        Intent intent = new Intent(this, getClass());
-        intent.setAction(action);
-        return PendingIntent.getService(this, 0, intent, 0);
-    }
-
-    private Notification newForegroundNotification() {
-        return new Notification.Builder(this)
-                // Mandatory fields
-                .setSmallIcon(android.R.drawable.alert_dark_frame)
-                .setContentTitle("TestDevToolsBridgeService")
-                .setContentText("Remote debugger connected")
-
-                // Optional
-                .addAction(android.R.drawable.ic_delete,
-                        "Disconnect", newPendingIntent(DISCONNECT_ALL_CLIENTS_ACTION))
-                .addAction(android.R.drawable.ic_menu_manage,
-                        "Update GCM channel", newPendingIntent(UPDATE_GCM_CHANNEL_ID_ACTION))
-                .setOngoing(true)
-                .setWhen(System.currentTimeMillis())
-
-                .build();
-    }
-}
diff --git a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/TestUtils.java b/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/TestUtils.java
deleted file mode 100644
index 5a280e73..0000000
--- a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/TestUtils.java
+++ /dev/null
@@ -1,137 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge;
-
-import android.net.LocalSocket;
-import android.net.LocalSocketAddress;
-
-import java.io.IOException;
-import java.util.concurrent.Callable;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
-
-/**
- * Utilities to testing a socket tunnel.
- */
-public class TestUtils {
-    private static final String CHARSET = "UTF-8";
-
-    // Sends |request| string to UNIX socket socketName on another thread and returns
-    // Future<String> for obtainings response.
-    public static Future<String> asyncRequest(final String socketName, final String request) {
-
-        final ExecutorService executor = Executors.newSingleThreadExecutor();
-
-        return executor.submit(new Callable<String>() {
-            @Override
-            public String call() throws Exception {
-                LocalSocket socket = new LocalSocket();
-                socket.connect(new LocalSocketAddress(socketName));
-                write(socket, request);
-
-                String response = readAll(socket);
-                socket.close();
-
-                executor.shutdown();
-                return response;
-            }
-        });
-    }
-
-    public static void write(LocalSocket socket, String data) throws IOException {
-        socket.getOutputStream().write(data.getBytes(CHARSET));
-        socket.getOutputStream().flush();
-    }
-
-    // Reads all bytes from socket input stream until EOF and converts it to UTF-8 string.
-    public static String read(LocalSocket socket, int length) throws IOException {
-        byte[] buffer = new byte[length];
-        int position = 0;
-        while (position < buffer.length) {
-            int count = socket.getInputStream().read(buffer, position, buffer.length - position);
-            if (count == -1)
-                break;
-            position += count;
-        }
-        return new String(buffer, 0, position, CHARSET);
-    }
-
-    public static String readAll(LocalSocket socket) throws IOException {
-        return read(socket, 1000);
-    }
-
-    /**
-     * Utility class for thread synchronization. Allow to track moving through series of steps.
-     */
-    public static class StateBarrier<T> {
-        private T mState;
-        private final Object mLock = new Object();
-
-        public StateBarrier(T initialState) {
-            mState = initialState;
-        }
-
-        // Waits until state |from| reached and change state to |to|.
-        public void advance(T from, T to) {
-            synchronized (mLock) {
-                while (mState.equals(from)) {
-                    try {
-                        mLock.wait();
-                    } catch (InterruptedException e) {
-                        throw new RuntimeException(e);
-                    }
-                }
-                mState = to;
-                mLock.notifyAll();
-            }
-        }
-    }
-
-    /**
-     * Helper with runs code on another thread and synchronously take the result.
-     */
-    public static class InvokeHelper<T> {
-        private final CountDownLatch mDone = new CountDownLatch(1);
-
-        private T mResult = null;
-        private Exception mException = null;
-
-        public void runOnTargetThread(Callable<T> callable) {
-            try {
-                mResult = callable.call();
-            } catch (Exception e) {
-                mException = e;
-            }
-            mDone.countDown();
-        }
-
-        public T takeResult() throws Exception {
-            mDone.await();
-            if (mException != null)
-                throw mException;
-            else
-                return mResult;
-        }
-    }
-
-    /**
-     * Adapts Runnable to Callable<Void>.
-     */
-    public static class RunnableAdapter implements Callable<Void> {
-        private final Runnable mAdaptee;
-
-        public RunnableAdapter(Runnable adaptee) {
-            mAdaptee = adaptee;
-        }
-
-        @Override
-        public Void call() {
-            mAdaptee.run();
-            return null;
-        }
-    }
-}
diff --git a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/apiary/TestApiaryClientFactory.java b/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/apiary/TestApiaryClientFactory.java
deleted file mode 100644
index c0b235b..0000000
--- a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/apiary/TestApiaryClientFactory.java
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge.apiary;
-
-/**
- * Implementation of ApiaryClientFactory for manual testing.
- */
-public class TestApiaryClientFactory extends ApiaryClientFactory {
-    public TestGCDClient newTestGCDClient(String oAuthToken) {
-        return new TestGCDClient(mHttpClient, getAPIKey(), oAuthToken);
-    }
-
-    public TurnConfigClient newConfigClient() {
-        return new TurnConfigClient(mHttpClient);
-    }
-}
diff --git a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/apiary/TestGCDClient.java b/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/apiary/TestGCDClient.java
deleted file mode 100644
index 397a2515..0000000
--- a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/apiary/TestGCDClient.java
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge.apiary;
-
-import android.util.JsonReader;
-
-import org.apache.http.client.HttpClient;
-
-import org.chromium.components.devtools_bridge.commands.Command;
-import org.chromium.components.devtools_bridge.gcd.RemoteInstance;
-import org.chromium.components.devtools_bridge.gcd.TestMessageReader;
-import org.chromium.components.devtools_bridge.gcd.TestMessageWriter;
-
-import java.io.IOException;
-import java.util.List;
-
-/**
- * Extension of GCDClient with methods needed for the testing app.
- */
-public class TestGCDClient extends GCDClient {
-    private static final String SEND_TIMEOUT_MS = "20000";
-
-    TestGCDClient(HttpClient httpClient, String apiKey, String oAuthToken) {
-        super(httpClient, apiKey, oAuthToken);
-        assert oAuthToken != null;
-    }
-
-    public List<RemoteInstance> fetchInstances() throws IOException {
-        return mHttpClient.execute(
-                newHttpGet("/devices"),
-                new JsonResponseHandler<List<RemoteInstance>>() {
-                    @Override
-                    public List<RemoteInstance> readResponse(JsonReader reader)
-                            throws IOException {
-                        return new TestMessageReader(reader).readRemoteInstances();
-                    }
-                });
-    }
-
-    public void send(String remoteInstanceId, final Command command) throws IOException {
-        String query = "expireInMs=" + SEND_TIMEOUT_MS
-                + "&responseAwaitMs=" + SEND_TIMEOUT_MS;
-
-        String content = new TestMessageWriter().writeCommand(remoteInstanceId, command)
-                .close().toString();
-
-        mHttpClient.execute(
-                newHttpPost("/commands", query, content),
-                new JsonResponseHandler<Boolean>() {
-                    @Override
-                    public Boolean readResponse(JsonReader reader) throws IOException {
-                        new TestMessageReader(reader).readCommandResult(command);
-                        return Boolean.TRUE;
-                    }
-                });
-    }
-}
diff --git a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/apiary/TurnConfigClient.java b/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/apiary/TurnConfigClient.java
deleted file mode 100644
index 2b26938..0000000
--- a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/apiary/TurnConfigClient.java
+++ /dev/null
@@ -1,76 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge.apiary;
-
-import android.util.JsonReader;
-
-import org.apache.http.client.HttpClient;
-import org.apache.http.client.methods.HttpGet;
-
-import org.chromium.components.devtools_bridge.RTCConfiguration;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Client for fetching TURN configuration form a demo server.
- */
-public final class TurnConfigClient {
-    private static final String URL =
-            "http://computeengineondemand.appspot.com/turn?username=28230128&key=4080218913";
-    private static final String STUN_URL = "stun.l.google.com:19302";
-
-    private final HttpClient mHttpClient;
-
-    TurnConfigClient(HttpClient httpClient) {
-        mHttpClient = httpClient;
-    }
-
-    public RTCConfiguration fetch() throws IOException {
-        return mHttpClient.execute(
-                new HttpGet(URL), new ConfigResponseHandler());
-    }
-
-    private class ConfigResponseHandler extends JsonResponseHandler<RTCConfiguration> {
-        public RTCConfiguration readResponse(JsonReader reader) throws IOException {
-            List<String> uris = null;
-            String username = null;
-            String password = null;
-
-            reader.beginObject();
-            while (reader.hasNext()) {
-                String name = reader.nextName();
-                if ("username".equals(name)) {
-                    username = reader.nextString();
-                } else if ("password".equals(name)) {
-                    password = reader.nextString();
-                } else if ("uris".equals(name)) {
-                    uris = readStringList(reader);
-                } else {
-                    reader.skipValue();
-                }
-            }
-            reader.endObject();
-
-            RTCConfiguration.Builder builder = new RTCConfiguration.Builder();
-            builder.addIceServer(STUN_URL);
-            for (String uri : uris) {
-                builder.addIceServer(uri, username, password);
-            }
-            return builder.build();
-        }
-    }
-
-    private List<String> readStringList(JsonReader reader) throws IOException {
-        ArrayList<String> result = new ArrayList<String>();
-        reader.beginArray();
-        while (reader.hasNext()) {
-            result.add(reader.nextString());
-        }
-        reader.endArray();
-        return result;
-    }
-}
diff --git a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/commands/CommandSender.java b/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/commands/CommandSender.java
deleted file mode 100644
index 2bb4d7d..0000000
--- a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/commands/CommandSender.java
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge.commands;
-
-import org.chromium.components.devtools_bridge.RTCConfiguration;
-import org.chromium.components.devtools_bridge.SessionBase;
-import org.chromium.components.devtools_bridge.SignalingReceiver;
-
-import java.util.List;
-
-/**
- * Implementation of SignalingReceiver which wraps each call into a Command object.
- */
-public abstract class CommandSender implements SignalingReceiver {
-    protected abstract void send(Command command, Runnable completionCallback);
-
-    @Override
-    public void startSession(
-            String sessionId, RTCConfiguration config, String offer,
-            final SessionBase.NegotiationCallback callback) {
-        final Commands.StartSessionCommand command =
-                new Commands.StartSessionCommand(sessionId, config, offer);
-        send(command, new Runnable() {
-            @Override
-            public void run() {
-                if (!handleFailure(command, callback)) {
-                    callback.onSuccess(command.getResult());
-                }
-            }
-        });
-    }
-
-    @Override
-    public void renegotiate(
-            String sessionId, String offer, final SessionBase.NegotiationCallback callback) {
-        final Commands.RenegotiateCommand command =
-                new Commands.RenegotiateCommand(sessionId, offer);
-        send(command, new Runnable() {
-            @Override
-            public void run() {
-                if (!handleFailure(command, callback)) {
-                    callback.onSuccess(command.getResult());
-                }
-            }
-        });
-    }
-
-    @Override
-    public void iceExchange(
-            String sessionId, List<String> clientCandidates,
-            final SessionBase.IceExchangeCallback callback) {
-        final Commands.IceExchangeCommand command =
-                new Commands.IceExchangeCommand(sessionId, clientCandidates);
-        send(command, new Runnable() {
-            @Override
-            public void run() {
-                if (!handleFailure(command, callback)) {
-                    callback.onSuccess(command.getResult());
-                }
-            }
-        });
-    }
-
-    private static boolean handleFailure(Command command, SessionBase.ServerCallback callback) {
-        if (command.state() == Command.State.DONE) return false;
-        if (command.state() == Command.State.ERROR) {
-            callback.onFailure(command.getErrorMessage());
-        } else {
-            callback.onFailure("Invalid command state: " + command.state());
-        }
-        return true;
-    }
-}
diff --git a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/gcd/RemoteInstance.java b/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/gcd/RemoteInstance.java
deleted file mode 100644
index 7379bd5..0000000
--- a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/gcd/RemoteInstance.java
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge.gcd;
-
-/**
- * Remote DevTools bridge instance (for testing app).
- */
-public final class RemoteInstance {
-    public final String id;
-    public final String displayName;
-
-    public RemoteInstance(String id, String displayName) {
-        assert id != null;
-        assert displayName != null;
-
-        this.id = id;
-        this.displayName = displayName;
-    }
-
-    @Override
-    public String toString() {
-        return displayName + ": " + id;
-    }
-}
diff --git a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/gcd/TestMessageReader.java b/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/gcd/TestMessageReader.java
deleted file mode 100644
index 3505af8..0000000
--- a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/gcd/TestMessageReader.java
+++ /dev/null
@@ -1,124 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge.gcd;
-
-import android.util.JsonReader;
-import android.util.Log;
-
-import org.chromium.components.devtools_bridge.commands.Command;
-import org.chromium.components.devtools_bridge.commands.CommandFormatException;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Reader for additional messages (used only in the testing app).
- */
-public final class TestMessageReader {
-    private static final String TAG = "TestMessageReader";
-
-    private final JsonReader mReader;
-
-    public TestMessageReader(JsonReader reader) {
-        mReader = reader;
-    }
-
-    public List<RemoteInstance> readRemoteInstances() throws IOException {
-        final List<RemoteInstance> result = new ArrayList<RemoteInstance>();
-
-        mReader.beginObject();
-        while (mReader.hasNext()) {
-            String name = mReader.nextName();
-            if (name.equals("devices")) {
-                mReader.beginArray();
-                while (mReader.hasNext()) {
-                    result.add(readInstance());
-                }
-                mReader.endArray();
-            } else {
-                mReader.skipValue();
-            }
-        }
-        mReader.endObject();
-        return result;
-    }
-
-    private RemoteInstance readInstance() throws IOException {
-        String id = null;
-        String displayName = null;
-
-        mReader.beginObject();
-        while (mReader.hasNext()) {
-            String name = mReader.nextName();
-            if (name.equals("id")) {
-                id = mReader.nextString();
-            } else if (name.equals("displayName")) {
-                displayName = mReader.nextString();
-            } else {
-                mReader.skipValue();
-            }
-        }
-        mReader.endObject();
-        if (id == null) {
-            throw new IllegalArgumentException("Missing remote instance id");
-        }
-        if (displayName == null) {
-            throw new IllegalArgumentException("Missing remote instance display name");
-        }
-        return new RemoteInstance(id, displayName);
-    }
-
-    public void readCommandResult(Command command) throws IOException {
-        String state = null;
-        Map<String, String> outParams = null;
-        String errorMessage = null;
-
-        mReader.beginObject();
-        while (mReader.hasNext()) {
-            String name = mReader.nextName();
-            if (name.equals("state")) {
-                state = mReader.nextString();
-            } else if (name.equals("results")) {
-                outParams = MessageReader.readStringMap(mReader);
-            } else if (name.equals("error")) {
-                errorMessage = readErrorMessage();
-            } else {
-                mReader.skipValue();
-            }
-        }
-        mReader.endObject();
-
-        if ("done".equals(state) && outParams != null) {
-            try {
-                command.setSuccess(outParams);
-            } catch (CommandFormatException e) {
-                Log.e(TAG, "Invalid command format", e);
-                command.setFailure("Invalid format: " + e.getMessage());
-            }
-        } else if ("error".equals(state) && errorMessage != null) {
-            Log.w(TAG, "Command error: " + errorMessage);
-            command.setFailure(errorMessage);
-        } else {
-            Log.w(TAG, "Invalid command state: " + state);
-            command.setFailure("Invalid state: " + state);
-        }
-    }
-
-    private String readErrorMessage() throws IOException {
-        String result = null;
-        mReader.beginObject();
-        while (mReader.hasNext()) {
-            if (mReader.nextName().equals("message")) {
-                result = mReader.nextString();
-            } else {
-                mReader.skipValue();
-            }
-        }
-        mReader.endObject();
-        return result;
-    }
-}
diff --git a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/gcd/TestMessageWriter.java b/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/gcd/TestMessageWriter.java
deleted file mode 100644
index 1d4d75b7..0000000
--- a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/gcd/TestMessageWriter.java
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge.gcd;
-
-import android.util.JsonWriter;
-
-import org.chromium.components.devtools_bridge.commands.Command;
-import org.chromium.components.devtools_bridge.commands.ParamDefinition;
-
-import java.io.IOException;
-import java.io.StringWriter;
-
-/**
- * Helper class for constructing GCD JSON messages (HTTP requests) used in the DevTools bridge.
- */
-public final class TestMessageWriter {
-    private final StringWriter mStringWriter;
-    private final JsonWriter mWriter;
-    boolean mClosed = false;
-
-    public TestMessageWriter() {
-        mStringWriter = new StringWriter();
-        mWriter = new JsonWriter(mStringWriter);
-    }
-
-    public TestMessageWriter close() throws IOException {
-        assert !mClosed;
-        mWriter.close();
-        mClosed = true;
-        return this;
-    }
-
-    @Override
-    public String toString() {
-        assert mClosed;
-        return mStringWriter.toString();
-    }
-
-    public TestMessageWriter writeCommand(
-            String remoteInstanceId, Command command) throws IOException {
-        mWriter.beginObject()
-                .name("deviceId").value(remoteInstanceId)
-                .name("name").value(command.type.definition.fullName());
-
-        mWriter.name("parameters").beginObject();
-        command.visitInParams(new Command.ParamVisitor() {
-            @Override
-            public void visit(ParamDefinition<?> param, String value) {
-                try {
-                    mWriter.name(param.name()).value(value);
-                } catch (IOException e) {
-                    // IO excepion must not happen since we writng to a string.
-                    throw new RuntimeException(e);
-                }
-            }
-        });
-        mWriter.endObject();
-
-        mWriter.endObject();
-
-        return this;
-    }
-}
diff --git a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/ui/RemoteInstanceListFragment.java b/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/ui/RemoteInstanceListFragment.java
deleted file mode 100644
index 8441da0e..0000000
--- a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/ui/RemoteInstanceListFragment.java
+++ /dev/null
@@ -1,350 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge.ui;
-
-import android.accounts.Account;
-import android.accounts.AccountManager;
-import android.accounts.AccountManagerCallback;
-import android.accounts.AccountManagerFuture;
-import android.app.Activity;
-import android.app.ListFragment;
-import android.content.Intent;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.util.Log;
-import android.view.ContextMenu;
-import android.view.LayoutInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ArrayAdapter;
-import android.widget.ListView;
-import android.widget.Toast;
-
-import org.chromium.components.devtools_bridge.RTCConfiguration;
-import org.chromium.components.devtools_bridge.SessionBase;
-import org.chromium.components.devtools_bridge.apiary.ApiaryClientFactory;
-import org.chromium.components.devtools_bridge.apiary.TestApiaryClientFactory;
-import org.chromium.components.devtools_bridge.commands.Command;
-import org.chromium.components.devtools_bridge.commands.CommandSender;
-import org.chromium.components.devtools_bridge.gcd.RemoteInstance;
-
-import java.io.IOException;
-import java.util.List;
-
-/**
- * Fragment of application for manual testing the DevTools bridge. Shows instances
- * registered in GCD and lets unregister them.
- */
-public abstract class RemoteInstanceListFragment extends ListFragment {
-    private static final String TAG = "RemoteInstanceListFragment";
-    private static final String NO_ID = "";
-    private static final int CODE_ACCOUNT_SELECTED = 1;
-
-    private final TestApiaryClientFactory mClientFactory = new TestApiaryClientFactory();
-    private ArrayAdapter<RemoteInstance> mListAdapter;
-    private String mOAuthToken;
-    private RemoteInstance mSelected;
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        mListAdapter = new ArrayAdapter<RemoteInstance>(
-                getActivity(), android.R.layout.simple_list_item_1);
-        new UpdateListAction().execute();
-        setListAdapter(mListAdapter);
-    }
-
-    @Override
-    public void onDestroy() {
-        new AsyncTask<Void, Void, Void>() {
-            @Override
-            protected final Void doInBackground(Void... args) {
-                mClientFactory.close();
-                return null;
-            }
-        }.execute();
-        super.onDestroy();
-    }
-
-    @Override
-    public View onCreateView(
-            LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
-        View root = super.onCreateView(inflater, container, savedInstanceState);
-        registerForContextMenu(root);
-        return root;
-    }
-
-    @Override
-    public void onListItemClick(ListView listView, View view, int position, long id) {
-        mSelected = mListAdapter.getItem(position);
-        if (mOAuthToken == null) {
-            signIn();
-        } else {
-            getActivity().openContextMenu(view);
-        }
-    }
-
-    @Override
-    public void onCreateContextMenu(
-            ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) {
-        super.onCreateContextMenu(menu, view, menuInfo);
-
-        if (mOAuthToken == null) return;
-
-        menu.add("Connect")
-                .setOnMenuItemClickListener(new ConnectAction())
-                .setEnabled(mSelected != null);
-        menu.add("Send invalid offer")
-                .setOnMenuItemClickListener(new SendInvalidOfferAction())
-                .setEnabled(mSelected != null);
-        menu.add("Delete")
-                .setOnMenuItemClickListener(new DeleteInstanceAction(mSelected))
-                .setEnabled(mSelected != null);
-        menu.add("Update list")
-                .setOnMenuItemClickListener(new UpdateListAction());
-        menu.add("Delete all")
-                .setOnMenuItemClickListener(new DeleteAllAction());
-    }
-
-    public void signIn() {
-        AccountManager manager = AccountManager.get(getActivity());
-
-        Intent intent = manager.newChooseAccountIntent(
-                null /* selectedAccount */,
-                null /* allowableAccounts */,
-                new String[] { "com.google" } /* allowableAccountTypes */,
-                true /* alwaysPromptForAccount */,
-                "Sign into GCD" /* descriptionOverrideText */,
-                null /* addAccountAuthTokenType */,
-                null /* addAccountRequiredFeatures */,
-                null /* addAccountOptions */);
-        startActivityForResult(intent, CODE_ACCOUNT_SELECTED);
-    }
-
-    @Override
-    public void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
-        if (requestCode == CODE_ACCOUNT_SELECTED && resultCode == Activity.RESULT_OK) {
-            queryOAuthToken(new Account(
-                    data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME),
-                    data.getStringExtra(AccountManager.KEY_ACCOUNT_TYPE)));
-        }
-    }
-
-    protected abstract void connect(String oAuthToken, String remoteInstanceId);
-
-    public void queryOAuthToken(Account accout) {
-        AccountManager manager = AccountManager.get(getActivity());
-
-        manager.getAuthToken(
-                accout,
-                "oauth2:" + ApiaryClientFactory.OAUTH_SCOPE, null /* options */, getActivity(),
-                new AccountManagerCallback<Bundle>() {
-                    @Override
-                    public void run(AccountManagerFuture<Bundle> future) {
-                        try {
-                            mOAuthToken = future.getResult().getString(
-                                    AccountManager.KEY_AUTHTOKEN);
-                            updateList();
-                        } catch (Exception e) {
-                            Log.d(TAG, "Failed to get token: ", e);
-                        }
-                    }
-                }, null);
-    }
-
-    public void updateList() {
-        new UpdateListAction().execute();
-    }
-
-    private final class ConnectAction implements MenuItem.OnMenuItemClickListener {
-        @Override
-        public boolean onMenuItemClick(MenuItem item) {
-            if (mOAuthToken != null && mSelected != null) {
-                connect(mOAuthToken, mSelected.id);
-                return true;
-            }
-            return false;
-        }
-    }
-
-    private abstract class AsyncAction extends AsyncTask<Void, Void, Boolean>
-            implements MenuItem.OnMenuItemClickListener {
-        private final String mActionName;
-
-        protected AsyncAction(String actionName) {
-            mActionName = actionName;
-        }
-
-        @Override
-        public boolean onMenuItemClick(MenuItem item) {
-            execute();
-            return true;
-        }
-
-        @Override
-        protected final Boolean doInBackground(Void... args) {
-            try {
-                doInBackgroundImpl();
-                return Boolean.TRUE;
-            } catch (IOException e) {
-                Log.e(TAG, mActionName + " failed", e);
-                return Boolean.FALSE;
-            }
-        }
-
-        @Override
-        protected void onPostExecute(Boolean success) {
-            if (Boolean.TRUE.equals(success)) {
-                onSuccess();
-                showToast(mActionName + " completed");
-            } else {
-                onFailure();
-                showToast(mActionName + " failed");
-            }
-        }
-
-        protected void showToast(String message) {
-            Toast.makeText(getActivity(), message, Toast.LENGTH_SHORT).show();
-        }
-
-        protected abstract void doInBackgroundImpl() throws IOException;
-        protected abstract void onSuccess();
-        protected void onFailure() {}
-    }
-
-    private final class SendInvalidOfferAction extends AsyncAction {
-        private final String mOAuthTokenCopy = mOAuthToken;
-        private final RemoteInstance mSelectedCopy = mSelected;
-        private IOException mException;
-
-        public SendInvalidOfferAction() {
-            super("Sending invalid offer");
-        }
-
-        @Override
-        protected final void doInBackgroundImpl() throws IOException {
-            if (mOAuthTokenCopy == null || mSelected == null) {
-                throw new IOException("Action cann't be applied.");
-            }
-
-            final String sessionId = "sessionId";
-            final String offer = "INVALID_OFFER";
-            final RTCConfiguration config = new RTCConfiguration();
-
-            CommandSender sender = new CommandSender() {
-                @Override
-                protected void send(Command command, Runnable completionCallback) {
-                    try {
-                        mClientFactory.newTestGCDClient(mOAuthTokenCopy)
-                                .send(mSelectedCopy.id, command);
-                    } catch (IOException e) {
-                        mException = e;
-                        command.setFailure("IO exception");
-                    } finally {
-                        completionCallback.run();
-                    }
-                }
-            };
-
-            sender.startSession(sessionId, config, offer, new SessionBase.NegotiationCallback() {
-                @Override
-                public void onSuccess(String answer) {
-                    mException = new IOException("Unexpected success");
-                }
-
-                @Override
-                public void onFailure(String errorMessage) {
-                    Log.i(TAG, "Expected failure: " + errorMessage);
-                }
-            });
-
-            if (mException != null)
-                throw mException;
-        }
-
-        @Override
-        protected void onSuccess() {
-        }
-    }
-
-    private final class UpdateListAction extends AsyncAction {
-        private final String mOAuthTokenCopy = mOAuthToken;
-        private List<RemoteInstance> mResult;
-
-        public UpdateListAction() {
-            super("Updating instance list");
-        }
-
-        @Override
-        protected final void doInBackgroundImpl() throws IOException {
-            if (mOAuthTokenCopy == null) return;
-
-            mResult = mClientFactory.newTestGCDClient(mOAuthTokenCopy).fetchInstances();
-        }
-
-        @Override
-        protected void onSuccess() {
-            mListAdapter.clear();
-            if (mOAuthTokenCopy == null) {
-                mListAdapter.add(new RemoteInstance(NO_ID, "Sign in"));
-            } else if (mResult.size() > 0) {
-                mListAdapter.addAll(mResult);
-            } else {
-                mListAdapter.add(new RemoteInstance(NO_ID, "Empty list"));
-            }
-        }
-
-        @Override
-        protected void onFailure() {
-            mListAdapter.clear();
-            mListAdapter.add(new RemoteInstance(NO_ID, "Update failed"));
-        }
-
-        @Override
-        protected void showToast(String message) {}
-    }
-
-    private final class DeleteInstanceAction extends AsyncAction {
-        private final String mOAuthTokenCopy = mOAuthToken;
-        private final RemoteInstance mInstance;
-
-        public DeleteInstanceAction(RemoteInstance instance) {
-            super("Deleting instance");
-            mInstance = instance;
-        }
-
-        @Override
-        protected final void doInBackgroundImpl() throws IOException {
-            mClientFactory.newTestGCDClient(mOAuthTokenCopy).deleteInstance(mInstance.id);
-        }
-
-        @Override
-        protected void onSuccess() {
-            updateList();
-        }
-    }
-
-    private final class DeleteAllAction extends AsyncAction {
-        private final String mOAuthTokenCopy = mOAuthToken;
-
-        public DeleteAllAction() {
-            super("Deleting all");
-        }
-
-        @Override
-        protected final void doInBackgroundImpl() throws IOException {
-            for (RemoteInstance instance :
-                        mClientFactory.newTestGCDClient(mOAuthTokenCopy).fetchInstances()) {
-                mClientFactory.newTestGCDClient(mOAuthTokenCopy).deleteInstance(instance.id);
-            }
-        }
-
-        @Override
-        protected void onSuccess() {
-            updateList();
-        }
-    }
-}
diff --git a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/util/TestSource.java b/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/util/TestSource.java
deleted file mode 100644
index 9a53a39f..0000000
--- a/components/devtools_bridge/test/android/javatests/src/org/chromium/components/devtools_bridge/util/TestSource.java
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.devtools_bridge.util;
-
-import android.util.JsonReader;
-import android.util.JsonWriter;
-
-import java.io.StringReader;
-import java.io.StringWriter;
-
-/**
- * Helper class for testing JSON-based readers.
- */
-public class TestSource {
-    private final StringWriter mSource;
-    private final JsonWriter mSourceWriter;
-
-    public TestSource() {
-        mSource = new StringWriter();
-        mSourceWriter = new JsonWriter(mSource);
-    }
-
-    public JsonReader read() {
-        return new JsonReader(new StringReader(mSource.toString()));
-    }
-
-    public JsonWriter write() {
-        return mSourceWriter;
-    }
-}
diff --git a/components/devtools_http_handler/devtools_http_handler.cc b/components/devtools_http_handler/devtools_http_handler.cc
index 3c9a8e77..67c061c7c 100644
--- a/components/devtools_http_handler/devtools_http_handler.cc
+++ b/components/devtools_http_handler/devtools_http_handler.cc
@@ -813,13 +813,11 @@
   // Serialize value and message.
   std::string json_value;
   if (value) {
-    base::JSONWriter::WriteWithOptions(value,
-                                       base::JSONWriter::OPTIONS_PRETTY_PRINT,
-                                       &json_value);
+    base::JSONWriter::WriteWithOptions(
+        *value, base::JSONWriter::OPTIONS_PRETTY_PRINT, &json_value);
   }
   std::string json_message;
-  scoped_ptr<base::Value> message_object(new base::StringValue(message));
-  base::JSONWriter::Write(message_object.get(), &json_message);
+  base::JSONWriter::Write(base::StringValue(message), &json_message);
 
   net::HttpServerResponseInfo response(status_code);
   response.SetBody(json_value + message, "application/json; charset=UTF-8");
diff --git a/components/dom_distiller/core/distiller_page.cc b/components/dom_distiller/core/distiller_page.cc
index 8eb6585..74e6f1c 100644
--- a/components/dom_distiller/core/distiller_page.cc
+++ b/components/dom_distiller/core/distiller_page.cc
@@ -40,7 +40,7 @@
   scoped_ptr<base::Value> options_value(
       dom_distiller::proto::json::DomDistillerOptions::WriteToValue(options));
   std::string options_json;
-  if (!base::JSONWriter::Write(options_value.get(), &options_json)) {
+  if (!base::JSONWriter::Write(*options_value, &options_json)) {
     NOTREACHED();
   }
   size_t options_offset = script.find(kOptionsPlaceholder);
diff --git a/components/dom_distiller/core/page_features_unittest.cc b/components/dom_distiller/core/page_features_unittest.cc
index 413c55f7..1fee593 100644
--- a/components/dom_distiller/core/page_features_unittest.cc
+++ b/components/dom_distiller/core/page_features_unittest.cc
@@ -70,7 +70,7 @@
     // CalculateDerivedFeaturesFromJSON expects a base::Value of the stringified
     // JSON (and not a base::Value of the JSON itself)
     std::string stringified_json;
-    ASSERT_TRUE(base::JSONWriter::Write(core_features, &stringified_json));
+    ASSERT_TRUE(base::JSONWriter::Write(*core_features, &stringified_json));
     scoped_ptr<base::Value> stringified_value(
         new base::StringValue(stringified_json));
     std::vector<double> derived(
diff --git a/components/dom_distiller/core/viewer.cc b/components/dom_distiller/core/viewer.cc
index e19f378..0244a4f51 100644
--- a/components/dom_distiller/core/viewer.cc
+++ b/components/dom_distiller/core/viewer.cc
@@ -159,9 +159,9 @@
   std::string yes;
   std::string no;
 
-  base::JSONWriter::Write(&question_val, &question);
-  base::JSONWriter::Write(&yes_val, &yes);
-  base::JSONWriter::Write(&no_val, &no);
+  base::JSONWriter::Write(question_val, &question);
+  base::JSONWriter::Write(yes_val, &yes);
+  base::JSONWriter::Write(no_val, &no);
 
   return "showFeedbackForm(" + question + ", " + yes + ", " + no + ");";
 }
@@ -172,7 +172,7 @@
   std::string output(page_proto->html());
   EnsureNonEmptyContent(&output);
   base::StringValue value(output);
-  base::JSONWriter::Write(&value, &output);
+  base::JSONWriter::Write(value, &output);
   std::string page_update("addToPage(");
   page_update += output + ");";
   return page_update + GetToggleLoadingIndicatorJs(
@@ -184,7 +184,7 @@
   base::StringValue value(l10n_util::GetStringUTF8(
       IDS_DOM_DISTILLER_VIEWER_FAILED_TO_FIND_ARTICLE_CONTENT));
   std::string output;
-  base::JSONWriter::Write(&value, &output);
+  base::JSONWriter::Write(value, &output);
   std::string page_update("addToPage(");
   page_update += output + ");";
   return page_update;
@@ -226,8 +226,7 @@
 
   std::string output(unsafe_output_stream.str());
   EnsureNonEmptyContent(&output);
-  base::StringValue value(output);
-  base::JSONWriter::Write(&value, &output);
+  base::JSONWriter::Write(base::StringValue(output), &output);
   std::string page_update("addToPage(");
   page_update += output + ");";
   return page_update + GetToggleLoadingIndicatorJs(true);
diff --git a/components/domain_reliability/context.cc b/components/domain_reliability/context.cc
index 230581f..5a35090 100644
--- a/components/domain_reliability/context.cc
+++ b/components/domain_reliability/context.cc
@@ -223,9 +223,7 @@
   DCHECK(upload_time_.is_null());
   upload_time_ = time_->NowTicks();
   std::string report_json;
-  scoped_ptr<const Value> report_value(CreateReport(upload_time_));
-  base::JSONWriter::Write(report_value.get(), &report_json);
-  report_value.reset();
+  base::JSONWriter::Write(*CreateReport(upload_time_), &report_json);
 
   size_t collector_index = scheduler_.OnUploadStart();
 
@@ -281,7 +279,7 @@
       resources_value->Append(resource_report.release());
   }
 
-  DictionaryValue* report_value = new DictionaryValue();
+  scoped_ptr<DictionaryValue> report_value(new DictionaryValue());
   if (!config().version.empty())
     report_value->SetString("config_version", config().version);
   report_value->SetString("reporter", upload_reporter_string_);
@@ -289,7 +287,7 @@
   if (!resources_value->empty())
     report_value->Set("resources", resources_value.release());
 
-  return scoped_ptr<const Value>(report_value);
+  return report_value.Pass();
 }
 
 void DomainReliabilityContext::MarkUpload() {
diff --git a/components/domain_reliability/monitor.cc b/components/domain_reliability/monitor.cc
index 83a6af19..014f34d 100644
--- a/components/domain_reliability/monitor.cc
+++ b/components/domain_reliability/monitor.cc
@@ -11,7 +11,10 @@
 #include "base/task_runner.h"
 #include "base/time/time.h"
 #include "components/domain_reliability/baked_in_configs.h"
+#include "net/base/ip_endpoint.h"
 #include "net/base/load_flags.h"
+#include "net/base/net_errors.h"
+#include "net/base/net_util.h"
 #include "net/http/http_response_headers.h"
 #include "net/url_request/url_request.h"
 #include "net/url_request/url_request_context.h"
@@ -19,6 +22,55 @@
 
 namespace domain_reliability {
 
+namespace {
+
+int URLRequestStatusToNetError(const net::URLRequestStatus& status) {
+  switch (status.status()) {
+    case net::URLRequestStatus::SUCCESS:
+      return net::OK;
+    case net::URLRequestStatus::IO_PENDING:
+      return net::ERR_IO_PENDING;
+    case net::URLRequestStatus::CANCELED:
+      return net::ERR_ABORTED;
+    case net::URLRequestStatus::FAILED:
+      return status.error();
+    default:
+      NOTREACHED();
+      return net::ERR_UNEXPECTED;
+  }
+}
+
+// Updates the status, chrome_error, and server_ip fields of |beacon| from
+// the endpoint and result of |attempt|. If there is no matching status for
+// the result, returns false (which means the attempt should not result in a
+// beacon being reported).
+bool UpdateBeaconFromAttempt(DomainReliabilityBeacon* beacon,
+                             const net::ConnectionAttempt& attempt) {
+  if (!GetDomainReliabilityBeaconStatus(
+          attempt.result, beacon->http_response_code, &beacon->status)) {
+    return false;
+  }
+  beacon->chrome_error = attempt.result;
+  if (!attempt.endpoint.address().empty())
+    beacon->server_ip = attempt.endpoint.ToString();
+  else
+    beacon->server_ip = "";
+  return true;
+}
+
+// TODO(ttuttle): This function is absurd. See if |socket_address| in
+// HttpResponseInfo can become an IPEndPoint.
+bool ConvertHostPortPairToIPEndPoint(const net::HostPortPair& host_port_pair,
+                                     net::IPEndPoint* ip_endpoint_out) {
+  net::IPAddressNumber ip_address_number;
+  if (!net::ParseIPLiteralToNumber(host_port_pair.host(), &ip_address_number))
+    return false;
+  *ip_endpoint_out = net::IPEndPoint(ip_address_number, host_port_pair.port());
+  return true;
+}
+
+}  // namespace
+
 DomainReliabilityMonitor::DomainReliabilityMonitor(
     const std::string& upload_reporter_string,
     const scoped_refptr<base::SingleThreadTaskRunner>& pref_thread,
@@ -150,8 +202,9 @@
   if (!started)
     return;
   RequestInfo request_info(*request);
-  if (request_info.AccessedNetwork()) {
-    OnRequestLegComplete(request_info);
+  OnRequestLegComplete(request_info);
+
+  if (request_info.response_info.network_accessed) {
     // A request was just using the network, so now is a good time to run any
     // pending and eligible uploads.
     dispatcher_.RunEligibleTasks();
@@ -221,13 +274,27 @@
       load_flags(request.load_flags()),
       is_upload(DomainReliabilityUploader::URLRequestIsUpload(request)) {
   request.GetLoadTimingInfo(&load_timing_info);
+  request.GetConnectionAttempts(&connection_attempts);
 }
 
 DomainReliabilityMonitor::RequestInfo::~RequestInfo() {}
 
-bool DomainReliabilityMonitor::RequestInfo::AccessedNetwork() const {
-  return status.status() != net::URLRequestStatus::CANCELED &&
-     response_info.network_accessed;
+// static
+bool DomainReliabilityMonitor::RequestInfo::ShouldReportRequest(
+    const DomainReliabilityMonitor::RequestInfo& request) {
+  // Don't report requests for Domain Reliability uploads or that weren't
+  // supposed to send cookies.
+  if (request.is_upload)
+    return false;
+  if (request.load_flags & net::LOAD_DO_NOT_SEND_COOKIES)
+    return false;
+  // Report requests that accessed the network or failed with an error code
+  // that Domain Reliability is interested in.
+  if (request.response_info.network_accessed)
+    return true;
+  if (URLRequestStatusToNetError(request.status) != net::OK)
+    return true;
+  return false;
 }
 
 void DomainReliabilityMonitor::OnRequestLegComplete(
@@ -236,44 +303,30 @@
   DCHECK(OnNetworkThread());
   DCHECK(discard_uploads_set_);
 
+  if (!RequestInfo::ShouldReportRequest(request))
+    return;
+
   int response_code;
   if (request.response_info.headers.get())
     response_code = request.response_info.headers->response_code();
   else
     response_code = -1;
-  std::string beacon_status;
 
-  int error_code = net::OK;
-  if (request.status.status() == net::URLRequestStatus::FAILED)
-    error_code = request.status.error();
-
-  // Ignore requests where:
-  // 1. The request did not access the network.
-  // 2. The request is not supposed to send cookies (to avoid associating the
-  //    request with any potentially unique data in the config).
-  // 3. The request was itself a Domain Reliability upload (to avoid loops).
-  // 4. There is no matching beacon status for the error or HTTP response code
-  //    (to avoid leaking network-local errors).
-  if (!request.AccessedNetwork() ||
-      (request.load_flags & net::LOAD_DO_NOT_SEND_COOKIES) ||
-      request.is_upload ||
-      !GetDomainReliabilityBeaconStatus(
-          error_code, response_code, &beacon_status)) {
-    return;
-  }
-
-  DomainReliabilityBeacon beacon;
-  beacon.status = beacon_status;
-  beacon.chrome_error = error_code;
-  // If the response was cached, the socket address was the address that the
-  // response was originally received from, so it shouldn't be copied into the
-  // beacon.
-  //
-  // TODO(ttuttle): Wire up a way to get the real socket address in that case.
+  net::IPEndPoint url_request_endpoint;
+  // If response was cached, socket address will be from the serialized
+  // response info in the cache, so don't report it.
+  // TODO(ttuttle): Plumb out the "current" socket address so we can always
+  // report it.
   if (!request.response_info.was_cached &&
       !request.response_info.was_fetched_via_proxy) {
-    beacon.server_ip = request.response_info.socket_address.host();
+    ConvertHostPortPairToIPEndPoint(request.response_info.socket_address,
+                                    &url_request_endpoint);
   }
+
+  net::ConnectionAttempt url_request_attempt(
+      url_request_endpoint, URLRequestStatusToNetError(request.status));
+
+  DomainReliabilityBeacon beacon;
   beacon.protocol = GetDomainReliabilityProtocol(
       request.response_info.connection_info,
       request.response_info.ssl_info.is_valid());
@@ -282,6 +335,25 @@
   beacon.elapsed = time_->NowTicks() - beacon.start_time;
   beacon.was_proxied = request.response_info.was_fetched_via_proxy;
   beacon.domain = request.url.host();
+
+  // This is not foolproof -- it's possible that we'll see the same error twice
+  // (e.g. an SSL error during connection on one attempt, and then an error
+  // that maps to the same code during a read).
+  // TODO(ttuttle): Find a way for this code to reliably tell whether we
+  // eventually established a connection or not.
+  bool url_request_attempt_is_duplicate = false;
+  for (const auto& attempt : request.connection_attempts) {
+    if (attempt.result == url_request_attempt.result)
+      url_request_attempt_is_duplicate = true;
+    if (!UpdateBeaconFromAttempt(&beacon, attempt))
+      continue;
+    context_manager_.RouteBeacon(request.url, beacon);
+  }
+
+  if (url_request_attempt_is_duplicate)
+    return;
+  if (!UpdateBeaconFromAttempt(&beacon, url_request_attempt))
+    return;
   context_manager_.RouteBeacon(request.url, beacon);
 }
 
diff --git a/components/domain_reliability/monitor.h b/components/domain_reliability/monitor.h
index 6fd0bfbf..5260f9f 100644
--- a/components/domain_reliability/monitor.h
+++ b/components/domain_reliability/monitor.h
@@ -25,6 +25,7 @@
 #include "net/base/load_timing_info.h"
 #include "net/base/network_change_notifier.h"
 #include "net/http/http_response_info.h"
+#include "net/socket/connection_attempts.h"
 #include "net/url_request/url_request_status.h"
 
 namespace base {
@@ -137,13 +138,14 @@
     explicit RequestInfo(const net::URLRequest& request);
     ~RequestInfo();
 
-    bool AccessedNetwork() const;
+    static bool ShouldReportRequest(const RequestInfo& request);
 
     GURL url;
     net::URLRequestStatus status;
     net::HttpResponseInfo response_info;
     int load_flags;
     net::LoadTimingInfo load_timing_info;
+    net::ConnectionAttempts connection_attempts;
     bool is_upload;
   };
 
diff --git a/components/error_page/renderer/net_error_helper_core.cc b/components/error_page/renderer/net_error_helper_core.cc
index 9a92d74..0c89ec3c 100644
--- a/components/error_page/renderer/net_error_helper_core.cc
+++ b/components/error_page/renderer/net_error_helper_core.cc
@@ -198,7 +198,7 @@
   request_dict.Set("params", params_dict.release());
 
   std::string request_body;
-  bool success = base::JSONWriter::Write(&request_dict, &request_body);
+  bool success = base::JSONWriter::Write(request_dict, &request_body);
   DCHECK(success);
   return request_body;
 }
diff --git a/components/error_page/renderer/net_error_helper_core_unittest.cc b/components/error_page/renderer/net_error_helper_core_unittest.cc
index 97897fb3..5ec9377 100644
--- a/components/error_page/renderer/net_error_helper_core_unittest.cc
+++ b/components/error_page/renderer/net_error_helper_core_unittest.cc
@@ -84,13 +84,13 @@
   for (int i = 0; i < num_corrections; ++i)
     url_corrections->Append(corrections[i].ToValue());
 
-  scoped_ptr<base::DictionaryValue> response(new base::DictionaryValue());
-  response->Set("result.UrlCorrections", url_corrections);
-  response->SetString("result.eventId", kNavigationCorrectionEventId);
-  response->SetString("result.fingerprint", kNavigationCorrectionFingerprint);
+  base::DictionaryValue response;
+  response.Set("result.UrlCorrections", url_corrections);
+  response.SetString("result.eventId", kNavigationCorrectionEventId);
+  response.SetString("result.fingerprint", kNavigationCorrectionFingerprint);
 
   std::string json;
-  base::JSONWriter::Write(response.get(), &json);
+  base::JSONWriter::Write(response, &json);
   return json;
 }
 
diff --git a/components/gcm_driver/instance_id/instance_id_driver.cc b/components/gcm_driver/instance_id/instance_id_driver.cc
index edb5270..3377b3b 100644
--- a/components/gcm_driver/instance_id/instance_id_driver.cc
+++ b/components/gcm_driver/instance_id/instance_id_driver.cc
@@ -4,26 +4,17 @@
 
 #include "components/gcm_driver/instance_id/instance_id_driver.h"
 
-#include "base/metrics/field_trial.h"
 #include "components/gcm_driver/instance_id/instance_id.h"
 
 namespace instance_id {
 
-namespace {
-#if !defined(OS_ANDROID)
-const char kInstanceIDFieldTrialName[] = "InstanceID";
-const char kInstanceIDFieldTrialEnabledGroupName[] = "Enabled";
-#endif    // !defined(OS_ANDROID)
-}  // namespace
-
 // static
 bool InstanceIDDriver::IsInstanceIDEnabled() {
 #if defined(OS_ANDROID)
-  return true;
+  // Not implemented yet.
+  return false;
 #else
-  std::string group_name =
-      base::FieldTrialList::FindFullName(kInstanceIDFieldTrialName);
-  return group_name == kInstanceIDFieldTrialEnabledGroupName;
+  return true;
 #endif    // defined(OS_ANDROID)
 }
 
diff --git a/components/history/core/browser/delete_directive_handler.cc b/components/history/core/browser/delete_directive_handler.cc
index 0aba13f..71d7f03 100644
--- a/components/history/core/browser/delete_directive_handler.cc
+++ b/components/history/core/browser/delete_directive_handler.cc
@@ -32,7 +32,7 @@
   scoped_ptr<base::DictionaryValue> value(
       syncer::HistoryDeleteDirectiveSpecificsToValue(delete_directive));
   std::string str;
-  base::JSONWriter::Write(value.get(), &str);
+  base::JSONWriter::Write(*value, &str);
   return str;
 }
 
diff --git a/components/history/core/browser/web_history_service.cc b/components/history/core/browser/web_history_service.cc
index 4a8b3aa7f..b4047f6b 100644
--- a/components/history/core/browser/web_history_service.cc
+++ b/components/history/core/browser/web_history_service.cc
@@ -362,7 +362,7 @@
   }
   delete_request.Set("del", deletions.release());
   std::string post_data;
-  base::JSONWriter::Write(&delete_request, &post_data);
+  base::JSONWriter::Write(delete_request, &post_data);
 
   GURL url(kHistoryDeleteHistoryUrl);
 
@@ -426,7 +426,7 @@
                                   new_enabled_value);
   enable_audio_history.SetString("client", "audio");
   std::string post_data;
-  base::JSONWriter::Write(&enable_audio_history, &post_data);
+  base::JSONWriter::Write(enable_audio_history, &post_data);
   request->SetPostData(post_data);
 
   request->Start();
diff --git a/components/html_viewer/blink_url_request_type_converters.cc b/components/html_viewer/blink_url_request_type_converters.cc
index 920583c..9e6a40d 100644
--- a/components/html_viewer/blink_url_request_type_converters.cc
+++ b/components/html_viewer/blink_url_request_type_converters.cc
@@ -26,17 +26,17 @@
     if (LowerCaseEqualsASCII(name_latin1, "accept"))
       has_accept_header_ = true;
 
-    HTTPHeaderPtr header = HTTPHeader::New();
+    HttpHeaderPtr header = HttpHeader::New();
     header->name = name_latin1;
     header->value = value_latin1;
     buffer_.push_back(header.Pass());
   }
 
-  Array<HTTPHeaderPtr> GetBuffer() {
+  Array<HttpHeaderPtr> GetBuffer() {
     // In some cases, WebKit doesn't add an Accept header, but not having the
     // header confuses some web servers.  See bug 808613.
     if (!has_accept_header_) {
-      HTTPHeaderPtr header = HTTPHeader::New();
+      HttpHeaderPtr header = HttpHeader::New();
       header->name = "Accept";
       header->value = "*/*";
       buffer_.push_back(header.Pass());
@@ -46,7 +46,7 @@
   }
 
  private:
-  Array<HTTPHeaderPtr> buffer_;
+  Array<HttpHeaderPtr> buffer_;
   bool has_accept_header_;
 };
 
diff --git a/components/html_viewer/web_mime_registry_impl.cc b/components/html_viewer/web_mime_registry_impl.cc
index 976a777..7954aba7 100644
--- a/components/html_viewer/web_mime_registry_impl.cc
+++ b/components/html_viewer/web_mime_registry_impl.cc
@@ -10,6 +10,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "components/mime_util/mime_util.h"
 #include "media/base/key_systems.h"
+#include "media/base/mime_util.h"
 #include "media/filters/stream_parser_factory.h"
 #include "net/base/mime_util.h"
 #include "third_party/WebKit/public/platform/WebString.h"
@@ -63,7 +64,7 @@
     const blink::WebString& key_system) {
   const std::string mime_type_ascii = ToASCIIOrEmpty(mime_type);
   // Not supporting the container is a flat-out no.
-  if (!net::IsSupportedMediaMimeType(mime_type_ascii))
+  if (!media::IsSupportedMediaMimeType(mime_type_ascii))
     return IsNotSupported;
 
   // Mojo does not currently support any key systems.
@@ -71,18 +72,18 @@
     return IsNotSupported;
 
   // Check list of strict codecs to see if it is supported.
-  if (net::IsStrictMediaMimeType(mime_type_ascii)) {
+  if (media::IsStrictMediaMimeType(mime_type_ascii)) {
     // Check if the codecs are a perfect match.
     std::vector<std::string> strict_codecs;
-    net::ParseCodecString(ToASCIIOrEmpty(codecs), &strict_codecs, false);
+    media::ParseCodecString(ToASCIIOrEmpty(codecs), &strict_codecs, false);
     return static_cast<WebMimeRegistry::SupportsType>(
-        net::IsSupportedStrictMediaMimeType(mime_type_ascii, strict_codecs));
+        media::IsSupportedStrictMediaMimeType(mime_type_ascii, strict_codecs));
   }
 
   // If we don't recognize the codec, it's possible we support it.
   std::vector<std::string> parsed_codecs;
-  net::ParseCodecString(ToASCIIOrEmpty(codecs), &parsed_codecs, true);
-  if (!net::AreSupportedMediaCodecs(parsed_codecs))
+  media::ParseCodecString(ToASCIIOrEmpty(codecs), &parsed_codecs, true);
+  if (!media::AreSupportedMediaCodecs(parsed_codecs))
     return MayBeSupported;
 
   // Otherwise we have a perfect match.
@@ -97,7 +98,7 @@
     return false;
 
   std::vector<std::string> parsed_codec_ids;
-  net::ParseCodecString(ToASCIIOrEmpty(codecs), &parsed_codec_ids, false);
+  media::ParseCodecString(ToASCIIOrEmpty(codecs), &parsed_codec_ids, false);
   return media::StreamParserFactory::IsTypeSupported(mime_type_ascii,
                                                      parsed_codec_ids);
 }
diff --git a/components/invalidation/invalidation_test_util.cc b/components/invalidation/invalidation_test_util.cc
index 3368797..6fcd8ef 100644
--- a/components/invalidation/invalidation_test_util.cc
+++ b/components/invalidation/invalidation_test_util.cc
@@ -99,9 +99,8 @@
 }  // namespace
 
 void PrintTo(const AckHandle& ack_handle, ::std::ostream* os) {
-  scoped_ptr<base::Value> value(ack_handle.ToValue());
   std::string printable_ack_handle;
-  base::JSONWriter::Write(value.get(), &printable_ack_handle);
+  base::JSONWriter::Write(*ack_handle.ToValue(), &printable_ack_handle);
   *os << "{ ack_handle: " << printable_ack_handle << " }";
 }
 
diff --git a/components/invalidation/invalidation_util.cc b/components/invalidation/invalidation_util.cc
index 50e3a5c..d3706f4 100644
--- a/components/invalidation/invalidation_util.cc
+++ b/components/invalidation/invalidation_util.cc
@@ -61,9 +61,8 @@
 }
 
 std::string ObjectIdToString(const invalidation::ObjectId& object_id) {
-  scoped_ptr<base::DictionaryValue> value(ObjectIdToValue(object_id));
   std::string str;
-  base::JSONWriter::Write(value.get(), &str);
+  base::JSONWriter::Write(*ObjectIdToValue(object_id), &str);
   return str;
 }
 
diff --git a/components/invalidation/p2p_invalidator.cc b/components/invalidation/p2p_invalidator.cc
index c583d44..906a201d 100644
--- a/components/invalidation/p2p_invalidator.cc
+++ b/components/invalidation/p2p_invalidator.cc
@@ -102,13 +102,12 @@
 }
 
 std::string P2PNotificationData::ToString() const {
-  scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
-  dict->SetString(kSenderIdKey, sender_id_);
-  dict->SetString(kNotificationTypeKey,
-                  P2PNotificationTargetToString(target_));
-  dict->Set(kInvalidationsKey, invalidation_map_.ToValue().release());
+  base::DictionaryValue dict;
+  dict.SetString(kSenderIdKey, sender_id_);
+  dict.SetString(kNotificationTypeKey, P2PNotificationTargetToString(target_));
+  dict.Set(kInvalidationsKey, invalidation_map_.ToValue().release());
   std::string json;
-  base::JSONWriter::Write(dict.get(), &json);
+  base::JSONWriter::Write(dict, &json);
   return json;
 }
 
diff --git a/components/mime_util/BUILD.gn b/components/mime_util/BUILD.gn
index 096db1a..0e3a813 100644
--- a/components/mime_util/BUILD.gn
+++ b/components/mime_util/BUILD.gn
@@ -12,6 +12,11 @@
     "//base",
     "//net",
   ]
+
+  # iOS doesn't use and must not depend on //media
+  if (!is_ios) {
+    deps += [ "//media" ]
+  }
 }
 
 source_set("unit_tests") {
diff --git a/components/mime_util/DEPS b/components/mime_util/DEPS
index 7e0780e..2b1acf8 100644
--- a/components/mime_util/DEPS
+++ b/components/mime_util/DEPS
@@ -3,5 +3,6 @@
   # any dependencies on //content
   "-content",
 
+  "+media/base/mime_util.h",  # Only for platforms other than iOS
   "+net/base",
 ]
diff --git a/components/mime_util/mime_util.cc b/components/mime_util/mime_util.cc
index a017f45..5e5d004 100644
--- a/components/mime_util/mime_util.cc
+++ b/components/mime_util/mime_util.cc
@@ -9,6 +9,11 @@
 #include "base/strings/string_util.h"
 #include "build/build_config.h"
 
+#if !defined(OS_IOS)
+// iOS doesn't use and must not depend on //media
+#include "media/base/mime_util.h"
+#endif
+
 namespace mime_util {
 
 namespace {
@@ -153,11 +158,13 @@
 bool MimeUtil::IsSupportedNonImageMimeType(const std::string& mime_type) const {
   return non_image_types_.find(base::StringToLowerASCII(mime_type)) !=
              non_image_types_.end() ||
+#if !defined(OS_IOS)
+         media::IsSupportedMediaMimeType(mime_type) ||
+#endif
          (StartsWithASCII(mime_type, "text/", false /* case insensitive */) &&
           !IsUnsupportedTextMimeType(mime_type)) ||
          (StartsWithASCII(mime_type, "application/", false) &&
-          net::MatchesMimeType("application/*+json", mime_type)) ||
-         net::IsSupportedMediaMimeType(mime_type);
+          net::MatchesMimeType("application/*+json", mime_type));
 }
 
 bool MimeUtil::IsUnsupportedTextMimeType(const std::string& mime_type) const {
diff --git a/components/mime_util/mime_util.gyp b/components/mime_util/mime_util.gyp
index 66b4228..c922f98 100644
--- a/components/mime_util/mime_util.gyp
+++ b/components/mime_util/mime_util.gyp
@@ -16,6 +16,14 @@
         'mime_util.cc',
         'mime_util.h',
       ],
+      'conditions': [
+        ['OS!="ios"', {
+          # iOS doesn't use and must not depend on //media
+          'dependencies': [
+            '../../media/media.gyp:media',
+          ],
+        }],
+      ],
     }
   ],
 }
diff --git a/components/nacl/renderer/ppb_nacl_private_impl.cc b/components/nacl/renderer/ppb_nacl_private_impl.cc
index 5ebc61f..e77b977f 100644
--- a/components/nacl/renderer/ppb_nacl_private_impl.cc
+++ b/components/nacl/renderer/ppb_nacl_private_impl.cc
@@ -1190,12 +1190,12 @@
   base::JSONReader json_reader;
   int json_read_error_code;
   std::string json_read_error_msg;
-  base::Value* json_data = json_reader.ReadAndReturnError(
+  scoped_ptr<base::Value> json_data(json_reader.ReadAndReturnError(
       buffer.get(),
       base::JSON_PARSE_RFC,
       &json_read_error_code,
-      &json_read_error_msg);
-  if (json_data == NULL) {
+      &json_read_error_msg));
+  if (!json_data) {
     load_manager->ReportLoadError(
         PP_NACL_ERROR_PNACL_RESOURCE_FETCH,
         std::string("Parsing resource info failed: JSON parse error: ") +
diff --git a/components/native_viewport/BUILD.gn b/components/native_viewport/BUILD.gn
index 5b27f1d6..a313b26 100644
--- a/components/native_viewport/BUILD.gn
+++ b/components/native_viewport/BUILD.gn
@@ -57,6 +57,8 @@
 
 source_set("lib") {
   sources = [
+    "native_viewport_application_delegate.cc",
+    "native_viewport_application_delegate.h",
     "native_viewport_impl.cc",
     "native_viewport_impl.h",
     "onscreen_context_provider.cc",
diff --git a/components/native_viewport/main.cc b/components/native_viewport/main.cc
index 7cc33236..1a749f4 100644
--- a/components/native_viewport/main.cc
+++ b/components/native_viewport/main.cc
@@ -2,83 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/command_line.h"
-#include "base/macros.h"
 #include "base/message_loop/message_loop.h"
-#include "components/gles2/gpu_impl.h"
-#include "components/native_viewport/native_viewport_impl.h"
-#include "components/native_viewport/public/cpp/args.h"
+#include "components/native_viewport/native_viewport_application_delegate.h"
 #include "mojo/application/application_runner_chromium.h"
-#include "mojo/application/public/cpp/application_connection.h"
-#include "mojo/application/public/cpp/application_delegate.h"
-#include "mojo/application/public/cpp/application_impl.h"
-#include "mojo/application/public/cpp/interface_factory_impl.h"
-#include "mojo/common/tracing_impl.h"
 #include "third_party/mojo/src/mojo/public/c/system/main.h"
-#include "ui/events/event_switches.h"
-#include "ui/gl/gl_surface.h"
-
-using mojo::ApplicationConnection;
-using mojo::Gpu;
-using mojo::NativeViewport;
-
-namespace native_viewport {
-
-class NativeViewportAppDelegate : public mojo::ApplicationDelegate,
-                                  public mojo::InterfaceFactory<NativeViewport>,
-                                  public mojo::InterfaceFactory<Gpu> {
- public:
-  NativeViewportAppDelegate() : is_headless_(false) {}
-  ~NativeViewportAppDelegate() override {}
-
- private:
-  // mojo::ApplicationDelegate implementation.
-  void Initialize(mojo::ApplicationImpl* application) override {
-    tracing_.Initialize(application);
-
-    base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
-    is_headless_ = command_line->HasSwitch(mojo::kUseHeadlessConfig);
-    if (!is_headless_) {
-      if (command_line->HasSwitch(mojo::kUseTestConfig))
-        gfx::GLSurface::InitializeOneOffForTests();
-      else
-        gfx::GLSurface::InitializeOneOff();
-    }
-  }
-
-  bool ConfigureIncomingConnection(ApplicationConnection* connection) override {
-    connection->AddService<NativeViewport>(this);
-    connection->AddService<Gpu>(this);
-    return true;
-  }
-
-  // mojo::InterfaceFactory<NativeViewport> implementation.
-  void Create(ApplicationConnection* connection,
-              mojo::InterfaceRequest<NativeViewport> request) override {
-    if (!gpu_state_.get())
-      gpu_state_ = new gles2::GpuState;
-    new NativeViewportImpl(is_headless_, gpu_state_, request.Pass());
-  }
-
-  // mojo::InterfaceFactory<Gpu> implementation.
-  void Create(ApplicationConnection* connection,
-              mojo::InterfaceRequest<Gpu> request) override {
-    if (!gpu_state_.get())
-      gpu_state_ = new gles2::GpuState;
-    new gles2::GpuImpl(request.Pass(), gpu_state_);
-  }
-
-  scoped_refptr<gles2::GpuState> gpu_state_;
-  bool is_headless_;
-  mojo::TracingImpl tracing_;
-
-  DISALLOW_COPY_AND_ASSIGN(NativeViewportAppDelegate);
-};
-}
 
 MojoResult MojoMain(MojoHandle shell_handle) {
   mojo::ApplicationRunnerChromium runner(
-      new native_viewport::NativeViewportAppDelegate);
+      new native_viewport::NativeViewportApplicationDelegate);
   runner.set_message_loop_type(base::MessageLoop::TYPE_UI);
   return runner.Run(shell_handle);
 }
diff --git a/components/native_viewport/native_viewport_application_delegate.cc b/components/native_viewport/native_viewport_application_delegate.cc
new file mode 100644
index 0000000..4f247c7a5
--- /dev/null
+++ b/components/native_viewport/native_viewport_application_delegate.cc
@@ -0,0 +1,61 @@
+// 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 "components/native_viewport/native_viewport_application_delegate.h"
+
+#include "base/command_line.h"
+#include "components/native_viewport/native_viewport_impl.h"
+#include "components/native_viewport/public/cpp/args.h"
+#include "mojo/application/public/cpp/application_connection.h"
+#include "mojo/application/public/cpp/application_impl.h"
+#include "ui/events/event_switches.h"
+#include "ui/gl/gl_surface.h"
+
+namespace native_viewport {
+
+NativeViewportApplicationDelegate::NativeViewportApplicationDelegate()
+    : is_headless_(false) {
+}
+
+NativeViewportApplicationDelegate::~NativeViewportApplicationDelegate() {
+}
+
+void NativeViewportApplicationDelegate::Initialize(
+    mojo::ApplicationImpl* application) {
+  tracing_.Initialize(application);
+
+  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+  is_headless_ = command_line->HasSwitch(mojo::kUseHeadlessConfig);
+  if (!is_headless_) {
+    if (command_line->HasSwitch(mojo::kUseTestConfig))
+      gfx::GLSurface::InitializeOneOffForTests();
+    else
+      gfx::GLSurface::InitializeOneOff();
+  }
+}
+
+bool NativeViewportApplicationDelegate::ConfigureIncomingConnection(
+    mojo::ApplicationConnection* connection) {
+  connection->AddService<mojo::NativeViewport>(this);
+  connection->AddService<mojo::Gpu>(this);
+  return true;
+}
+
+void NativeViewportApplicationDelegate::Create(
+    mojo::ApplicationConnection* connection,
+    mojo::InterfaceRequest<mojo::NativeViewport> request) {
+  if (!gpu_state_.get())
+    gpu_state_ = new gles2::GpuState;
+  new NativeViewportImpl(is_headless_, gpu_state_, request.Pass());
+}
+
+void NativeViewportApplicationDelegate::Create(
+    mojo::ApplicationConnection* connection,
+    mojo::InterfaceRequest<mojo::Gpu> request) {
+  if (!gpu_state_.get())
+    gpu_state_ = new gles2::GpuState;
+  new gles2::GpuImpl(request.Pass(), gpu_state_);
+}
+
+}  // namespace native_viewport
diff --git a/components/native_viewport/native_viewport_application_delegate.h b/components/native_viewport/native_viewport_application_delegate.h
new file mode 100644
index 0000000..4584fff
--- /dev/null
+++ b/components/native_viewport/native_viewport_application_delegate.h
@@ -0,0 +1,53 @@
+// 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 COMPONENTS_NATIVE_VIEWPORT_NATIVE_VIEWPORT_APPLICATION_DELEGATE_H_
+#define COMPONENTS_NATIVE_VIEWPORT_NATIVE_VIEWPORT_APPLICATION_DELEGATE_H_
+
+#include "base/macros.h"
+#include "components/gles2/gpu_impl.h"
+#include "components/native_viewport/public/interfaces/native_viewport.mojom.h"
+#include "mojo/application/public/cpp/application_delegate.h"
+#include "mojo/application/public/cpp/interface_factory_impl.h"
+#include "mojo/common/tracing_impl.h"
+
+namespace mojo {
+class ApplicationConnection;
+class ApplicationImpl;
+}
+
+namespace native_viewport {
+
+class NativeViewportApplicationDelegate
+    : public mojo::ApplicationDelegate,
+      public mojo::InterfaceFactory<mojo::NativeViewport>,
+      public mojo::InterfaceFactory<mojo::Gpu> {
+ public:
+  NativeViewportApplicationDelegate();
+  ~NativeViewportApplicationDelegate() override;
+
+ private:
+  // mojo::ApplicationDelegate implementation.
+  void Initialize(mojo::ApplicationImpl* application) override;
+  bool ConfigureIncomingConnection(
+      mojo::ApplicationConnection* connection) override;
+
+  // mojo::InterfaceFactory<NativeViewport> implementation.
+  void Create(mojo::ApplicationConnection* connection,
+              mojo::InterfaceRequest<mojo::NativeViewport> request) override;
+
+  // mojo::InterfaceFactory<Gpu> implementation.
+  void Create(mojo::ApplicationConnection* connection,
+              mojo::InterfaceRequest<mojo::Gpu> request) override;
+
+  scoped_refptr<gles2::GpuState> gpu_state_;
+  bool is_headless_;
+  mojo::TracingImpl tracing_;
+
+  DISALLOW_COPY_AND_ASSIGN(NativeViewportApplicationDelegate);
+};
+
+}  // namespace native_viewport
+
+#endif  // COMPONENTS_NATIVE_VIEWPORT_NATIVE_VIEWPORT_APPLICATION_DELEGATE_H_
diff --git a/components/omnibox/search_suggestion_parser.cc b/components/omnibox/search_suggestion_parser.cc
index 96933cf..26d1933e 100644
--- a/components/omnibox/search_suggestion_parser.cc
+++ b/components/omnibox/search_suggestion_parser.cc
@@ -518,7 +518,7 @@
               answer->AddImageURLsTo(&results->answers_image_urls);
 
               std::string contents;
-              base::JSONWriter::Write(answer_json, &contents);
+              base::JSONWriter::Write(*answer_json, &contents);
               answer_contents = base::UTF8ToUTF16(contents);
             } else {
               answer_type_str = base::string16();
diff --git a/components/password_manager/core/browser/affiliated_match_helper.cc b/components/password_manager/core/browser/affiliated_match_helper.cc
index 6acfb59f..225de22 100644
--- a/components/password_manager/core/browser/affiliated_match_helper.cc
+++ b/components/password_manager/core/browser/affiliated_match_helper.cc
@@ -114,6 +114,10 @@
   }
 }
 
+void AffiliatedMatchHelper::TrimAffiliationCache() {
+  affiliation_service_->TrimCache();
+}
+
 // static
 bool AffiliatedMatchHelper::IsValidAndroidCredential(
     const autofill::PasswordForm& form) {
diff --git a/components/password_manager/core/browser/affiliated_match_helper.h b/components/password_manager/core/browser/affiliated_match_helper.h
index b3ba8860..6f7b9097 100644
--- a/components/password_manager/core/browser/affiliated_match_helper.h
+++ b/components/password_manager/core/browser/affiliated_match_helper.h
@@ -80,6 +80,9 @@
       const autofill::PasswordForm& android_form,
       const AffiliatedRealmsCallback& result_callback);
 
+  // Removes cached affiliation data that is no longer needed.
+  void TrimAffiliationCache();
+
   // Returns whether or not |form| represents an Android credential.
   static bool IsValidAndroidCredential(const autofill::PasswordForm& form);
 
diff --git a/components/password_manager/core/browser/affiliation_backend.cc b/components/password_manager/core/browser/affiliation_backend.cc
index 48301dbf..fd4af444 100644
--- a/components/password_manager/core/browser/affiliation_backend.cc
+++ b/components/password_manager/core/browser/affiliation_backend.cc
@@ -5,6 +5,7 @@
 #include "components/password_manager/core/browser/affiliation_backend.h"
 
 #include <stdint.h>
+#include <algorithm>
 
 #include "base/bind.h"
 #include "base/location.h"
@@ -98,8 +99,30 @@
 void AffiliationBackend::TrimCache() {
   DCHECK(thread_checker_ && thread_checker_->CalledOnValidThread());
 
-  // TODO(engedy): Implement this. crbug.com/437865.
-  NOTIMPLEMENTED();
+  // Discard all equivalence classes except those that contain >= 1 facet for
+  // which there is a FacetManager claiming that it needs to keep the data.
+  std::vector<AffiliatedFacetsWithUpdateTime> all_affiliations;
+  cache_->GetAllAffiliations(&all_affiliations);
+  for (const auto& affiliation : all_affiliations) {
+    bool can_discard = true;
+    for (const auto& facet_uri : affiliation.facets) {
+      FacetManager* facet_manager = facet_managers_.get(facet_uri);
+      if (facet_manager && !facet_manager->CanCachedDataBeDiscarded()) {
+        can_discard = false;
+        break;
+      }
+    }
+    if (can_discard) {
+      // The database should not be serving empty equivalence classes.
+      CHECK(affiliation.facets.size());
+      cache_->DeleteAffiliationsForFacet(affiliation.facets[0]);
+    }
+  }
+}
+
+// static
+void AffiliationBackend::DeleteCache(const base::FilePath& db_path) {
+  AffiliationDatabase::Delete(db_path);
 }
 
 FacetManager* AffiliationBackend::GetOrCreateFacetManager(
diff --git a/components/password_manager/core/browser/affiliation_backend.h b/components/password_manager/core/browser/affiliation_backend.h
index abd84d6..a1a2c96 100644
--- a/components/password_manager/core/browser/affiliation_backend.h
+++ b/components/password_manager/core/browser/affiliation_backend.h
@@ -79,6 +79,10 @@
                       const base::Time& keep_fresh_until);
   void TrimCache();
 
+  // Deletes the cache database file at |db_path|, and all auxiliary files. The
+  // database must be closed before calling this.
+  static void DeleteCache(const base::FilePath& db_path);
+
  private:
   friend class AffiliationBackendTest;
 
diff --git a/components/password_manager/core/browser/affiliation_backend_unittest.cc b/components/password_manager/core/browser/affiliation_backend_unittest.cc
index a0421d386..256fb00 100644
--- a/components/password_manager/core/browser/affiliation_backend_unittest.cc
+++ b/components/password_manager/core/browser/affiliation_backend_unittest.cc
@@ -13,6 +13,7 @@
 #include "base/test/test_simple_task_runner.h"
 #include "base/time/clock.h"
 #include "base/time/tick_clock.h"
+#include "components/password_manager/core/browser/affiliation_database.h"
 #include "components/password_manager/core/browser/affiliation_fetch_throttler.h"
 #include "components/password_manager/core/browser/affiliation_fetch_throttler_delegate.h"
 #include "components/password_manager/core/browser/facet_manager.h"
@@ -262,6 +263,16 @@
     backend_task_runner_->FastForwardBy(delta);
   }
 
+  // Directly opens the database and returns the number of equivalence classes
+  // stored therein.
+  size_t GetNumOfEquivalenceClassInDatabase() {
+    AffiliationDatabase database;
+    EXPECT_TRUE(database.Init(db_path()));
+    std::vector<AffiliatedFacetsWithUpdateTime> all_affiliations;
+    database.GetAllAffiliations(&all_affiliations);
+    return all_affiliations.size();
+  }
+
   size_t backend_facet_manager_count() {
     return backend()->facet_manager_count_for_testing();
   }
@@ -279,6 +290,8 @@
 
   AffiliationBackend* backend() { return backend_.get(); }
 
+  const base::FilePath& db_path() const { return db_path_; }
+
   base::TestMockTimeTaskRunner* backend_task_runner() {
     return backend_task_runner_.get();
   }
@@ -300,12 +313,11 @@
  private:
   // testing::Test:
   void SetUp() override {
-    base::FilePath database_path;
-    ASSERT_TRUE(CreateTemporaryFile(&database_path));
+    ASSERT_TRUE(CreateTemporaryFile(&db_path_));
     backend_.reset(new AffiliationBackend(
         NULL, backend_task_runner_, backend_task_runner_->GetMockClock(),
         backend_task_runner_->GetMockTickClock()));
-    backend_->Initialize(database_path);
+    backend_->Initialize(db_path());
     mock_fetch_throttler_ = new MockAffiliationFetchThrottler(backend_.get());
     backend_->SetThrottlerForTesting(
         make_scoped_ptr<AffiliationFetchThrottler>(mock_fetch_throttler_));
@@ -321,6 +333,7 @@
   scoped_refptr<base::TestMockTimeTaskRunner> backend_task_runner_;
   scoped_refptr<base::TestSimpleTaskRunner> consumer_task_runner_;
 
+  base::FilePath db_path_;
   ScopedFakeAffiliationAPI fake_affiliation_api_;
   MockAffiliationConsumer mock_consumer_;
   scoped_ptr<AffiliationBackend> backend_;
@@ -773,6 +786,76 @@
   EXPECT_FALSE(backend_task_runner()->HasPendingTask());
 }
 
+// Verify removal of equivalence classes that contain only facets for which
+// there are no FacetManagers.
+TEST_F(AffiliationBackendTest, TrimCacheDiscardsDataWithoutFacetManagers) {
+  ASSERT_NO_FATAL_FAILURE(GetAffiliationsAndExpectFetchAndThenResult(
+      FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1),
+      GetTestEquivalenceClassAlpha()));
+  ASSERT_NO_FATAL_FAILURE(PrefetchAndExpectFetch(
+      FacetURI::FromCanonicalSpec(kTestFacetURIBeta1),
+      backend_task_runner()->Now() + GetShortTestPeriod()));
+  Prefetch(FacetURI::FromCanonicalSpec(kTestFacetURIBeta2), base::Time::Max());
+  ASSERT_NO_FATAL_FAILURE(ExpectNoFetchNeeded());
+  EXPECT_EQ(2u, GetNumOfEquivalenceClassInDatabase());
+
+  AdvanceTime(GetShortTestPeriod());
+
+  // Worst-case scenario: the first prefetch has just expired, the other has
+  // just been canceled when TrimCache() is called; plus immediately afterwards
+  // the backend is destroyed.
+  ASSERT_NO_FATAL_FAILURE(CancelPrefetch(
+      FacetURI::FromCanonicalSpec(kTestFacetURIBeta2), base::Time::Max()));
+  backend()->TrimCache();
+  DestroyBackend();
+  EXPECT_EQ(0u, GetNumOfEquivalenceClassInDatabase());
+}
+
+// Verify removal of equivalence classes that contain only facets for which
+// there are either no FacetManagers, or only such that do not need the data.
+TEST_F(AffiliationBackendTest,
+       TrimCacheDiscardsDataNoLongerNeededByFacetManagers) {
+  FacetURI facet_uri(FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1));
+
+  // Set up some stale data in the database.
+  ASSERT_NO_FATAL_FAILURE(GetAffiliationsAndExpectFetchAndThenResult(
+      facet_uri, GetTestEquivalenceClassAlpha()));
+  AdvanceTime(GetCacheHardExpiryPeriod());
+  EXPECT_FALSE(IsCachedDataFreshForFacet(facet_uri));
+
+  // Now start prefetching the same facet, but keep the network fetch hanging.
+  Prefetch(facet_uri, base::Time::Max());
+  ASSERT_TRUE(mock_fetch_throttler()->has_signaled_network_request_needed());
+  EXPECT_EQ(1u, GetNumOfEquivalenceClassInDatabase());
+
+  // The already stale data should be removed regardless of the active prefetch.
+  backend()->TrimCache();
+  EXPECT_EQ(0u, GetNumOfEquivalenceClassInDatabase());
+
+  mock_fetch_throttler()->reset_signaled_network_request_needed();
+}
+
+// Verify preservation of equivalence classes that contain >= 1 facet for which
+// there is a FacetManager claiming that it needs to keep the data.
+TEST_F(AffiliationBackendTest, TrimCacheRetainsDataThatNeededByFacetManagers) {
+  FacetURI facet_uri(FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1));
+
+  ASSERT_NO_FATAL_FAILURE(PrefetchAndExpectFetch(
+      facet_uri, backend_task_runner()->Now() + GetCacheHardExpiryPeriod()));
+  backend()->TrimCache();
+
+  // Also verify that the last update time of the affiliation data is preserved,
+  // i.e., that it expires when it would normally have expired.
+  AdvanceTime(GetCacheHardExpiryPeriod() - Epsilon());
+  EXPECT_TRUE(IsCachedDataFreshForFacet(facet_uri));
+  ASSERT_NO_FATAL_FAILURE(ExpectThatEquivalenceClassIsServedFromCache(
+      GetTestEquivalenceClassAlpha()));
+  AdvanceTime(Epsilon());
+  EXPECT_FALSE(IsCachedDataFreshForFacet(facet_uri));
+  ASSERT_NO_FATAL_FAILURE(
+      GetAffiliationsAndExpectFailureWithoutFetch(facet_uri));
+}
+
 TEST_F(AffiliationBackendTest, NothingExplodesWhenShutDownDuringFetch) {
   GetAffiliations(mock_consumer(),
                   FacetURI::FromCanonicalSpec(kTestFacetURIAlpha2),
@@ -797,4 +880,11 @@
   testing::Mock::VerifyAndClearExpectations(mock_consumer());
 }
 
+TEST_F(AffiliationBackendTest, DeleteCache) {
+  DestroyBackend();
+  ASSERT_TRUE(base::PathExists(db_path()));
+  AffiliationBackend::DeleteCache(db_path());
+  ASSERT_FALSE(base::PathExists(db_path()));
+}
+
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/affiliation_database.cc b/components/password_manager/core/browser/affiliation_database.cc
index 0757d711..bab8f366 100644
--- a/components/password_manager/core/browser/affiliation_database.cc
+++ b/components/password_manager/core/browser/affiliation_database.cc
@@ -214,6 +214,12 @@
   transaction.Commit();
 }
 
+// static
+void AffiliationDatabase::Delete(const base::FilePath& path) {
+  bool success = sql::Connection::Delete(path);
+  DCHECK(success);
+}
+
 bool AffiliationDatabase::CreateTablesAndIndicesIfNeeded() {
   if (!sql_connection_->Execute(
           "CREATE TABLE IF NOT EXISTS eq_classes("
diff --git a/components/password_manager/core/browser/affiliation_database.h b/components/password_manager/core/browser/affiliation_database.h
index 11d2c0e..621add9c 100644
--- a/components/password_manager/core/browser/affiliation_database.h
+++ b/components/password_manager/core/browser/affiliation_database.h
@@ -70,6 +70,10 @@
       const AffiliatedFacetsWithUpdateTime& affiliated_facets,
       std::vector<AffiliatedFacetsWithUpdateTime>* removed_affiliations);
 
+  // Deletes the database file at |path| along with all its auxiliary files. The
+  // database must be closed before calling this.
+  static void Delete(const base::FilePath& path);
+
  private:
   // Creates any tables and indices that do not already exist in the database.
   bool CreateTablesAndIndicesIfNeeded();
diff --git a/components/password_manager/core/browser/affiliation_database_unittest.cc b/components/password_manager/core/browser/affiliation_database_unittest.cc
index 6fc8a7e..4734392 100644
--- a/components/password_manager/core/browser/affiliation_database_unittest.cc
+++ b/components/password_manager/core/browser/affiliation_database_unittest.cc
@@ -5,6 +5,7 @@
 #include "components/password_manager/core/browser/affiliation_database.h"
 
 #include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
 #include "sql/test/scoped_error_ignorer.h"
 #include "sql/test/test_helpers.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -69,7 +70,7 @@
   ~AffiliationDatabaseTest() override {}
 
   void SetUp() override {
-    ASSERT_TRUE(CreateTemporaryFile(&db_path_));
+    ASSERT_TRUE(temp_directory_.CreateUniqueTempDir());
     OpenDatabase();
   }
 
@@ -88,10 +89,13 @@
 
   AffiliationDatabase& db() { return *db_; }
 
-  const base::FilePath& db_path() { return db_path_; }
+  base::FilePath db_path() {
+    return temp_directory_.path().Append(
+        FILE_PATH_LITERAL("Test Affiliation Database"));
+  }
 
  private:
-  base::FilePath db_path_;
+  base::ScopedTempDir temp_directory_;
   scoped_ptr<AffiliationDatabase> db_;
 
   DISALLOW_COPY_AND_ASSIGN(AffiliationDatabaseTest);
@@ -290,4 +294,13 @@
   EXPECT_EQ(0u, affiliations.size());
 }
 
+// Verify that all files get deleted.
+TEST_F(AffiliationDatabaseTest, Delete) {
+  ASSERT_NO_FATAL_FAILURE(StoreInitialTestData());
+  CloseDatabase();
+
+  AffiliationDatabase::Delete(db_path());
+  EXPECT_TRUE(base::IsDirectoryEmpty(db_path().DirName()));
+}
+
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/affiliation_service.cc b/components/password_manager/core/browser/affiliation_service.cc
index 0bcade91..30fbe632 100644
--- a/components/password_manager/core/browser/affiliation_service.cc
+++ b/components/password_manager/core/browser/affiliation_service.cc
@@ -89,4 +89,12 @@
       base::Bind(&AffiliationBackend::TrimCache, base::Unretained(backend_)));
 }
 
+// static
+void AffiliationService::DeleteCache(
+    const base::FilePath& db_path,
+    base::SingleThreadTaskRunner* backend_task_runner) {
+  backend_task_runner->PostTask(
+      FROM_HERE, base::Bind(&AffiliationBackend::DeleteCache, db_path));
+}
+
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/affiliation_service.h b/components/password_manager/core/browser/affiliation_service.h
index adc2349e..fd81a3bd 100644
--- a/components/password_manager/core/browser/affiliation_service.h
+++ b/components/password_manager/core/browser/affiliation_service.h
@@ -142,6 +142,12 @@
   // triggered by this call.
   void TrimCache();
 
+  // Posts a task to the |backend_task_runner| to delete the cache database file
+  // at |db_path|, and all auxiliary files. The database must be closed before
+  // calling this.
+  static void DeleteCache(const base::FilePath& db_path,
+                          base::SingleThreadTaskRunner* backend_task_runner);
+
  private:
   // The backend, owned by this AffiliationService instance, but living on the
   // DB thread. It will be deleted asynchronously during shutdown on the DB
diff --git a/components/password_manager/core/browser/facet_manager.cc b/components/password_manager/core/browser/facet_manager.cc
index ea84f50e..a0e9e86 100644
--- a/components/password_manager/core/browser/facet_manager.cc
+++ b/components/password_manager/core/browser/facet_manager.cc
@@ -187,6 +187,11 @@
          GetMaximumKeepFreshUntilThreshold() <= clock_->Now();
 }
 
+bool FacetManager::CanCachedDataBeDiscarded() const {
+  return GetMaximumKeepFreshUntilThreshold() <= clock_->Now() ||
+         !IsCachedDataFresh();
+}
+
 bool FacetManager::DoesRequireFetch() const {
   return (!pending_requests_.empty() && !IsCachedDataFresh()) ||
          GetNextRequiredFetchTimeDueToPrefetch() <= clock_->Now();
diff --git a/components/password_manager/core/browser/facet_manager.h b/components/password_manager/core/browser/facet_manager.h
index 81c5fed..5e3ee77 100644
--- a/components/password_manager/core/browser/facet_manager.h
+++ b/components/password_manager/core/browser/facet_manager.h
@@ -58,6 +58,10 @@
   // more meaningful state than a newly created instance would have.
   bool CanBeDiscarded() const;
 
+  // Returns whether or not cached data for this facet can be discarded without
+  // harm when trimming the database.
+  bool CanCachedDataBeDiscarded() const;
+
   // Returns whether or not affiliation information relating to this facet needs
   // to be fetched right now.
   bool DoesRequireFetch() const;
diff --git a/components/password_manager/core/browser/facet_manager_unittest.cc b/components/password_manager/core/browser/facet_manager_unittest.cc
index 4cc3b30..01ae885f 100644
--- a/components/password_manager/core/browser/facet_manager_unittest.cc
+++ b/components/password_manager/core/browser/facet_manager_unittest.cc
@@ -288,6 +288,7 @@
     for (base::TimeDelta step : SamplingPoints(until_time - Now())) {
       SCOPED_TRACE(testing::Message() << "dT: " << DeltaNow());
       EXPECT_FALSE(facet_manager()->CanBeDiscarded());
+      EXPECT_FALSE(facet_manager()->CanCachedDataBeDiscarded());
       ExpectRequestsServedFromCache();
       ExpectNoFetchNeeded();
       AdvanceTime(step);
@@ -411,6 +412,7 @@
 TEST_F(FacetManagerTest, NewInstanceCanBeDiscarded) {
   CreateFacetManager();
   EXPECT_TRUE(facet_manager()->CanBeDiscarded());
+  EXPECT_TRUE(facet_manager()->CanCachedDataBeDiscarded());
   EXPECT_FALSE(facet_manager()->DoesRequireFetch());
   EXPECT_FALSE(main_task_runner()->HasPendingTask());
 }
@@ -1300,6 +1302,34 @@
   DestroyFacetManager();
 }
 
+TEST_F(FacetManagerTest, CachedDataCannotBeDiscarded) {
+  CreateFacetManager();
+
+  const base::TimeDelta kPrefetchLength =
+      2 * GetCacheSoftExpiryPeriod() + GetCacheHardExpiryPeriod();
+
+  facet_manager_notifier()->set_accuracy(NotificationAccuracy::NEVER_CALLED);
+
+  const base::Time prefetch_end = Now() + kPrefetchLength;
+  std::vector<ExpectedFetchDetails> expected_fetches(1);
+  expected_fetches[0].time = Now();
+
+  Prefetch(prefetch_end);
+  ASSERT_NO_FATAL_FAILURE(AdvanceTimeAndVerifyPrefetchWithFetchesAt(
+      Now() + GetCacheSoftExpiryPeriod(), expected_fetches));
+  for (base::TimeDelta step : SamplingPoints(prefetch_end - Now())) {
+    SCOPED_TRACE(testing::Message() << "dT: " << DeltaNow());
+    EXPECT_FALSE(facet_manager()->CanBeDiscarded());
+    ASSERT_TRUE(facet_manager()->DoesRequireFetch());
+    if (DeltaNow() < GetCacheHardExpiryPeriod())
+      ExpectRequestsServedFromCache();
+    AdvanceTime(step);
+  }
+  EXPECT_TRUE(facet_manager()->CanBeDiscarded());
+  EXPECT_FALSE(main_task_runner()->HasPendingTask());
+  DestroyFacetManager();
+}
+
 // RequestNotificationAtTime() ends up calling NotifyAtRequestedTime() always
 // a bit earlier than needed. This should result in NotifyAtRequestedTime()
 // being called repeatedly until the callback is finally on time, but should
@@ -1402,4 +1432,87 @@
   DestroyFacetManager();
 }
 
+TEST_F(FacetManagerTest, StaleCachedDataBeCanDiscardedWhilePendingFetch) {
+  CreateFacetManager();
+  ASSERT_FALSE(facet_manager()->IsCachedDataFresh());
+
+  GetAffiliations(StrategyOnCacheMiss::FETCH_OVER_NETWORK);
+  ASSERT_NO_FATAL_FAILURE(ExpectFetchNeeded());
+  EXPECT_FALSE(facet_manager()->CanBeDiscarded());
+  EXPECT_TRUE(facet_manager()->CanCachedDataBeDiscarded());
+
+  fake_facet_manager_host()->reset_need_network_request();
+}
+
+TEST_F(FacetManagerTest, CachedDataBeCanDiscardedAfterOnDemandGetAffiliatons) {
+  CreateFacetManager();
+  ASSERT_FALSE(facet_manager()->IsCachedDataFresh());
+
+  GetAffiliations(StrategyOnCacheMiss::FETCH_OVER_NETWORK);
+  ASSERT_NO_FATAL_FAILURE(ExpectFetchNeeded());
+  ASSERT_NO_FATAL_FAILURE(CompleteFetch());
+  ExpectConsumerSuccessCallback();
+
+  EXPECT_TRUE(facet_manager()->IsCachedDataFresh());
+  EXPECT_TRUE(facet_manager()->CanBeDiscarded());
+  EXPECT_TRUE(facet_manager()->CanCachedDataBeDiscarded());
+}
+
+// The cached data can be discarded (indicated by 'd') if and only if it is no
+// longer needed to be kept fresh, or if it already stale.
+//
+//      t=0                        S       H                  F2+S   F2+H
+//      /                          /       /                  /      /
+//  ---o--------------------------o-------o------------------o-------o------> t
+//     :                          :       :
+//     [F-------------------------NNNNNNNNNNNF---)
+//                                        ddd    ddd...
+//
+TEST_F(FacetManagerTest,
+       CachedDataCanBeDiscardedAfterAndSometimesDuringPrefetch) {
+  CreateFacetManager();
+  Prefetch(Now() + GetCacheHardExpiryPeriod() + 2 * GetShortTestPeriod());
+  ASSERT_NO_FATAL_FAILURE(ExpectFetchNeeded());
+  ASSERT_NO_FATAL_FAILURE(CompleteFetch());
+
+  for (base::TimeDelta step : SamplingPoints(GetCacheHardExpiryPeriod())) {
+    SCOPED_TRACE(testing::Message() << "dT: " << DeltaNow());
+    EXPECT_FALSE(facet_manager()->CanCachedDataBeDiscarded());
+    AdvanceTime(step);
+  }
+
+  for (base::TimeDelta step : SamplingPoints(GetShortTestPeriod())) {
+    SCOPED_TRACE(testing::Message() << "dT: " << DeltaNow());
+    EXPECT_TRUE(facet_manager()->CanCachedDataBeDiscarded());
+    AdvanceTime(step);
+  }
+
+  ASSERT_NO_FATAL_FAILURE(ExpectFetchNeeded());
+  ASSERT_NO_FATAL_FAILURE(CompleteFetch());
+
+  for (base::TimeDelta step : SamplingPoints(GetShortTestPeriod())) {
+    SCOPED_TRACE(testing::Message() << "dT: " << DeltaNow());
+    EXPECT_FALSE(facet_manager()->CanCachedDataBeDiscarded());
+    AdvanceTime(step);
+  }
+
+  EXPECT_TRUE(facet_manager()->CanBeDiscarded());
+  EXPECT_TRUE(facet_manager()->CanCachedDataBeDiscarded());
+}
+
+TEST_F(FacetManagerTest, CachedDataBeCanDiscardedAfterCancelledPrefetch) {
+  CreateFacetManager();
+  Prefetch(base::Time::Max());
+  ASSERT_NO_FATAL_FAILURE(ExpectFetchNeeded());
+  ASSERT_NO_FATAL_FAILURE(CompleteFetch());
+
+  EXPECT_FALSE(facet_manager()->CanCachedDataBeDiscarded());
+
+  AdvanceTime(GetShortTestPeriod());
+  CancelPrefetch(base::Time::Max());
+
+  EXPECT_TRUE(facet_manager()->CanBeDiscarded());
+  EXPECT_TRUE(facet_manager()->CanCachedDataBeDiscarded());
+}
+
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/password_store.cc b/components/password_manager/core/browser/password_store.cc
index 4a357919..08e827db 100644
--- a/components/password_manager/core/browser/password_store.cc
+++ b/components/password_manager/core/browser/password_store.cc
@@ -116,6 +116,11 @@
                           this, delete_begin, delete_end));
 }
 
+void PasswordStore::TrimAffiliationCache() {
+  if (affiliated_match_helper_)
+    affiliated_match_helper_->TrimAffiliationCache();
+}
+
 void PasswordStore::GetLogins(const PasswordForm& form,
                               AuthorizationPromptPolicy prompt_policy,
                               PasswordStoreConsumer* consumer) {
diff --git a/components/password_manager/core/browser/password_store.h b/components/password_manager/core/browser/password_store.h
index c1194cfc..c49aecb 100644
--- a/components/password_manager/core/browser/password_store.h
+++ b/components/password_manager/core/browser/password_store.h
@@ -102,6 +102,10 @@
   virtual void RemoveLoginsSyncedBetween(base::Time delete_begin,
                                          base::Time delete_end);
 
+  // Removes cached affiliation data that is no longer needed; provided that
+  // affiliation-based matching is enabled.
+  void TrimAffiliationCache();
+
   // Searches for a matching PasswordForm, and notifies |consumer| on
   // completion. The request will be cancelled if the consumer is destroyed.
   // |prompt_policy| indicates whether it's permissible to prompt the user to
diff --git a/components/policy/core/common/cloud/cloud_policy_constants.cc b/components/policy/core/common/cloud/cloud_policy_constants.cc
index 43324e1..4fa62f55 100644
--- a/components/policy/core/common/cloud/cloud_policy_constants.cc
+++ b/components/policy/core/common/cloud/cloud_policy_constants.cc
@@ -42,8 +42,8 @@
 const char kValueUserAffiliationManaged[] = "managed";
 const char kValueUserAffiliationNone[] = "none";
 const char kValueRequestDeviceAttributeUpdatePermission[] =
-    "attribute_update_permission";
-const char kValueRequestDeviceAttributeUpdate[] = "attribute_update";
+    "device_attribute_update_permission";
+const char kValueRequestDeviceAttributeUpdate[] = "device_attribute_update";
 
 const char kChromeDevicePolicyType[] = "google/chromeos/device";
 #if defined(OS_CHROMEOS)
diff --git a/components/policy/core/common/cloud/cloud_policy_core.cc b/components/policy/core/common/cloud/cloud_policy_core.cc
index f1f5fca..302808e 100644
--- a/components/policy/core/common/cloud/cloud_policy_core.cc
+++ b/components/policy/core/common/cloud/cloud_policy_core.cc
@@ -19,6 +19,10 @@
 
 CloudPolicyCore::Observer::~Observer() {}
 
+void CloudPolicyCore::Observer::OnRemoteCommandsServiceStarted(
+    CloudPolicyCore* core) {
+}
+
 CloudPolicyCore::CloudPolicyCore(
     const std::string& policy_type,
     const std::string& settings_entity_id,
@@ -59,6 +63,8 @@
 
   // Do an initial remote commands fetch immediately.
   remote_commands_service_->FetchRemoteCommands();
+
+  FOR_EACH_OBSERVER(Observer, observers_, OnRemoteCommandsServiceStarted(this));
 }
 
 void CloudPolicyCore::RefreshSoon() {
diff --git a/components/policy/core/common/cloud/cloud_policy_core.h b/components/policy/core/common/cloud/cloud_policy_core.h
index 031aa34..7a9bf59a 100644
--- a/components/policy/core/common/cloud/cloud_policy_core.h
+++ b/components/policy/core/common/cloud/cloud_policy_core.h
@@ -50,6 +50,10 @@
 
     // Called before the core is disconnected.
     virtual void OnCoreDisconnecting(CloudPolicyCore* core) = 0;
+
+    // Called after the remote commands service is started. Defaults to be
+    // empty.
+    virtual void OnRemoteCommandsServiceStarted(CloudPolicyCore* core);
   };
 
   // |task_runner| is the runner for policy refresh tasks.
diff --git a/components/policy/core/common/cloud/policy_header_service.cc b/components/policy/core/common/cloud/policy_header_service.cc
index d0f6980..62519c75 100644
--- a/components/policy/core/common/cloud/policy_header_service.cc
+++ b/components/policy/core/common/cloud/policy_header_service.cc
@@ -74,7 +74,7 @@
   // TODO(atwilson): add user_policy_token once the server starts sending it
   // down (http://crbug.com/326799).
   std::string json;
-  base::JSONWriter::Write(&value, &json);
+  base::JSONWriter::Write(value, &json);
   DCHECK(!json.empty());
 
   // Base64-encode the result so we can include it in a header.
diff --git a/components/policy/core/common/policy_loader_win.cc b/components/policy/core/common/policy_loader_win.cc
index f223da5..f49f944e 100644
--- a/components/policy/core/common/policy_loader_win.cc
+++ b/components/policy/core/common/policy_loader_win.cc
@@ -128,7 +128,7 @@
   }
 
   std::string serialized;
-  base::JSONWriter::Write(json.get(), &serialized);
+  base::JSONWriter::Write(*json, &serialized);
   return serialized;
 }
 
diff --git a/components/policy/core/common/policy_loader_win_unittest.cc b/components/policy/core/common/policy_loader_win_unittest.cc
index 76adc44..c2db3f2 100644
--- a/components/policy/core/common/policy_loader_win_unittest.cc
+++ b/components/policy/core/common/policy_loader_win_unittest.cc
@@ -402,7 +402,7 @@
     const std::string& policy_name,
     const base::DictionaryValue* policy_value) {
   std::string json;
-  base::JSONWriter::Write(policy_value, &json);
+  base::JSONWriter::Write(*policy_value, &json);
   RegKey key(hive_, kTestPolicyKey, KEY_ALL_ACCESS);
   ASSERT_TRUE(key.Valid());
   key.WriteValue(UTF8ToUTF16(policy_name).c_str(),
@@ -506,7 +506,7 @@
     const std::string& policy_name,
     const base::DictionaryValue* policy_value) {
   std::string json;
-  base::JSONWriter::Write(policy_value, &json);
+  base::JSONWriter::Write(*policy_value, &json);
   AppendStringToPRegFile(kTestPolicyKey, policy_name, json);
 }
 
@@ -910,11 +910,11 @@
   policy.Set("list", list.DeepCopy());
   // Encode |policy| before adding the "dict" entry.
   std::string encoded_dict;
-  base::JSONWriter::Write(&policy, &encoded_dict);
+  base::JSONWriter::Write(policy, &encoded_dict);
   ASSERT_FALSE(encoded_dict.empty());
   policy.Set("dict", policy.DeepCopy());
   std::string encoded_list;
-  base::JSONWriter::Write(&list, &encoded_list);
+  base::JSONWriter::Write(list, &encoded_list);
   ASSERT_FALSE(encoded_list.empty());
   base::DictionaryValue encoded_policy;
   encoded_policy.SetString("null", "");
diff --git a/components/policy/core/common/policy_test_utils.cc b/components/policy/core/common/policy_test_utils.cc
index 79180e4..e9116b76 100644
--- a/components/policy/core/common/policy_test_utils.cc
+++ b/components/policy/core/common/policy_test_utils.cc
@@ -222,9 +222,8 @@
 
 std::ostream& operator<<(std::ostream& os, const policy::PolicyMap::Entry& e) {
   std::string value;
-  base::JSONWriter::WriteWithOptions(e.value,
-                                     base::JSONWriter::OPTIONS_PRETTY_PRINT,
-                                     &value);
+  base::JSONWriter::WriteWithOptions(
+      *e.value, base::JSONWriter::OPTIONS_PRETTY_PRINT, &value);
   os << "{" << std::endl
      << "  \"level\": " << e.level << "," << std::endl
      << "  \"scope\": " << e.scope << "," << std::endl
diff --git a/components/policy/core/common/remote_commands/remote_commands_service.cc b/components/policy/core/common/remote_commands/remote_commands_service.cc
index 1b3bb678..d7b53bc 100644
--- a/components/policy/core/common/remote_commands/remote_commands_service.cc
+++ b/components/policy/core/common/remote_commands/remote_commands_service.cc
@@ -30,7 +30,7 @@
 }
 
 bool RemoteCommandsService::FetchRemoteCommands() {
-  if (!client_->is_registered())
+  if (!client_ || !client_->is_registered())
     return false;
 
   if (command_fetch_in_progress_) {
diff --git a/components/policy/proto/device_management_backend.proto b/components/policy/proto/device_management_backend.proto
index 37322aa..aab6a9e 100644
--- a/components/policy/proto/device_management_backend.proto
+++ b/components/policy/proto/device_management_backend.proto
@@ -350,6 +350,18 @@
   // Indicates the state that the device should be in.
   optional DeviceState device_state = 17;
 
+  // The object source which hosts command queue objects within the
+  // invalidation service. This value is combined with
+  // command_invalidation_name to form the object ID used to
+  // register for invalidations to the command queue.
+  optional int32 command_invalidation_source = 18;
+
+  // The name which uniquely identifies this device’s queue within
+  // the invalidation service object source. This value is combined
+  // with command_invalidation_source to form the object ID used to
+  // register for invalidations to the command queue.
+  optional bytes command_invalidation_name = 19;
+
   // The free-text location info the admin enters to associate the device
   // with a location.
   optional string annotated_location = 20;
diff --git a/components/printing/renderer/print_web_view_helper.cc b/components/printing/renderer/print_web_view_helper.cc
index 7d1b9078..bd6267c8 100644
--- a/components/printing/renderer/print_web_view_helper.cc
+++ b/components/printing/renderer/print_web_view_helper.cc
@@ -83,7 +83,7 @@
                    const char* script_format,
                    const base::Value& parameters) {
   std::string json;
-  base::JSONWriter::Write(&parameters, &json);
+  base::JSONWriter::Write(parameters, &json);
   std::string script = base::StringPrintf(script_format, json.c_str());
   frame->executeScript(blink::WebString(base::UTF8ToUTF16(script)));
 }
diff --git a/components/proximity_auth/client.cc b/components/proximity_auth/client.cc
index a0b6a06..255b6f6 100644
--- a/components/proximity_auth/client.cc
+++ b/components/proximity_auth/client.cc
@@ -37,7 +37,7 @@
 // Serializes the |value| to a JSON string and returns the result.
 std::string SerializeValueToJson(const base::Value& value) {
   std::string json;
-  base::JSONWriter::Write(&value, &json);
+  base::JSONWriter::Write(value, &json);
   return json;
 }
 
diff --git a/components/search_engines/keyword_table.cc b/components/search_engines/keyword_table.cc
index 3e21c1f..7de6217 100644
--- a/components/search_engines/keyword_table.cc
+++ b/components/search_engines/keyword_table.cc
@@ -100,7 +100,7 @@
   for (size_t i = 0; i < data.alternate_urls.size(); ++i)
     alternate_urls_value.AppendString(data.alternate_urls[i]);
   std::string alternate_urls;
-  base::JSONWriter::Write(&alternate_urls_value, &alternate_urls);
+  base::JSONWriter::Write(alternate_urls_value, &alternate_urls);
 
   s->BindInt64(id_column, data.id);
   s->BindString16(starting_column, data.short_name());
diff --git a/components/search_provider_logos/logo_cache.cc b/components/search_provider_logos/logo_cache.cc
index bfa419e..c6272ee5 100644
--- a/components/search_provider_logos/logo_cache.cc
+++ b/components/search_provider_logos/logo_cache.cc
@@ -152,7 +152,7 @@
                   metadata.can_show_after_expiration);
   dict.SetInteger(kNumBytesKey, num_bytes);
   SetTimeValue(dict, kExpirationTimeKey, metadata.expiration_time);
-  base::JSONWriter::Write(&dict, str);
+  base::JSONWriter::Write(dict, str);
 }
 
 base::FilePath LogoCache::GetLogoPath() {
diff --git a/components/search_provider_logos/logo_tracker_unittest.cc b/components/search_provider_logos/logo_tracker_unittest.cc
index 590985a..fcd4653 100644
--- a/components/search_provider_logos/logo_tracker_unittest.cc
+++ b/components/search_provider_logos/logo_tracker_unittest.cc
@@ -139,7 +139,7 @@
                     static_cast<int>(time_to_live.InMilliseconds()));
 
   std::string output;
-  base::JSONWriter::Write(&dict, &output);
+  base::JSONWriter::Write(dict, &output);
   return output;
 }
 
diff --git a/components/signin/core/browser/account_tracker_service.cc b/components/signin/core/browser/account_tracker_service.cc
index ec24462..d29adf1 100644
--- a/components/signin/core/browser/account_tracker_service.cc
+++ b/components/signin/core/browser/account_tracker_service.cc
@@ -10,6 +10,7 @@
 #include "base/metrics/field_trial.h"
 #include "base/prefs/scoped_user_pref_update.h"
 #include "base/profiler/scoped_tracker.h"
+#include "base/strings/string_split.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/trace_event/trace_event.h"
 #include "components/signin/core/browser/refresh_token_annotation_request.h"
@@ -17,6 +18,8 @@
 #include "components/signin/core/browser/signin_manager.h"
 #include "components/signin/core/common/signin_pref_names.h"
 #include "components/signin/core/common/signin_switches.h"
+#include "google_apis/gaia/gaia_auth_consumer.h"
+#include "google_apis/gaia/gaia_auth_fetcher.h"
 #include "google_apis/gaia/gaia_auth_util.h"
 #include "google_apis/gaia/gaia_constants.h"
 #include "google_apis/gaia/gaia_oauth_client.h"
@@ -31,6 +34,7 @@
 const char kAccountFullNamePath[] = "full_name";
 const char kAccountGivenNamePath[] = "given_name";
 const char kAccountLocalePath[] = "locale";
+const char kAccountServiceFlagsPath[] = "service_flags";
 
 const base::TimeDelta kRefreshFromTokenServiceDelay =
     base::TimeDelta::FromHours(24);
@@ -50,7 +54,8 @@
 const char AccountTrackerService::kNoHostedDomainFound[] = "NO_HOSTED_DOMAIN";
 
 class AccountInfoFetcher : public OAuth2TokenService::Consumer,
-                           public gaia::GaiaOAuthClient::Delegate {
+                           public gaia::GaiaOAuthClient::Delegate,
+                           public GaiaAuthConsumer {
  public:
   AccountInfoFetcher(OAuth2TokenService* token_service,
                      net::URLRequestContextGetter* request_context_getter,
@@ -61,6 +66,7 @@
   const std::string& account_id() { return account_id_; }
 
   void Start();
+  void SendSuccessIfDoneFetching();
 
   // OAuth2TokenService::Consumer implementation.
   void OnGetTokenSuccess(const OAuth2TokenService::Request* request,
@@ -75,6 +81,12 @@
   void OnOAuthError() override;
   void OnNetworkError(int response_code) override;
 
+  // Overridden from GaiaAuthConsumer:
+  void OnClientLoginSuccess(const ClientLoginResult& result) override;
+  void OnClientLoginFailure(const GoogleServiceAuthError& error) override;
+  void OnGetUserInfoSuccess(const UserInfoMap& data) override;
+  void OnGetUserInfoFailure(const GoogleServiceAuthError& error) override;
+
  private:
   OAuth2TokenService* token_service_;
   net::URLRequestContextGetter* request_context_getter_;
@@ -83,6 +95,10 @@
 
   scoped_ptr<OAuth2TokenService::Request> login_token_request_;
   scoped_ptr<gaia::GaiaOAuthClient> gaia_oauth_client_;
+  scoped_ptr<GaiaAuthFetcher> gaia_auth_fetcher_;
+
+  scoped_ptr<base::DictionaryValue> fetched_user_info_;
+  scoped_ptr<std::vector<std::string> > fetched_service_flags_;
 };
 
 AccountInfoFetcher::AccountInfoFetcher(
@@ -108,10 +124,18 @@
   OAuth2TokenService::ScopeSet scopes;
   scopes.insert(GaiaConstants::kGoogleUserInfoEmail);
   scopes.insert(GaiaConstants::kGoogleUserInfoProfile);
+  scopes.insert(GaiaConstants::kOAuth1LoginScope);
   login_token_request_ = token_service_->StartRequest(
       account_id_, scopes, this);
 }
 
+void AccountInfoFetcher::SendSuccessIfDoneFetching() {
+  if (fetched_user_info_ && fetched_service_flags_) {
+    service_->OnUserInfoFetchSuccess(
+        this, fetched_user_info_.get(), fetched_service_flags_.get());
+  }
+}
+
 void AccountInfoFetcher::OnGetTokenSuccess(
     const OAuth2TokenService::Request* request,
     const std::string& access_token,
@@ -121,9 +145,14 @@
   DCHECK_EQ(request, login_token_request_.get());
 
   gaia_oauth_client_.reset(new gaia::GaiaOAuthClient(request_context_getter_));
-
   const int kMaxRetries = 3;
   gaia_oauth_client_->GetUserInfo(access_token, kMaxRetries, this);
+
+  gaia_auth_fetcher_.reset(
+      new GaiaAuthFetcher(
+          this, GaiaConstants::kChromeSource, request_context_getter_));
+  gaia_auth_fetcher_->StartOAuthLogin(
+      access_token, GaiaConstants::kGaiaService);
 }
 
 void AccountInfoFetcher::OnGetTokenFailure(
@@ -148,7 +177,36 @@
                                "OnGetUserInfoResponse",
                                "account_id",
                                account_id_);
-  service_->OnUserInfoFetchSuccess(this, user_info.get());
+  fetched_user_info_ = user_info.Pass();
+  SendSuccessIfDoneFetching();
+}
+
+void AccountInfoFetcher::OnClientLoginSuccess(
+    const ClientLoginResult& result) {
+  gaia_auth_fetcher_->StartGetUserInfo(result.lsid);
+}
+
+void AccountInfoFetcher::OnClientLoginFailure(
+    const GoogleServiceAuthError& error) {
+  service_->OnUserInfoFetchFailure(this);
+}
+
+void AccountInfoFetcher::OnGetUserInfoSuccess(const UserInfoMap& data) {
+  fetched_service_flags_.reset(new std::vector<std::string>);
+  UserInfoMap::const_iterator services_iter = data.find("allServices");
+  if (services_iter != data.end()) {
+    base::SplitString(services_iter->second, ',', fetched_service_flags_.get());
+    SendSuccessIfDoneFetching();
+  } else {
+    DLOG(WARNING) << "AccountInfoFetcher::OnGetUserInfoSuccess: "
+                  << "GetUserInfo response didn't include allServices field.";
+    service_->OnUserInfoFetchFailure(this);
+  }
+}
+
+void AccountInfoFetcher::OnGetUserInfoFailure(
+    const GoogleServiceAuthError& error) {
+  service_->OnUserInfoFetchFailure(this);
 }
 
 void AccountInfoFetcher::OnOAuthError() {
@@ -440,7 +498,8 @@
 
 void AccountTrackerService::SetAccountStateFromUserInfo(
     const std::string& account_id,
-    const base::DictionaryValue* user_info) {
+    const base::DictionaryValue* user_info,
+    const std::vector<std::string>* service_flags) {
   AccountState& state = accounts_[account_id];
 
   std::string gaia_id;
@@ -461,6 +520,8 @@
     user_info->GetString("given_name", &state.info.given_name);
     user_info->GetString("locale", &state.info.locale);
 
+    state.info.service_flags = *service_flags;
+
     NotifyAccountUpdated(state);
     SaveToPrefs(state);
   }
@@ -468,11 +529,12 @@
 
 void AccountTrackerService::OnUserInfoFetchSuccess(
     AccountInfoFetcher* fetcher,
-    const base::DictionaryValue* user_info) {
+    const base::DictionaryValue* user_info,
+    const std::vector<std::string>* service_flags) {
   const std::string& account_id = fetcher->account_id();
   DCHECK(ContainsKey(accounts_, account_id));
 
-  SetAccountStateFromUserInfo(account_id, user_info);
+  SetAccountStateFromUserInfo(account_id, user_info, service_flags);
   DeleteFetcher(fetcher);
 }
 
@@ -516,6 +578,18 @@
           state.info.given_name = base::UTF16ToUTF8(value);
         if (dict->GetString(kAccountLocalePath, &value))
           state.info.locale = base::UTF16ToUTF8(value);
+
+        const base::ListValue* service_flags_list;
+        if (dict->GetList(kAccountServiceFlagsPath, &service_flags_list)) {
+          std::string flag;
+          for(base::Value* flag: *service_flags_list) {
+            std::string flag_string;
+            if(flag->GetAsString(&flag_string)) {
+              state.info.service_flags.push_back(flag_string);
+            }
+          }
+        }
+
         if (state.info.IsValid())
           NotifyAccountUpdated(state);
       }
@@ -552,6 +626,12 @@
   dict->SetString(kAccountFullNamePath, state.info.full_name);
   dict->SetString(kAccountGivenNamePath, state.info.given_name);
   dict->SetString(kAccountLocalePath, state.info.locale);
+
+  scoped_ptr<base::ListValue> service_flags_list;
+  service_flags_list.reset(new base::ListValue);
+  service_flags_list->AppendStrings(state.info.service_flags);
+
+  dict->Set(kAccountServiceFlagsPath, service_flags_list.Pass());
 }
 
 void AccountTrackerService::RemoveFromPrefs(const AccountState& state) {
diff --git a/components/signin/core/browser/account_tracker_service.h b/components/signin/core/browser/account_tracker_service.h
index 2040e70..4debf41 100644
--- a/components/signin/core/browser/account_tracker_service.h
+++ b/components/signin/core/browser/account_tracker_service.h
@@ -58,6 +58,7 @@
     std::string given_name;
     std::string hosted_domain;
     std::string locale;
+    std::vector<std::string> service_flags;
     // TODO(rogerta): eventually this structure will include other information
     // about the account, like full name, profile picture URL, etc.
 
@@ -130,15 +131,18 @@
 
  protected:
   // Available to be called in tests.
-  void SetAccountStateFromUserInfo(const std::string& account_id,
-                                   const base::DictionaryValue* user_info);
+  void SetAccountStateFromUserInfo(
+      const std::string& account_id,
+      const base::DictionaryValue* user_info,
+      const std::vector<std::string>* service_flags);
 
  private:
   friend class AccountInfoFetcher;
 
   // These methods are called by fetchers.
   void OnUserInfoFetchSuccess(AccountInfoFetcher* fetcher,
-                              const base::DictionaryValue* user_info);
+                              const base::DictionaryValue* user_info,
+                              const std::vector<std::string>* service_flags);
   void OnUserInfoFetchFailure(AccountInfoFetcher* fetcher);
 
   // Refreshes the AccountInfo associated with |account_id| if it's invalid or
diff --git a/components/signin/core/browser/account_tracker_service_unittest.cc b/components/signin/core/browser/account_tracker_service_unittest.cc
index 3ea1ab4..fe4a929 100644
--- a/components/signin/core/browser/account_tracker_service_unittest.cc
+++ b/components/signin/core/browser/account_tracker_service_unittest.cc
@@ -39,6 +39,10 @@
       \"hd\": \"\",           \
     }";
 
+const std::string kLSIDResponse = "{ lsid: \"Foo\" }";
+
+const std::string kServiceFlags = "allServices=Service1,Service2";
+
 enum TrackingEventType {
   UPDATED,
   REMOVED,
@@ -74,6 +78,9 @@
   EXPECT_EQ(AccountIdToFullName(account_id), info.full_name);
   EXPECT_EQ(AccountIdToGivenName(account_id), info.given_name);
   EXPECT_EQ(AccountIdToLocale(account_id), info.locale);
+  EXPECT_EQ(2U, info.service_flags.size());
+  EXPECT_EQ("Service1", info.service_flags[0]);
+  EXPECT_EQ("Service2", info.service_flags[1]);
 }
 
 class TrackingEvent {
@@ -340,6 +347,8 @@
   ReturnOAuthUrlFetchResults(gaia::GaiaOAuthClient::kUrlFetcherId,
                              net::HTTP_OK,
                              GenerateValidTokenInfoResponse(account_id));
+  ReturnOAuthUrlFetchResults(0, net::HTTP_OK, kLSIDResponse);
+  ReturnOAuthUrlFetchResults(0, net::HTTP_OK, kServiceFlags);
 }
 
 void AccountTrackerServiceTest::ReturnOAuthUrlFetchSuccessIncomplete(
diff --git a/components/signin/core/browser/mutable_profile_oauth2_token_service.cc b/components/signin/core/browser/mutable_profile_oauth2_token_service.cc
index 849c7731..9995142 100644
--- a/components/signin/core/browser/mutable_profile_oauth2_token_service.cc
+++ b/components/signin/core/browser/mutable_profile_oauth2_token_service.cc
@@ -373,9 +373,6 @@
               << "account_id=" << account_id;
       std::string revoke_reason = refresh_token_present ? "token differs" :
                                                           "token is missing";
-      LOG(WARNING) << "Revoking refresh token on server. "
-                   << "Reason: token update, " << revoke_reason;
-      RevokeCredentialsOnServer(refresh_tokens_[account_id]->refresh_token());
       CancelRequestsForAccount(account_id);
       ClearCacheForAccount(account_id);
       refresh_tokens_[account_id]->set_refresh_token(refresh_token);
diff --git a/components/sync_driver/pref_names.cc b/components/sync_driver/pref_names.cc
index 1a5727a..8caf875 100644
--- a/components/sync_driver/pref_names.cc
+++ b/components/sync_driver/pref_names.cc
@@ -104,6 +104,12 @@
 // that we only want to use once.
 const char kSyncPassphrasePrompted[] = "sync.passphrase_prompted";
 
+// Stores how many times received MEMORY_PRESSURE_LEVEL_CRITICAL.
+const char kSyncMemoryPressureWarningCount[] = "sync.memory_warning_count";
+
+// Stores if sync shutdown cleanly.
+const char kSyncShutdownCleanly[] = "sync.shutdown_cleanly";
+
 }  // namespace prefs
 
 }  // namespace sync_driver
diff --git a/components/sync_driver/pref_names.h b/components/sync_driver/pref_names.h
index 3cbce22..2491390 100644
--- a/components/sync_driver/pref_names.h
+++ b/components/sync_driver/pref_names.h
@@ -66,6 +66,9 @@
 
 extern const char kSyncPassphrasePrompted[];
 
+extern const char kSyncMemoryPressureWarningCount[];
+extern const char kSyncShutdownCleanly[];
+
 }  // namespace prefs
 
 }  // namespace sync_driver
diff --git a/components/sync_driver/sync_prefs.cc b/components/sync_driver/sync_prefs.cc
index 82106ee..9f80075 100644
--- a/components/sync_driver/sync_prefs.cc
+++ b/components/sync_driver/sync_prefs.cc
@@ -83,6 +83,10 @@
   registry->RegisterIntegerPref(prefs::kSyncRemainingRollbackTries, 0);
 
   registry->RegisterBooleanPref(prefs::kSyncPassphrasePrompted, false);
+
+  registry->RegisterIntegerPref(prefs::kSyncMemoryPressureWarningCount, -1);
+
+  registry->RegisterBooleanPref(prefs::kSyncShutdownCleanly, false);
 }
 
 void SyncPrefs::AddSyncPrefObserver(SyncPrefObserver* sync_pref_observer) {
@@ -455,4 +459,22 @@
   pref_service_->SetBoolean(prefs::kSyncPassphrasePrompted, value);
 }
 
+int SyncPrefs::GetMemoryPressureWarningCount() const {
+  return pref_service_->GetInteger(prefs::kSyncMemoryPressureWarningCount);
+}
+
+void SyncPrefs::SetMemoryPressureWarningCount(int value) {
+  pref_service_->SetInteger(prefs::kSyncMemoryPressureWarningCount, value);
+}
+
+bool SyncPrefs::DidSyncShutdownCleanly() const {
+  return pref_service_->GetBoolean(prefs::kSyncShutdownCleanly);
+}
+
+void SyncPrefs::SetCleanShutdown(bool value) {
+  pref_service_->SetBoolean(prefs::kSyncShutdownCleanly, value);
+}
+
 }  // namespace sync_driver
+
+
diff --git a/components/sync_driver/sync_prefs.h b/components/sync_driver/sync_prefs.h
index 5a3abe5..10b3bcd 100644
--- a/components/sync_driver/sync_prefs.h
+++ b/components/sync_driver/sync_prefs.h
@@ -143,6 +143,16 @@
   // For testing.
   void SetManagedForTest(bool is_managed);
 
+  // Get/Set number of memory warnings received.
+  int GetMemoryPressureWarningCount() const;
+  void SetMemoryPressureWarningCount(int value);
+
+  // Check if the previous shutdown was clean.
+  bool DidSyncShutdownCleanly() const;
+
+  // Set whetherthe last shutdown was clean.
+  void SetCleanShutdown(bool value);
+
  private:
   void RegisterPrefGroups();
 
diff --git a/components/user_manager/user_manager_base.cc b/components/user_manager/user_manager_base.cc
index 8b1feae..3e11ff8 100644
--- a/components/user_manager/user_manager_base.cc
+++ b/components/user_manager/user_manager_base.cc
@@ -1148,6 +1148,10 @@
 
 void UserManagerBase::SetKnownUserDeviceId(const UserID& user_id,
                                            const std::string& device_id) {
+  const std::string known_device_id = GetKnownUserDeviceId(user_id);
+  if (!known_device_id.empty() && device_id != known_device_id) {
+    NOTREACHED() << "Trying to change device ID for known user.";
+  }
   SetKnownUserStringPref(user_id, kDeviceId, device_id);
 }
 
diff --git a/components/webcrypto/jwk.cc b/components/webcrypto/jwk.cc
index 4e1781d..8a9ad74 100644
--- a/components/webcrypto/jwk.cc
+++ b/components/webcrypto/jwk.cc
@@ -369,7 +369,7 @@
 
 void JwkWriter::ToJson(std::vector<uint8_t>* utf8_bytes) const {
   std::string json;
-  base::JSONWriter::Write(&dict_, &json);
+  base::JSONWriter::Write(dict_, &json);
   utf8_bytes->assign(json.begin(), json.end());
 }
 
diff --git a/components/webcrypto/test/test_helpers.cc b/components/webcrypto/test/test_helpers.cc
index 76da7fa..8e24c95f 100644
--- a/components/webcrypto/test/test_helpers.cc
+++ b/components/webcrypto/test/test_helpers.cc
@@ -168,7 +168,7 @@
 
 std::vector<uint8_t> MakeJsonVector(const base::DictionaryValue& dict) {
   std::string json;
-  base::JSONWriter::Write(&dict, &json);
+  base::JSONWriter::Write(dict, &json);
   return MakeJsonVector(json);
 }
 
diff --git a/content/browser/accessibility/accessibility_tree_formatter_mac.mm b/content/browser/accessibility/accessibility_tree_formatter_mac.mm
index 7b99225..b3799a9 100644
--- a/content/browser/accessibility/accessibility_tree_formatter_mac.mm
+++ b/content/browser/accessibility/accessibility_tree_formatter_mac.mm
@@ -267,7 +267,7 @@
     const base::Value* value;
     if (dict.Get(requestedAttributeUTF8, &value)) {
       std::string json_value;
-      base::JSONWriter::Write(value, &json_value);
+      base::JSONWriter::Write(*value, &json_value);
       WriteAttribute(
           [defaultAttributes containsObject:requestedAttribute],
           StringPrintf("%s=%s",
diff --git a/content/browser/accessibility/accessibility_ui.cc b/content/browser/accessibility/accessibility_ui.cc
index 3bfa6ee6..1a46646 100644
--- a/content/browser/accessibility/accessibility_ui.cc
+++ b/content/browser/accessibility/accessibility_ui.cc
@@ -116,14 +116,14 @@
     rvh_list->Append(BuildTargetDescriptor(rvh));
   }
 
-  scoped_ptr<base::DictionaryValue> data(new base::DictionaryValue());
-  data->Set("list", rvh_list.release());
-  data->SetInteger(
+  base::DictionaryValue data;
+  data.Set("list", rvh_list.release());
+  data.SetInteger(
       "global_a11y_mode",
       BrowserAccessibilityStateImpl::GetInstance()->accessibility_mode());
 
   std::string json_string;
-  base::JSONWriter::Write(data.get(), &json_string);
+  base::JSONWriter::Write(data, &json_string);
 
   callback.Run(base::RefCountedString::TakeString(&json_string));
   return true;
diff --git a/content/browser/android/in_process/synchronous_compositor_impl.cc b/content/browser/android/in_process/synchronous_compositor_impl.cc
index 24232ae..d3c6b83 100644
--- a/content/browser/android/in_process/synchronous_compositor_impl.cc
+++ b/content/browser/android/in_process/synchronous_compositor_impl.cc
@@ -316,6 +316,7 @@
 void SynchronousCompositorImpl::DidActivatePendingTree() {
   DCHECK(compositor_client_);
   compositor_client_->DidUpdateContent();
+  DeliverMessages();
 }
 
 gfx::ScrollOffset SynchronousCompositorImpl::GetTotalScrollOffset() {
diff --git a/content/browser/android/tracing_controller_android.cc b/content/browser/android/tracing_controller_android.cc
index 6953a0de..5c14535a 100644
--- a/content/browser/android/tracing_controller_android.cc
+++ b/content/browser/android/tracing_controller_android.cc
@@ -91,14 +91,14 @@
 
 void TracingControllerAndroid::OnKnownCategoriesReceived(
     const std::set<std::string>& categories_received) {
-  scoped_ptr<base::ListValue> category_list(new base::ListValue());
+  base::ListValue category_list;
   for (std::set<std::string>::const_iterator it = categories_received.begin();
        it != categories_received.end();
        ++it) {
-    category_list->AppendString(*it);
+    category_list.AppendString(*it);
   }
   std::string received_category_list;
-  base::JSONWriter::Write(category_list.get(), &received_category_list);
+  base::JSONWriter::Write(category_list, &received_category_list);
 
   // This log is required by adb_profile_chrome.py.
   LOG(WARNING) << "{\"traceCategoriesList\": " << received_category_list << "}";
diff --git a/content/browser/appcache/appcache_disk_cache.cc b/content/browser/appcache/appcache_disk_cache.cc
index 382ed45..03d348c7 100644
--- a/content/browser/appcache/appcache_disk_cache.cc
+++ b/content/browser/appcache/appcache_disk_cache.cc
@@ -8,6 +8,7 @@
 #include "base/bind_helpers.h"
 #include "base/files/file_path.h"
 #include "base/logging.h"
+#include "base/memory/ref_counted.h"
 #include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
@@ -114,70 +115,95 @@
 
 // Separate object to hold state for each Create, Delete, or Doom call
 // while the call is in-flight and to produce an EntryImpl upon completion.
-class AppCacheDiskCache::ActiveCall {
+class AppCacheDiskCache::ActiveCall
+    : public base::RefCounted<AppCacheDiskCache::ActiveCall> {
  public:
-  explicit ActiveCall(AppCacheDiskCache* owner)
-      : entry_(NULL),
-        owner_(owner),
-        entry_ptr_(NULL) {
+  static int CreateEntry(const base::WeakPtr<AppCacheDiskCache>& owner,
+                         int64 key, Entry** entry,
+                         const net::CompletionCallback& callback) {
+    scoped_refptr<ActiveCall> active_call(
+        new ActiveCall(owner, entry, callback));
+    int rv = owner->disk_cache()->CreateEntry(
+        base::Int64ToString(key), &active_call->entry_ptr_,
+        base::Bind(&ActiveCall::OnAsyncCompletion, active_call));
+    return active_call->HandleImmediateReturnValue(rv);
   }
 
-  int CreateEntry(int64 key, Entry** entry,
-                  const net::CompletionCallback& callback) {
-    int rv = owner_->disk_cache()->CreateEntry(
-        base::Int64ToString(key), &entry_ptr_,
-        base::Bind(&ActiveCall::OnAsyncCompletion, base::Unretained(this)));
-    return HandleImmediateReturnValue(rv, entry, callback);
+  static int OpenEntry(const base::WeakPtr<AppCacheDiskCache>& owner,
+                       int64 key, Entry** entry,
+                       const net::CompletionCallback& callback) {
+    scoped_refptr<ActiveCall> active_call(
+        new ActiveCall(owner, entry, callback));
+    int rv = owner->disk_cache()->OpenEntry(
+        base::Int64ToString(key), &active_call->entry_ptr_,
+        base::Bind(&ActiveCall::OnAsyncCompletion, active_call));
+    return active_call->HandleImmediateReturnValue(rv);
   }
 
-  int OpenEntry(int64 key, Entry** entry,
-                const net::CompletionCallback& callback) {
-    int rv = owner_->disk_cache()->OpenEntry(
-        base::Int64ToString(key), &entry_ptr_,
-        base::Bind(&ActiveCall::OnAsyncCompletion, base::Unretained(this)));
-    return HandleImmediateReturnValue(rv, entry, callback);
-  }
-
-  int DoomEntry(int64 key, const net::CompletionCallback& callback) {
-    int rv = owner_->disk_cache()->DoomEntry(
+  static int DoomEntry(const base::WeakPtr<AppCacheDiskCache>& owner,
+                       int64 key, const net::CompletionCallback& callback) {
+    scoped_refptr<ActiveCall> active_call(
+        new ActiveCall(owner, nullptr, callback));
+    int rv = owner->disk_cache()->DoomEntry(
         base::Int64ToString(key),
-        base::Bind(&ActiveCall::OnAsyncCompletion, base::Unretained(this)));
-    return HandleImmediateReturnValue(rv, NULL, callback);
+        base::Bind(&ActiveCall::OnAsyncCompletion, active_call));
+    return active_call->HandleImmediateReturnValue(rv);
   }
 
  private:
-  int HandleImmediateReturnValue(int rv, Entry** entry,
-                                 const net::CompletionCallback& callback) {
+  friend class base::RefCounted<AppCacheDiskCache::ActiveCall>;
+
+  ActiveCall(const base::WeakPtr<AppCacheDiskCache>& owner,
+             Entry** entry,
+             const net::CompletionCallback& callback)
+      : owner_(owner),
+        entry_(entry),
+        callback_(callback),
+        entry_ptr_(nullptr) {
+    DCHECK(owner_);
+  }
+
+  ~ActiveCall() {}
+
+  int HandleImmediateReturnValue(int rv) {
     if (rv == net::ERR_IO_PENDING) {
       // OnAsyncCompletion will be called later.
-      callback_ = callback;
-      entry_ = entry;
-      owner_->AddActiveCall(this);
-      return net::ERR_IO_PENDING;
+      return rv;
     }
-    if (rv == net::OK && entry)
-      *entry = new EntryImpl(entry_ptr_, owner_);
-    delete this;
+
+    if (rv == net::OK && entry_) {
+      DCHECK(entry_ptr_);
+      *entry_ = new EntryImpl(entry_ptr_, owner_.get());
+    }
     return rv;
   }
 
   void OnAsyncCompletion(int rv) {
-    owner_->RemoveActiveCall(this);
-    if (rv == net::OK && entry_)
-      *entry_ = new EntryImpl(entry_ptr_, owner_);
+    if (rv == net::OK && entry_) {
+      DCHECK(entry_ptr_);
+      if (owner_) {
+        *entry_ = new EntryImpl(entry_ptr_, owner_.get());
+      } else {
+        entry_ptr_->Close();
+        rv = net::ERR_ABORTED;
+      }
+    }
     callback_.Run(rv);
-    callback_.Reset();
-    delete this;
   }
 
+  base::WeakPtr<AppCacheDiskCache> owner_;
   Entry** entry_;
   net::CompletionCallback callback_;
-  AppCacheDiskCache* owner_;
   disk_cache::Entry* entry_ptr_;
 };
 
 AppCacheDiskCache::AppCacheDiskCache()
-    : is_disabled_(false) {
+#if defined(APPCACHE_USE_SIMPLE_CACHE)
+    : AppCacheDiskCache(true)
+#else
+    : AppCacheDiskCache(false)
+#endif
+{
 }
 
 AppCacheDiskCache::~AppCacheDiskCache() {
@@ -225,7 +251,6 @@
   }
   open_entries_.clear();
   disk_cache_.reset();
-  STLDeleteElements(&active_calls_);
 }
 
 int AppCacheDiskCache::CreateEntry(int64 key, Entry** entry,
@@ -243,7 +268,8 @@
   if (!disk_cache_)
     return net::ERR_FAILED;
 
-  return (new ActiveCall(this))->CreateEntry(key, entry, callback);
+  return ActiveCall::CreateEntry(
+      weak_factory_.GetWeakPtr(), key, entry, callback);
 }
 
 int AppCacheDiskCache::OpenEntry(int64 key, Entry** entry,
@@ -261,7 +287,8 @@
   if (!disk_cache_)
     return net::ERR_FAILED;
 
-  return (new ActiveCall(this))->OpenEntry(key, entry, callback);
+  return ActiveCall::OpenEntry(
+      weak_factory_.GetWeakPtr(), key, entry, callback);
 }
 
 int AppCacheDiskCache::DoomEntry(int64 key,
@@ -278,7 +305,13 @@
   if (!disk_cache_)
     return net::ERR_FAILED;
 
-  return (new ActiveCall(this))->DoomEntry(key, callback);
+  return ActiveCall::DoomEntry(weak_factory_.GetWeakPtr(), key, callback);
+}
+
+AppCacheDiskCache::AppCacheDiskCache(bool use_simple_cache)
+    : use_simple_cache_(use_simple_cache),
+      is_disabled_(false),
+      weak_factory_(this) {
 }
 
 AppCacheDiskCache::PendingCall::PendingCall()
@@ -310,14 +343,10 @@
   is_disabled_ = false;
   create_backend_callback_ = new CreateBackendCallbackShim(this);
 
-#if defined(APPCACHE_USE_SIMPLE_CACHE)
-  const net::BackendType backend_type = net::CACHE_BACKEND_SIMPLE;
-#else
-  const net::BackendType backend_type = net::CACHE_BACKEND_DEFAULT;
-#endif
   int rv = disk_cache::CreateCacheBackend(
       cache_type,
-      backend_type,
+      use_simple_cache_ ? net::CACHE_BACKEND_SIMPLE
+                        : net::CACHE_BACKEND_DEFAULT,
       cache_directory,
       cache_size,
       force,
diff --git a/content/browser/appcache/appcache_disk_cache.h b/content/browser/appcache/appcache_disk_cache.h
index 8995e83c..9165e1d 100644
--- a/content/browser/appcache/appcache_disk_cache.h
+++ b/content/browser/appcache/appcache_disk_cache.h
@@ -52,6 +52,9 @@
                 const net::CompletionCallback& callback) override;
   int DoomEntry(int64 key, const net::CompletionCallback& callback) override;
 
+ protected:
+  explicit AppCacheDiskCache(bool use_simple_cache);
+
  private:
   class CreateBackendCallbackShim;
   class EntryImpl;
@@ -96,18 +99,18 @@
            const scoped_refptr<base::SingleThreadTaskRunner>& cache_thread,
            const net::CompletionCallback& callback);
   void OnCreateBackendComplete(int rv);
-  void AddActiveCall(ActiveCall* call) { active_calls_.insert(call); }
-  void RemoveActiveCall(ActiveCall* call) { active_calls_.erase(call); }
   void AddOpenEntry(EntryImpl* entry) { open_entries_.insert(entry); }
   void RemoveOpenEntry(EntryImpl* entry) { open_entries_.erase(entry); }
 
+  bool use_simple_cache_;
   bool is_disabled_;
   net::CompletionCallback init_callback_;
   scoped_refptr<CreateBackendCallbackShim> create_backend_callback_;
   PendingCalls pending_calls_;
-  ActiveCalls active_calls_;
   OpenEntries open_entries_;
   scoped_ptr<disk_cache::Backend> disk_cache_;
+
+  base::WeakPtrFactory<AppCacheDiskCache> weak_factory_;
 };
 
 }  // namespace content
diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc
index 4d6c6c3..643cd38 100644
--- a/content/browser/browser_main_loop.cc
+++ b/content/browser/browser_main_loop.cc
@@ -50,7 +50,6 @@
 #include "content/common/host_discardable_shared_memory_manager.h"
 #include "content/common/host_shared_bitmap_manager.h"
 #include "content/public/browser/browser_main_parts.h"
-#include "content/public/browser/browser_shutdown.h"
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/tracing_controller.h"
@@ -336,30 +335,6 @@
 // The currently-running BrowserMainLoop.  There can be one or zero.
 BrowserMainLoop* g_current_browser_main_loop = NULL;
 
-// This is just to be able to keep ShutdownThreadsAndCleanUp out of
-// the public interface of BrowserMainLoop.
-class BrowserShutdownImpl {
- public:
-  static void ImmediateShutdownAndExitProcess() {
-    DCHECK(g_current_browser_main_loop);
-    g_current_browser_main_loop->ShutdownThreadsAndCleanUp();
-
-#if defined(OS_WIN)
-    // At this point the message loop is still running yet we've shut everything
-    // down. If any messages are processed we'll likely crash. Exit now.
-    ExitProcess(RESULT_CODE_NORMAL_EXIT);
-#elif defined(OS_POSIX) && !defined(OS_MACOSX)
-    _exit(RESULT_CODE_NORMAL_EXIT);
-#else
-    NOTIMPLEMENTED();
-#endif
-  }
-};
-
-void ImmediateShutdownAndExitProcess() {
-  BrowserShutdownImpl::ImmediateShutdownAndExitProcess();
-}
-
 // For measuring memory usage after each task. Behind a command line flag.
 class BrowserMainLoop::MemoryObserver : public base::MessageLoop::TaskObserver {
  public:
diff --git a/content/browser/devtools/devtools_agent_host_impl.cc b/content/browser/devtools/devtools_agent_host_impl.cc
index cba575e..4ccb496 100644
--- a/content/browser/devtools/devtools_agent_host_impl.cc
+++ b/content/browser/devtools/devtools_agent_host_impl.cc
@@ -242,7 +242,7 @@
         delegate->HandleCommand(this, command.get()));
     if (response) {
       std::string json_response;
-      base::JSONWriter::Write(response.get(), &json_response);
+      base::JSONWriter::Write(*response, &json_response);
       SendMessageToClient(json_response);
       return true;
     }
diff --git a/content/browser/devtools/protocol/devtools_protocol_browsertest.cc b/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
index cbae682..573aca4 100644
--- a/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
+++ b/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
@@ -39,7 +39,7 @@
       command.Set(kParamsParam, params.release());
 
     std::string json_command;
-    base::JSONWriter::Write(&command, &json_command);
+    base::JSONWriter::Write(command, &json_command);
     agent_host_->DispatchProtocolMessage(json_command);
     base::MessageLoop::current()->Run();
   }
diff --git a/content/browser/devtools/protocol/devtools_protocol_client.cc b/content/browser/devtools/protocol/devtools_protocol_client.cc
index 4658b08..4b7c25d 100644
--- a/content/browser/devtools/protocol/devtools_protocol_client.cc
+++ b/content/browser/devtools/protocol/devtools_protocol_client.cc
@@ -46,7 +46,7 @@
 
 void DevToolsProtocolClient::SendMessage(const base::DictionaryValue& message) {
   std::string json_message;
-  base::JSONWriter::Write(&message, &json_message);
+  base::JSONWriter::Write(message, &json_message);
   SendRawMessage(json_message);
 }
 
diff --git a/content/browser/devtools/render_frame_devtools_agent_host.cc b/content/browser/devtools/render_frame_devtools_agent_host.cc
index 6f40d6fa..665885a2 100644
--- a/content/browser/devtools/render_frame_devtools_agent_host.cc
+++ b/content/browser/devtools/render_frame_devtools_agent_host.cc
@@ -417,6 +417,7 @@
 void RenderFrameDevToolsAgentHost::ClearRenderFrameHost() {
   DCHECK(render_frame_host_);
   render_frame_host_ = nullptr;
+  WebContentsObserver::Observe(nullptr);
   dom_handler_->SetRenderFrameHost(nullptr);
   if (emulation_handler_)
     emulation_handler_->SetRenderFrameHost(nullptr);
diff --git a/content/browser/dom_storage/dom_storage_area.cc b/content/browser/dom_storage/dom_storage_area.cc
index 67c7b98..e76f5c9 100644
--- a/content/browser/dom_storage/dom_storage_area.cc
+++ b/content/browser/dom_storage/dom_storage_area.cc
@@ -37,8 +37,8 @@
 
 // To avoid excessive IO we apply limits to the amount of data being written
 // and the frequency of writes. The specific values used are somewhat arbitrary.
-const int kMaxBytesPerDay = kPerStorageAreaQuota * 2;
-const int kMaxCommitsPerHour = 6;
+const int kMaxBytesPerHour = kPerStorageAreaQuota;
+const int kMaxCommitsPerHour = 60;
 
 }  // namespace
 
@@ -109,7 +109,7 @@
       is_shutdown_(false),
       commit_batches_in_flight_(0),
       start_time_(base::TimeTicks::Now()),
-      data_rate_limiter_(kMaxBytesPerDay, base::TimeDelta::FromHours(24)),
+      data_rate_limiter_(kMaxBytesPerHour, base::TimeDelta::FromHours(1)),
       commit_rate_limiter_(kMaxCommitsPerHour, base::TimeDelta::FromHours(1)) {
   if (!directory.empty()) {
     base::FilePath path = directory.Append(DatabaseFileNameFromOrigin(origin_));
@@ -134,7 +134,7 @@
       is_shutdown_(false),
       commit_batches_in_flight_(0),
       start_time_(base::TimeTicks::Now()),
-      data_rate_limiter_(kMaxBytesPerDay, base::TimeDelta::FromHours(24)),
+      data_rate_limiter_(kMaxBytesPerHour, base::TimeDelta::FromHours(1)),
       commit_rate_limiter_(kMaxCommitsPerHour, base::TimeDelta::FromHours(1)) {
   DCHECK(namespace_id != kLocalStorageNamespaceId);
   if (session_storage_backing) {
diff --git a/content/browser/frame_host/navigation_controller_impl.cc b/content/browser/frame_host/navigation_controller_impl.cc
index 8339b730..b9d69554 100644
--- a/content/browser/frame_host/navigation_controller_impl.cc
+++ b/content/browser/frame_host/navigation_controller_impl.cc
@@ -13,6 +13,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
 #include "base/trace_event/trace_event.h"
+#include "build/build_config.h"
 #include "cc/base/switches.h"
 #include "components/mime_util/mime_util.h"
 #include "content/browser/bad_message.h"
@@ -40,8 +41,8 @@
 #include "content/public/common/content_client.h"
 #include "content/public/common/content_constants.h"
 #include "content/public/common/content_switches.h"
+#include "media/base/mime_util.h"
 #include "net/base/escape.h"
-#include "net/base/mime_util.h"
 #include "net/base/net_util.h"
 #include "skia/ext/platform_canvas.h"
 #include "url/url_constants.h"
@@ -496,7 +497,7 @@
   const std::string& mime_type = delegate_->GetContentsMimeType();
   bool is_viewable_mime_type =
       mime_util::IsSupportedNonImageMimeType(mime_type) &&
-      !net::IsSupportedMediaMimeType(mime_type);
+      !media::IsSupportedMediaMimeType(mime_type);
   NavigationEntry* visible_entry = GetVisibleEntry();
   return visible_entry && !visible_entry->IsViewSourceMode() &&
       is_viewable_mime_type && !delegate_->GetInterstitialPage();
diff --git a/content/browser/frame_host/render_frame_host_impl_browsertest.cc b/content/browser/frame_host/render_frame_host_impl_browsertest.cc
index 9344c92..33826a0 100644
--- a/content/browser/frame_host/render_frame_host_impl_browsertest.cc
+++ b/content/browser/frame_host/render_frame_host_impl_browsertest.cc
@@ -56,7 +56,9 @@
 using RenderFrameHostImplBrowserTest = ContentBrowserTest;
 
 // Test that when creating a new window, the main frame is correctly focused.
-IN_PROC_BROWSER_TEST_F(RenderFrameHostImplBrowserTest, IsFocused_AtLoad) {
+// flaky http://crbug.com/452631
+IN_PROC_BROWSER_TEST_F(RenderFrameHostImplBrowserTest,
+                       DISABLED_IsFocused_AtLoad) {
   EXPECT_TRUE(
       NavigateToURL(shell(), GetTestUrl("render_frame_host", "focus.html")));
 
@@ -122,7 +124,9 @@
 
 // Test that even if the frame is focused in the frame tree but its
 // RenderWidgetHost is not focused, it is not considered as focused.
-IN_PROC_BROWSER_TEST_F(RenderFrameHostImplBrowserTest, IsFocused_Widget) {
+// flaky http://crbug.com/452631
+IN_PROC_BROWSER_TEST_F(RenderFrameHostImplBrowserTest,
+                       DISABLED_IsFocused_Widget) {
   EXPECT_TRUE(
       NavigateToURL(shell(), GetTestUrl("render_frame_host", "focus.html")));
   WebContents* web_contents = shell()->web_contents();
diff --git a/content/browser/frame_host/render_frame_host_manager_unittest.cc b/content/browser/frame_host/render_frame_host_manager_unittest.cc
index 0d36597..ec75f5b 100644
--- a/content/browser/frame_host/render_frame_host_manager_unittest.cc
+++ b/content/browser/frame_host/render_frame_host_manager_unittest.cc
@@ -202,6 +202,31 @@
   DISALLOW_COPY_AND_ASSIGN(RenderFrameHostDeletedObserver);
 };
 
+// This WebContents observer keep track of its RVH change.
+class RenderViewHostChangedObserver : public WebContentsObserver {
+ public:
+  RenderViewHostChangedObserver(WebContents* web_contents)
+      : WebContentsObserver(web_contents), host_changed_(false) {}
+
+  // WebContentsObserver.
+  void RenderViewHostChanged(RenderViewHost* old_host,
+                             RenderViewHost* new_host) override {
+    host_changed_ = true;
+  }
+
+  bool DidHostChange() {
+    bool host_changed = host_changed_;
+    Reset();
+    return host_changed;
+  }
+
+  void Reset() { host_changed_ = false; }
+
+ private:
+  bool host_changed_;
+  DISALLOW_COPY_AND_ASSIGN(RenderViewHostChangedObserver);
+};
+
 // This observer is used to check whether IPC messages are being filtered for
 // swapped out RenderFrameHost objects. It observes the plugin crash and favicon
 // update events, which the FilterMessagesWhileSwappedOut test simulates being
@@ -932,14 +957,11 @@
 // Tests the Navigate function. We navigate three sites consecutively and check
 // how the pending/committed RenderViewHost are modified.
 TEST_F(RenderFrameHostManagerTest, Navigate) {
-  TestNotificationTracker notifications;
-
   SiteInstance* instance = SiteInstance::Create(browser_context());
 
   scoped_ptr<TestWebContents> web_contents(
       TestWebContents::Create(browser_context(), instance));
-  notifications.ListenFor(NOTIFICATION_RENDER_VIEW_HOST_CHANGED,
-                          Source<WebContents>(web_contents.get()));
+  RenderViewHostChangedObserver change_observer(web_contents.get());
 
   RenderFrameHostManager* manager = web_contents->GetRenderManagerForTesting();
   RenderFrameHostImpl* host = NULL;
@@ -996,7 +1018,7 @@
   EXPECT_TRUE(GetPendingFrameHost(manager));
   ASSERT_EQ(host, GetPendingFrameHost(manager));
 
-  notifications.Reset();
+  change_observer.Reset();
 
   // Commit.
   manager->DidNavigateFrame(GetPendingFrameHost(manager), true);
@@ -1006,9 +1028,8 @@
   // Check the pending RenderFrameHost has been committed.
   EXPECT_FALSE(GetPendingFrameHost(manager));
 
-  // We should observe a notification.
-  EXPECT_TRUE(
-      notifications.Check1AndReset(NOTIFICATION_RENDER_VIEW_HOST_CHANGED));
+  // We should observe RVH changed event.
+  EXPECT_TRUE(change_observer.DidHostChange());
 }
 
 // Tests WebUI creation.
@@ -1612,8 +1633,6 @@
 
 // Test that we reuse the same guest SiteInstance if we navigate across sites.
 TEST_F(RenderFrameHostManagerTest, NoSwapOnGuestNavigations) {
-  TestNotificationTracker notifications;
-
   GURL guest_url(std::string(kGuestScheme).append("://abc123"));
   SiteInstance* instance =
       SiteInstance::CreateForURL(browser_context(), guest_url);
@@ -1675,9 +1694,8 @@
   BeforeUnloadFiredWebContentsDelegate delegate;
   scoped_ptr<TestWebContents> web_contents(
       TestWebContents::Create(browser_context(), instance));
+  RenderViewHostChangedObserver change_observer(web_contents.get());
   web_contents->SetDelegate(&delegate);
-  notifications.ListenFor(NOTIFICATION_RENDER_VIEW_HOST_CHANGED,
-                          Source<WebContents>(web_contents.get()));
 
   RenderFrameHostManager* manager = web_contents->GetRenderManagerForTesting();
 
@@ -1693,10 +1711,8 @@
   EXPECT_EQ(host, manager->current_frame_host());
   EXPECT_FALSE(GetPendingFrameHost(manager));
 
-  // We should observe a notification.
-  EXPECT_TRUE(
-      notifications.Check1AndReset(NOTIFICATION_RENDER_VIEW_HOST_CHANGED));
-  notifications.Reset();
+  // We should observe RVH changed event.
+  EXPECT_TRUE(change_observer.DidHostChange());
 
   // Commit.
   manager->DidNavigateFrame(host, true);
diff --git a/content/browser/geolocation/network_location_provider_unittest.cc b/content/browser/geolocation/network_location_provider_unittest.cc
index b8ef6ca..cc43330b 100644
--- a/content/browser/geolocation/network_location_provider_unittest.cc
+++ b/content/browser/geolocation/network_location_provider_unittest.cc
@@ -191,7 +191,7 @@
   static std::string PrettyJson(const base::Value& value) {
     std::string pretty;
     base::JSONWriter::WriteWithOptions(
-        &value, base::JSONWriter::OPTIONS_PRETTY_PRINT, &pretty);
+        value, base::JSONWriter::OPTIONS_PRETTY_PRINT, &pretty);
     return pretty;
   }
 
diff --git a/content/browser/geolocation/network_location_request.cc b/content/browser/geolocation/network_location_request.cc
index 253e321b..2a6c17ca 100644
--- a/content/browser/geolocation/network_location_request.cc
+++ b/content/browser/geolocation/network_location_request.cc
@@ -221,7 +221,7 @@
   AddWifiData(wifi_data, age, &request);
   if (!access_token.empty())
     request.SetString(kAccessTokenString, access_token);
-  base::JSONWriter::Write(&request, upload_data);
+  base::JSONWriter::Write(request, upload_data);
 }
 
 void AddString(const std::string& property_name, const std::string& value,
diff --git a/content/browser/indexed_db/indexed_db_backing_store.cc b/content/browser/indexed_db/indexed_db_backing_store.cc
index 79ab192..819aba5 100644
--- a/content/browser/indexed_db/indexed_db_backing_store.cc
+++ b/content/browser/indexed_db/indexed_db_backing_store.cc
@@ -958,7 +958,7 @@
   base::DictionaryValue root_dict;
   root_dict.SetString("message", message);
   std::string output_js;
-  base::JSONWriter::Write(&root_dict, &output_js);
+  base::JSONWriter::Write(root_dict, &output_js);
 
   base::File file(info_path,
                   base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
diff --git a/content/browser/indexed_db/indexed_db_database.cc b/content/browser/indexed_db/indexed_db_database.cc
index 6fbc77f87..8a924eb4 100644
--- a/content/browser/indexed_db/indexed_db_database.cc
+++ b/content/browser/indexed_db/indexed_db_database.cc
@@ -745,9 +745,7 @@
     IndexedDBTransaction* transaction) {
   IDB_TRACE1("IndexedDBDatabase::GetAllOperation", "txn.id", transaction->id());
 
-  DCHECK_GE(max_count, 0);
-  if (!max_count)
-    max_count = std::numeric_limits<decltype(max_count)>::max();
+  DCHECK_GT(max_count, 0);
 
   DCHECK(metadata_.object_stores.find(object_store_id) !=
          metadata_.object_stores.end());
diff --git a/content/browser/indexed_db/indexed_db_index_writer.cc b/content/browser/indexed_db/indexed_db_index_writer.cc
index c9de8a3..53ae963 100644
--- a/content/browser/indexed_db/indexed_db_index_writer.cc
+++ b/content/browser/indexed_db/indexed_db_index_writer.cc
@@ -160,7 +160,7 @@
     if (!can_add_keys)
       return true;
 
-    index_writers->push_back(index_writer.release());
+    index_writers->push_back(index_writer.Pass());
   }
 
   *completed = true;
diff --git a/content/browser/media/capture/capture_resolution_chooser.cc b/content/browser/media/capture/capture_resolution_chooser.cc
new file mode 100644
index 0000000..698882a
--- /dev/null
+++ b/content/browser/media/capture/capture_resolution_chooser.cc
@@ -0,0 +1,120 @@
+// 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 "content/browser/media/capture/capture_resolution_chooser.h"
+
+#include "media/base/limits.h"
+#include "media/base/video_util.h"
+
+namespace content {
+
+namespace {
+
+// Compute the minimum frame size from the given |max_frame_size| and
+// |resolution_change_policy|.
+gfx::Size ComputeMinimumCaptureSize(
+    const gfx::Size& max_frame_size,
+    media::ResolutionChangePolicy resolution_change_policy) {
+  switch (resolution_change_policy) {
+    case media::RESOLUTION_POLICY_FIXED_RESOLUTION:
+      return max_frame_size;
+    case media::RESOLUTION_POLICY_FIXED_ASPECT_RATIO: {
+      // TODO(miu): This is a place-holder until "min constraints" are plumbed-
+      // in from the MediaStream framework.  http://crbug.com/473336
+      const int kMinLines = 180;
+      if (max_frame_size.height() <= kMinLines)
+        return max_frame_size;
+      const gfx::Size result(
+          kMinLines * max_frame_size.width() / max_frame_size.height(),
+          kMinLines);
+      if (result.width() <= 0 || result.width() > media::limits::kMaxDimension)
+        return max_frame_size;
+      return result;
+    }
+    case media::RESOLUTION_POLICY_ANY_WITHIN_LIMIT:
+      return gfx::Size(1, 1);
+    case media::RESOLUTION_POLICY_LAST:
+      break;
+  }
+  NOTREACHED();
+  return gfx::Size(1, 1);
+}
+
+// Returns |size|, unless it exceeds |max_size| or is under |min_size|.  When
+// the bounds are exceeded, computes and returns an alternate size of similar
+// aspect ratio that is within the bounds.
+gfx::Size ComputeBoundedCaptureSize(const gfx::Size& size,
+                                    const gfx::Size& min_size,
+                                    const gfx::Size& max_size) {
+  if (size.width() > max_size.width() || size.height() > max_size.height()) {
+    gfx::Size result = media::ScaleSizeToFitWithinTarget(size, max_size);
+    result.SetToMax(min_size);
+    return result;
+  } else if (size.width() < min_size.width() ||
+             size.height() < min_size.height()) {
+    gfx::Size result = media::ScaleSizeToEncompassTarget(size, min_size);
+    result.SetToMin(max_size);
+    return result;
+  } else {
+    return size;
+  }
+}
+
+}  // namespace
+
+CaptureResolutionChooser::CaptureResolutionChooser(
+    const gfx::Size& max_frame_size,
+    media::ResolutionChangePolicy resolution_change_policy)
+    : max_frame_size_(max_frame_size),
+      min_frame_size_(ComputeMinimumCaptureSize(max_frame_size,
+                                                resolution_change_policy)),
+      resolution_change_policy_(resolution_change_policy),
+      constrained_size_(max_frame_size) {
+  DCHECK_LT(0, max_frame_size_.width());
+  DCHECK_LT(0, max_frame_size_.height());
+  DCHECK_LE(min_frame_size_.width(), max_frame_size_.width());
+  DCHECK_LE(min_frame_size_.height(), max_frame_size_.height());
+
+  RecomputeCaptureSize();
+}
+
+CaptureResolutionChooser::~CaptureResolutionChooser() {}
+
+void CaptureResolutionChooser::SetSourceSize(const gfx::Size& source_size) {
+  if (source_size.IsEmpty())
+    return;
+
+  switch (resolution_change_policy_) {
+    case media::RESOLUTION_POLICY_FIXED_RESOLUTION:
+      // Source size changes do not affect the frame resolution.  Frame
+      // resolution is always fixed to |max_frame_size_|.
+      break;
+
+    case media::RESOLUTION_POLICY_FIXED_ASPECT_RATIO:
+      constrained_size_ = ComputeBoundedCaptureSize(
+          media::PadToMatchAspectRatio(source_size, max_frame_size_),
+          min_frame_size_,
+          max_frame_size_);
+      RecomputeCaptureSize();
+      break;
+
+    case media::RESOLUTION_POLICY_ANY_WITHIN_LIMIT:
+      constrained_size_ = ComputeBoundedCaptureSize(
+          source_size, min_frame_size_, max_frame_size_);
+      RecomputeCaptureSize();
+      break;
+
+    case media::RESOLUTION_POLICY_LAST:
+      NOTREACHED();
+  }
+}
+
+void CaptureResolutionChooser::RecomputeCaptureSize() {
+  // TODO(miu): An upcoming change will introduce the ability to find the best
+  // capture resolution, given the current capabilities of the system.
+  // http://crbug.com/156767
+  capture_size_ = constrained_size_;
+}
+
+}  // namespace content
diff --git a/content/browser/media/capture/capture_resolution_chooser.h b/content/browser/media/capture/capture_resolution_chooser.h
new file mode 100644
index 0000000..f1bda79
--- /dev/null
+++ b/content/browser/media/capture/capture_resolution_chooser.h
@@ -0,0 +1,59 @@
+// 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_MEDIA_CAPTURE_CAPTURE_RESOLUTION_CHOOSER_H_
+#define CONTENT_BROWSER_MEDIA_CAPTURE_CAPTURE_RESOLUTION_CHOOSER_H_
+
+#include "content/common/content_export.h"
+#include "media/base/video_capture_types.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace content {
+
+// Encapsulates the logic that determines the capture frame resolution based on:
+//   1. The configured maximum frame resolution and resolution change policy.
+//   2. The resolution of the source content.
+//   3. The current capabilities of the end-to-end system, in terms of the
+//      maximum number of pixels per frame.
+class CONTENT_EXPORT CaptureResolutionChooser {
+ public:
+  // media::ResolutionChangePolicy determines whether the variable frame
+  // resolutions being computed must adhere to a fixed aspect ratio or not, or
+  // that there must only be a single fixed resolution.
+  CaptureResolutionChooser(
+      const gfx::Size& max_frame_size,
+      media::ResolutionChangePolicy resolution_change_policy);
+  ~CaptureResolutionChooser();
+
+  // Returns the current capture frame resolution to use.
+  gfx::Size capture_size() const {
+    return capture_size_;
+  }
+
+  // Updates the capture size based on a change in the resolution of the source
+  // content.
+  void SetSourceSize(const gfx::Size& source_size);
+
+ private:
+  // Called after any update that requires |capture_size_| be re-computed.
+  void RecomputeCaptureSize();
+
+  // Hard constraints.
+  const gfx::Size max_frame_size_;
+  const gfx::Size min_frame_size_;  // Computed from the ctor arguments.
+
+  // Specifies the set of heuristics to use.
+  const media::ResolutionChangePolicy resolution_change_policy_;
+
+  // The capture frame resolution to use, ignoring the limitations imposed by
+  // the capability metric.
+  gfx::Size constrained_size_;
+
+  // The current computed capture frame resolution.
+  gfx::Size capture_size_;
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_MEDIA_CAPTURE_RESOLUTION_CHOOSER_H_
diff --git a/content/browser/media/capture/capture_resolution_chooser_unittest.cc b/content/browser/media/capture/capture_resolution_chooser_unittest.cc
new file mode 100644
index 0000000..d91c0ce
--- /dev/null
+++ b/content/browser/media/capture/capture_resolution_chooser_unittest.cc
@@ -0,0 +1,169 @@
+// 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 "content/browser/media/capture/capture_resolution_chooser.h"
+
+#include "base/location.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using tracked_objects::Location;
+
+namespace content {
+
+namespace {
+
+// 16:9 maximum and minimum frame sizes.
+const int kMaxFrameWidth = 3840;
+const int kMaxFrameHeight = 2160;
+const int kMinFrameWidth = 320;
+const int kMinFrameHeight = 180;
+
+// Checks whether |size| is strictly between (inclusive) |min_size| and
+// |max_size| and has the same aspect ratio as |max_size|.
+void ExpectIsWithinBoundsAndSameAspectRatio(const Location& location,
+                                            const gfx::Size& min_size,
+                                            const gfx::Size& max_size,
+                                            const gfx::Size& size) {
+  SCOPED_TRACE(::testing::Message() << "From here: " << location.ToString());
+  EXPECT_LE(min_size.width(), size.width());
+  EXPECT_LE(min_size.height(), size.height());
+  EXPECT_GE(max_size.width(), size.width());
+  EXPECT_GE(max_size.height(), size.height());
+  EXPECT_NEAR(static_cast<double>(max_size.width()) / max_size.height(),
+              static_cast<double>(size.width()) / size.height(),
+              0.01);
+}
+
+}  // namespace
+
+TEST(CaptureResolutionChooserTest,
+     FixedResolutionPolicy_CaptureSizeAlwaysFixed) {
+  const gfx::Size the_one_frame_size(kMaxFrameWidth, kMaxFrameHeight);
+  CaptureResolutionChooser chooser(the_one_frame_size,
+                                   media::RESOLUTION_POLICY_FIXED_RESOLUTION);
+  EXPECT_EQ(the_one_frame_size, chooser.capture_size());
+
+  chooser.SetSourceSize(the_one_frame_size);
+  EXPECT_EQ(the_one_frame_size, chooser.capture_size());
+
+  chooser.SetSourceSize(gfx::Size(kMaxFrameWidth + 424, kMaxFrameHeight - 101));
+  EXPECT_EQ(the_one_frame_size, chooser.capture_size());
+
+  chooser.SetSourceSize(gfx::Size(kMaxFrameWidth - 202, kMaxFrameHeight + 56));
+  EXPECT_EQ(the_one_frame_size, chooser.capture_size());
+
+  chooser.SetSourceSize(gfx::Size(kMinFrameWidth, kMinFrameHeight));
+  EXPECT_EQ(the_one_frame_size, chooser.capture_size());
+}
+
+TEST(CaptureResolutionChooserTest,
+     FixedAspectRatioPolicy_CaptureSizeHasSameAspectRatio) {
+  CaptureResolutionChooser chooser(
+      gfx::Size(kMaxFrameWidth, kMaxFrameHeight),
+      media::RESOLUTION_POLICY_FIXED_ASPECT_RATIO);
+
+  // Starting condition.
+  const gfx::Size min_size(kMinFrameWidth, kMinFrameHeight);
+  const gfx::Size max_size(kMaxFrameWidth, kMaxFrameHeight);
+  ExpectIsWithinBoundsAndSameAspectRatio(
+      FROM_HERE, min_size, max_size, chooser.capture_size());
+
+  // Max size in --> max size out.
+  chooser.SetSourceSize(gfx::Size(kMaxFrameWidth, kMaxFrameHeight));
+  ExpectIsWithinBoundsAndSameAspectRatio(
+      FROM_HERE, min_size, max_size, chooser.capture_size());
+
+  // Various source sizes within bounds.
+  chooser.SetSourceSize(gfx::Size(640, 480));
+  ExpectIsWithinBoundsAndSameAspectRatio(
+      FROM_HERE, min_size, max_size, chooser.capture_size());
+
+  chooser.SetSourceSize(gfx::Size(480, 640));
+  ExpectIsWithinBoundsAndSameAspectRatio(
+      FROM_HERE, min_size, max_size, chooser.capture_size());
+
+  chooser.SetSourceSize(gfx::Size(640, 640));
+  ExpectIsWithinBoundsAndSameAspectRatio(
+      FROM_HERE, min_size, max_size, chooser.capture_size());
+
+  // Bad source size results in no update.
+  const gfx::Size unchanged_size = chooser.capture_size();
+  chooser.SetSourceSize(gfx::Size(0, 0));
+  EXPECT_EQ(unchanged_size, chooser.capture_size());
+
+  // Downscaling size (preserving aspect ratio) when source size exceeds the
+  // upper bounds.
+  chooser.SetSourceSize(gfx::Size(kMaxFrameWidth * 2, kMaxFrameHeight * 2));
+  ExpectIsWithinBoundsAndSameAspectRatio(
+      FROM_HERE, min_size, max_size, chooser.capture_size());
+
+  chooser.SetSourceSize(gfx::Size(kMaxFrameWidth * 2, kMaxFrameHeight));
+  ExpectIsWithinBoundsAndSameAspectRatio(
+      FROM_HERE, min_size, max_size, chooser.capture_size());
+
+  chooser.SetSourceSize(gfx::Size(kMaxFrameWidth, kMaxFrameHeight * 2));
+  ExpectIsWithinBoundsAndSameAspectRatio(
+      FROM_HERE, min_size, max_size, chooser.capture_size());
+
+  // Upscaling size (preserving aspect ratio) when source size is under the
+  // lower bounds.
+  chooser.SetSourceSize(gfx::Size(kMinFrameWidth / 2, kMinFrameHeight / 2));
+  ExpectIsWithinBoundsAndSameAspectRatio(
+      FROM_HERE, min_size, max_size, chooser.capture_size());
+
+  chooser.SetSourceSize(gfx::Size(kMinFrameWidth / 2, kMaxFrameHeight));
+  ExpectIsWithinBoundsAndSameAspectRatio(
+      FROM_HERE, min_size, max_size, chooser.capture_size());
+
+  chooser.SetSourceSize(gfx::Size(kMinFrameWidth, kMinFrameHeight / 2));
+  ExpectIsWithinBoundsAndSameAspectRatio(
+      FROM_HERE, min_size, max_size, chooser.capture_size());
+}
+
+TEST(CaptureResolutionChooserTest,
+     AnyWithinLimitPolicy_CaptureSizeIsAnythingWithinLimits) {
+  const gfx::Size max_size(kMaxFrameWidth, kMaxFrameHeight);
+  CaptureResolutionChooser chooser(
+      max_size, media::RESOLUTION_POLICY_ANY_WITHIN_LIMIT);
+
+  // Starting condition.
+  EXPECT_EQ(max_size, chooser.capture_size());
+
+  // Max size in --> max size out.
+  chooser.SetSourceSize(max_size);
+  EXPECT_EQ(max_size, chooser.capture_size());
+
+  // Various source sizes within bounds.
+  chooser.SetSourceSize(gfx::Size(640, 480));
+  EXPECT_EQ(gfx::Size(640, 480), chooser.capture_size());
+
+  chooser.SetSourceSize(gfx::Size(480, 640));
+  EXPECT_EQ(gfx::Size(480, 640), chooser.capture_size());
+
+  chooser.SetSourceSize(gfx::Size(640, 640));
+  EXPECT_EQ(gfx::Size(640, 640), chooser.capture_size());
+
+  chooser.SetSourceSize(gfx::Size(2, 2));
+  EXPECT_EQ(gfx::Size(2, 2), chooser.capture_size());
+
+  // Bad source size results in no update.
+  const gfx::Size unchanged_size = chooser.capture_size();
+  chooser.SetSourceSize(gfx::Size(0, 0));
+  EXPECT_EQ(unchanged_size, chooser.capture_size());
+
+  // Downscaling size (preserving aspect ratio) when source size exceeds the
+  // upper bounds.
+  chooser.SetSourceSize(gfx::Size(kMaxFrameWidth * 2, kMaxFrameHeight * 2));
+  EXPECT_EQ(max_size, chooser.capture_size());
+
+  chooser.SetSourceSize(gfx::Size(kMaxFrameWidth * 2, kMaxFrameHeight));
+  EXPECT_EQ(gfx::Size(kMaxFrameWidth, kMaxFrameHeight / 2),
+            chooser.capture_size());
+
+  chooser.SetSourceSize(gfx::Size(kMaxFrameWidth, kMaxFrameHeight * 2));
+  EXPECT_EQ(gfx::Size(kMaxFrameWidth / 2, kMaxFrameHeight),
+            chooser.capture_size());
+}
+
+}  // namespace content
diff --git a/content/browser/media/capture/content_video_capture_device_core.cc b/content/browser/media/capture/content_video_capture_device_core.cc
index 8d44104c..da0862c 100644
--- a/content/browser/media/capture/content_video_capture_device_core.cc
+++ b/content/browser/media/capture/content_video_capture_device_core.cc
@@ -49,7 +49,9 @@
       oracle_(base::TimeDelta::FromMicroseconds(
           static_cast<int64>(1000000.0 / params.requested_format.frame_rate +
                              0.5 /* to round to nearest int */))),
-      params_(params) {}
+      params_(params),
+      resolution_chooser_(params.requested_format.frame_size,
+                          params.resolution_change_policy) {}
 
 ThreadSafeCaptureOracle::~ThreadSafeCaptureOracle() {}
 
@@ -67,9 +69,7 @@
   if (!client_)
     return false;  // Capture is stopped.
 
-  if (capture_size_.IsEmpty())
-    capture_size_ = max_frame_size();
-  const gfx::Size visible_size = capture_size_;
+  const gfx::Size visible_size = resolution_chooser_.capture_size();
   // Always round up the coded size to multiple of 16 pixels.
   // See http://crbug.com/402151.
   const gfx::Size coded_size((visible_size.width() + 15) & ~15,
@@ -141,30 +141,15 @@
 
 gfx::Size ThreadSafeCaptureOracle::GetCaptureSize() const {
   base::AutoLock guard(lock_);
-  return capture_size_.IsEmpty() ? max_frame_size() : capture_size_;
+  return resolution_chooser_.capture_size();
 }
 
 void ThreadSafeCaptureOracle::UpdateCaptureSize(const gfx::Size& source_size) {
   base::AutoLock guard(lock_);
-
-  // Update |capture_size_| based on |source_size| if either: 1) The resolution
-  // change policy specifies fixed frame sizes and |capture_size_| has not yet
-  // been set; or 2) The resolution change policy specifies dynamic frame
-  // sizes.
-  if (capture_size_.IsEmpty() || params_.resolution_change_policy ==
-      media::RESOLUTION_POLICY_ANY_WITHIN_LIMIT) {
-    capture_size_ = source_size;
-    // The capture size should not exceed the maximum frame size.
-    if (capture_size_.width() > max_frame_size().width() ||
-        capture_size_.height() > max_frame_size().height()) {
-      capture_size_ = media::ComputeLetterboxRegion(
-          gfx::Rect(max_frame_size()), capture_size_).size();
-    }
-    // The capture size must be even and not less than the minimum frame size.
-    capture_size_ = gfx::Size(
-        std::max(kMinFrameWidth, MakeEven(capture_size_.width())),
-        std::max(kMinFrameHeight, MakeEven(capture_size_.height())));
-  }
+  resolution_chooser_.SetSourceSize(source_size);
+  VLOG(1) << "Source size changed to " << source_size.ToString()
+          << " --> Capture size is now "
+          << resolution_chooser_.capture_size().ToString();
 }
 
 void ThreadSafeCaptureOracle::Stop() {
@@ -234,23 +219,15 @@
     return;
   }
 
-   if (params.requested_format.frame_size.width() < kMinFrameWidth ||
-       params.requested_format.frame_size.height() < kMinFrameHeight) {
-     std::string error_msg =
-         "invalid frame size: " + params.requested_format.frame_size.ToString();
-     DVLOG(1) << error_msg;
-     client->OnError(error_msg);
-     return;
-   }
+  if (params.requested_format.frame_size.IsEmpty()) {
+    std::string error_msg =
+        "invalid frame size: " + params.requested_format.frame_size.ToString();
+    DVLOG(1) << error_msg;
+    client->OnError(error_msg);
+    return;
+  }
 
-  media::VideoCaptureParams new_params = params;
-  // Frame dimensions must each be an even integer since the client wants (or
-  // will convert to) YUV420.
-  new_params.requested_format.frame_size.SetSize(
-      MakeEven(params.requested_format.frame_size.width()),
-      MakeEven(params.requested_format.frame_size.height()));
-
-  oracle_proxy_ = new ThreadSafeCaptureOracle(client.Pass(), new_params);
+  oracle_proxy_ = new ThreadSafeCaptureOracle(client.Pass(), params);
 
   // Starts the capture machine asynchronously.
   BrowserThread::PostTaskAndReplyWithResult(
@@ -259,7 +236,7 @@
       base::Bind(&VideoCaptureMachine::Start,
                  base::Unretained(capture_machine_.get()),
                  oracle_proxy_,
-                 new_params),
+                 params),
       base::Bind(&ContentVideoCaptureDeviceCore::CaptureStarted, AsWeakPtr()));
 
   TransitionStateTo(kCapturing);
diff --git a/content/browser/media/capture/content_video_capture_device_core.h b/content/browser/media/capture/content_video_capture_device_core.h
index f477a15..67dffd6 100644
--- a/content/browser/media/capture/content_video_capture_device_core.h
+++ b/content/browser/media/capture/content_video_capture_device_core.h
@@ -11,6 +11,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/threading/thread.h"
 #include "base/threading/thread_checker.h"
+#include "content/browser/media/capture/capture_resolution_chooser.h"
 #include "content/browser/media/capture/video_capture_oracle.h"
 #include "content/common/content_export.h"
 #include "media/base/video_frame.h"
@@ -23,15 +24,6 @@
 
 namespace content {
 
-const int kMinFrameWidth = 2;
-const int kMinFrameHeight = 2;
-
-// Returns the nearest even integer closer to zero.
-template<typename IntType>
-IntType MakeEven(IntType x) {
-  return x & static_cast<IntType>(-2);
-}
-
 class VideoCaptureMachine;
 
 // Thread-safe, refcounted proxy to the VideoCaptureOracle.  This proxy wraps
@@ -104,8 +96,8 @@
   // The video capture parameters used to construct the oracle proxy.
   const media::VideoCaptureParams params_;
 
-  // The current video capture size.
-  gfx::Size capture_size_;
+  // Determines video capture frame sizes.
+  CaptureResolutionChooser resolution_chooser_;
 };
 
 // Keeps track of the video capture source frames and executes copying on the
diff --git a/content/browser/media/capture/desktop_capture_device.cc b/content/browser/media/capture/desktop_capture_device.cc
index a11e473..e42a678 100644
--- a/content/browser/media/capture/desktop_capture_device.cc
+++ b/content/browser/media/capture/desktop_capture_device.cc
@@ -12,6 +12,7 @@
 #include "base/synchronization/lock.h"
 #include "base/threading/thread.h"
 #include "base/timer/timer.h"
+#include "content/browser/media/capture/capture_resolution_chooser.h"
 #include "content/browser/media/capture/desktop_capture_device_uma_types.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/desktop_media_id.h"
@@ -72,11 +73,6 @@
   webrtc::SharedMemory* CreateSharedMemory(size_t size) override;
   void OnCaptureCompleted(webrtc::DesktopFrame* frame) override;
 
-  // Chooses new output properties based on the supplied source size and the
-  // properties requested to Allocate(), and dispatches OnFrameInfo[Changed]
-  // notifications.
-  void RefreshCaptureFormat(const webrtc::DesktopSize& frame_size);
-
   // Method that is scheduled on |task_runner_| to be called on regular interval
   // to capture a frame.
   void OnCaptureTimer();
@@ -97,24 +93,20 @@
   // on the task_runner_ thread.
   scoped_ptr<Client> client_;
 
-  // Requested video capture format (width, height, frame rate, etc).
-  media::VideoCaptureParams requested_params_;
-
-  // Actual video capture format being generated.
-  media::VideoCaptureFormat capture_format_;
+  // Requested video capture frame rate.
+  float requested_frame_rate_;
 
   // Size of frame most recently captured from the source.
   webrtc::DesktopSize previous_frame_size_;
 
+  // Determines the size of frames to deliver to the |client_|.
+  scoped_ptr<CaptureResolutionChooser> resolution_chooser_;
+
   // DesktopFrame into which captured frames are down-scaled and/or letterboxed,
   // depending upon the caller's requested capture capabilities. If frames can
   // be returned to the caller directly then this is NULL.
   scoped_ptr<webrtc::DesktopFrame> output_frame_;
 
-  // Sub-rectangle of |output_frame_| into which the source will be scaled
-  // and/or letterboxed.
-  webrtc::DesktopRect output_rect_;
-
   // Timer used to capture the frame.
   base::OneShotTimer<Core> capture_timer_;
 
@@ -167,12 +159,10 @@
   DCHECK(!client_.get());
 
   client_ = client.Pass();
-  requested_params_ = params;
-
-  capture_format_ = requested_params_.requested_format;
-
-  // This capturer always outputs ARGB, non-interlaced.
-  capture_format_.pixel_format = media::PIXEL_FORMAT_ARGB;
+  requested_frame_rate_ = params.requested_format.frame_rate;
+  resolution_chooser_.reset(new CaptureResolutionChooser(
+      params.requested_format.frame_size,
+      params.resolution_change_policy));
 
   power_save_blocker_.reset(
       PowerSaveBlocker::Create(
@@ -238,16 +228,29 @@
 
   scoped_ptr<webrtc::DesktopFrame> owned_frame(frame);
 
+  // If the frame size has changed, drop the output frame (if any), and
+  // determine the new output size.
+  if (!previous_frame_size_.equals(frame->size())) {
+    output_frame_.reset();
+    resolution_chooser_->SetSourceSize(gfx::Size(frame->size().width(),
+                                                 frame->size().height()));
+    previous_frame_size_ = frame->size();
+  }
+  // Align to 2x2 pixel boundaries, as required by OnIncomingCapturedData() so
+  // it can convert the frame to I420 format.
+  const webrtc::DesktopSize output_size(
+      resolution_chooser_->capture_size().width() & ~1,
+      resolution_chooser_->capture_size().height() & ~1);
+  if (output_size.is_empty())
+    return;
+
   // On OSX We receive a 1x1 frame when the shared window is minimized. It
   // cannot be subsampled to I420 and will be dropped downstream. So we replace
   // it with a black frame to avoid the video appearing frozen at the last
   // frame.
   if (frame->size().width() == 1 || frame->size().height() == 1) {
     if (!black_frame_.get()) {
-      black_frame_.reset(
-          new webrtc::BasicDesktopFrame(
-              webrtc::DesktopSize(capture_format_.frame_size.width(),
-                                  capture_format_.frame_size.height())));
+      black_frame_.reset(new webrtc::BasicDesktopFrame(output_size));
       memset(black_frame_->data(),
              0,
              black_frame_->stride() * black_frame_->size().height());
@@ -256,11 +259,6 @@
     frame = black_frame_.get();
   }
 
-  // Handle initial frame size and size changes.
-  RefreshCaptureFormat(frame->size());
-
-  webrtc::DesktopSize output_size(capture_format_.frame_size.width(),
-                                  capture_format_.frame_size.height());
   size_t output_bytes = output_size.width() * output_size.height() *
       webrtc::DesktopFrame::kBytesPerPixel;
   const uint8_t* output_data = NULL;
@@ -270,7 +268,7 @@
     // match the output size.
 
     // Allocate a buffer of the correct size to scale the frame into.
-    // |output_frame_| is cleared whenever |output_rect_| changes, so we don't
+    // |output_frame_| is cleared whenever the output size changes, so we don't
     // need to worry about clearing out stale pixel data in letterboxed areas.
     if (!output_frame_) {
       output_frame_.reset(new webrtc::BasicDesktopFrame(output_size));
@@ -280,13 +278,15 @@
 
     // TODO(wez): Optimize this to scale only changed portions of the output,
     // using ARGBScaleClip().
+    const webrtc::DesktopRect output_rect =
+        ComputeLetterboxRect(output_size, frame->size());
     uint8_t* output_rect_data = output_frame_->data() +
-        output_frame_->stride() * output_rect_.top() +
-        webrtc::DesktopFrame::kBytesPerPixel * output_rect_.left();
+        output_frame_->stride() * output_rect.top() +
+        webrtc::DesktopFrame::kBytesPerPixel * output_rect.left();
     libyuv::ARGBScale(frame->data(), frame->stride(),
                       frame->size().width(), frame->size().height(),
                       output_rect_data, output_frame_->stride(),
-                      output_rect_.width(), output_rect_.height(),
+                      output_rect.width(), output_rect.height(),
                       libyuv::kFilterBilinear);
     output_data = output_frame_->data();
   } else if (IsFrameUnpackedOrInverted(frame)) {
@@ -311,49 +311,14 @@
   }
 
   client_->OnIncomingCapturedData(
-      output_data, output_bytes, capture_format_, 0, base::TimeTicks::Now());
-}
-
-void DesktopCaptureDevice::Core::RefreshCaptureFormat(
-    const webrtc::DesktopSize& frame_size) {
-  if (previous_frame_size_.equals(frame_size))
-    return;
-
-  // Clear the output frame, if any, since it will either need resizing, or
-  // clearing of stale data in letterbox areas, anyway.
-  output_frame_.reset();
-
-  if (previous_frame_size_.is_empty() ||
-      requested_params_.resolution_change_policy ==
-      media::RESOLUTION_POLICY_ANY_WITHIN_LIMIT) {
-    // If this is the first frame, or the receiver supports variable resolution
-    // then determine the output size by treating the requested width & height
-    // as maxima.
-    if (frame_size.width() >
-            requested_params_.requested_format.frame_size.width() ||
-        frame_size.height() >
-            requested_params_.requested_format.frame_size.height()) {
-      output_rect_ = ComputeLetterboxRect(
-          webrtc::DesktopSize(
-              requested_params_.requested_format.frame_size.width(),
-              requested_params_.requested_format.frame_size.height()),
-          frame_size);
-      output_rect_.Translate(-output_rect_.left(), -output_rect_.top());
-    } else {
-      output_rect_ = webrtc::DesktopRect::MakeSize(frame_size);
-    }
-    capture_format_.frame_size.SetSize(output_rect_.width(),
-                                       output_rect_.height());
-  } else {
-    // Otherwise the output frame size cannot change, so just scale and
-    // letterbox.
-    output_rect_ = ComputeLetterboxRect(
-        webrtc::DesktopSize(capture_format_.frame_size.width(),
-                            capture_format_.frame_size.height()),
-        frame_size);
-  }
-
-  previous_frame_size_ = frame_size;
+      output_data,
+      output_bytes,
+      media::VideoCaptureFormat(gfx::Size(output_size.width(),
+                                          output_size.height()),
+                                requested_frame_rate_,
+                                media::PIXEL_FORMAT_ARGB),
+      0,
+      base::TimeTicks::Now());
 }
 
 void DesktopCaptureDevice::Core::OnCaptureTimer() {
@@ -375,7 +340,8 @@
   // Limit frame-rate to reduce CPU consumption.
   base::TimeDelta capture_period = std::max(
     (last_capture_duration * 100) / kMaximumCpuConsumptionPercentage,
-    base::TimeDelta::FromSeconds(1) / capture_format_.frame_rate);
+    base::TimeDelta::FromMicroseconds(static_cast<int64>(
+        1000000.0 / requested_frame_rate_ + 0.5 /* round to nearest int */)));
 
   // Schedule a task for the next frame.
   capture_timer_.Start(FROM_HERE, capture_period - last_capture_duration,
diff --git a/content/browser/media/capture/desktop_capture_device_unittest.cc b/content/browser/media/capture/desktop_capture_device_unittest.cc
index c86ddd38..56e06ff66 100644
--- a/content/browser/media/capture/desktop_capture_device_unittest.cc
+++ b/content/browser/media/capture/desktop_capture_device_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "content/browser/media/capture/desktop_capture_device.h"
 
+#include <algorithm>
 #include <string>
 
 #include "base/basictypes.h"
@@ -22,8 +23,10 @@
 using ::testing::AnyNumber;
 using ::testing::DoAll;
 using ::testing::Expectation;
+using ::testing::Invoke;
 using ::testing::InvokeWithoutArgs;
 using ::testing::SaveArg;
+using ::testing::WithArg;
 
 namespace content {
 
@@ -33,10 +36,10 @@
   return arg.width == width && arg.height == height;
 }
 
-const int kTestFrameWidth1 = 100;
-const int kTestFrameHeight1 = 100;
-const int kTestFrameWidth2 = 200;
-const int kTestFrameHeight2 = 150;
+const int kTestFrameWidth1 = 500;
+const int kTestFrameHeight1 = 500;
+const int kTestFrameWidth2 = 400;
+const int kTestFrameHeight2 = 300;
 
 const int kFrameRate = 30;
 
@@ -208,6 +211,32 @@
   bool generate_cropped_frames_;
 };
 
+// Helper used to check that only two specific frame sizes are delivered to the
+// OnIncomingCapturedData() callback.
+class FormatChecker {
+ public:
+  FormatChecker(const gfx::Size& size_for_even_frames,
+                const gfx::Size& size_for_odd_frames)
+      : size_for_even_frames_(size_for_even_frames),
+        size_for_odd_frames_(size_for_odd_frames),
+        frame_count_(0) {}
+
+  void ExpectAcceptableSize(const media::VideoCaptureFormat& format) {
+    if (frame_count_ % 2 == 0)
+      EXPECT_EQ(size_for_even_frames_, format.frame_size);
+    else
+      EXPECT_EQ(size_for_odd_frames_, format.frame_size);
+    ++frame_count_;
+    EXPECT_EQ(kFrameRate, format.frame_rate);
+    EXPECT_EQ(media::PIXEL_FORMAT_ARGB, format.pixel_format);
+  }
+
+ private:
+  const gfx::Size size_for_even_frames_;
+  const gfx::Size size_for_odd_frames_;
+  int frame_count_;
+};
+
 }  // namespace
 
 class DesktopCaptureDeviceTest : public testing::Test {
@@ -277,15 +306,15 @@
 
   CreateScreenCaptureDevice(scoped_ptr<webrtc::DesktopCapturer>(mock_capturer));
 
-  media::VideoCaptureFormat format;
+  FormatChecker format_checker(gfx::Size(kTestFrameWidth1, kTestFrameHeight1),
+                               gfx::Size(kTestFrameWidth1, kTestFrameHeight1));
   base::WaitableEvent done_event(false, false);
-  int frame_size;
 
   scoped_ptr<MockDeviceClient> client(new MockDeviceClient());
   EXPECT_CALL(*client, OnError(_)).Times(0);
   EXPECT_CALL(*client, OnIncomingCapturedData(_, _, _, _, _)).WillRepeatedly(
-      DoAll(SaveArg<1>(&frame_size),
-            SaveArg<2>(&format),
+      DoAll(WithArg<2>(Invoke(&format_checker,
+                              &FormatChecker::ExpectAcceptableSize)),
             InvokeWithoutArgs(&done_event, &base::WaitableEvent::Signal)));
 
   media::VideoCaptureParams capture_params;
@@ -293,23 +322,66 @@
                                                      kTestFrameHeight1);
   capture_params.requested_format.frame_rate = kFrameRate;
   capture_params.requested_format.pixel_format = media::PIXEL_FORMAT_I420;
+  capture_params.resolution_change_policy =
+      media::RESOLUTION_POLICY_FIXED_RESOLUTION;
 
   capture_device_->AllocateAndStart(capture_params, client.Pass());
 
   // Capture at least two frames, to ensure that the source frame size has
-  // changed while capturing.
-  EXPECT_TRUE(done_event.TimedWait(TestTimeouts::action_max_timeout()));
-  done_event.Reset();
-  EXPECT_TRUE(done_event.TimedWait(TestTimeouts::action_max_timeout()));
+  // changed to two different sizes while capturing.  The mock for
+  // OnIncomingCapturedData() will use FormatChecker to examine the format of
+  // each frame being delivered.
+  for (int i = 0; i < 2; ++i) {
+    EXPECT_TRUE(done_event.TimedWait(TestTimeouts::action_max_timeout()));
+    done_event.Reset();
+  }
 
   capture_device_->StopAndDeAllocate();
+}
 
-  EXPECT_EQ(kTestFrameWidth1, format.frame_size.width());
-  EXPECT_EQ(kTestFrameHeight1, format.frame_size.height());
-  EXPECT_EQ(kFrameRate, format.frame_rate);
-  EXPECT_EQ(media::PIXEL_FORMAT_ARGB, format.pixel_format);
+// Test that screen capturer behaves correctly if the source frame size changes,
+// where the video frames sent the the client vary in resolution but maintain
+// the same aspect ratio.
+TEST_F(DesktopCaptureDeviceTest, ScreenResolutionChangeFixedAspectRatio) {
+  FakeScreenCapturer* mock_capturer = new FakeScreenCapturer();
 
-  EXPECT_EQ(format.frame_size.GetArea() * 4, frame_size);
+  CreateScreenCaptureDevice(scoped_ptr<webrtc::DesktopCapturer>(mock_capturer));
+
+  FormatChecker format_checker(gfx::Size(888, 500), gfx::Size(532, 300));
+  base::WaitableEvent done_event(false, false);
+
+  scoped_ptr<MockDeviceClient> client(new MockDeviceClient());
+  EXPECT_CALL(*client, OnError(_)).Times(0);
+  EXPECT_CALL(*client, OnIncomingCapturedData(_, _, _, _, _)).WillRepeatedly(
+      DoAll(WithArg<2>(Invoke(&format_checker,
+                              &FormatChecker::ExpectAcceptableSize)),
+            InvokeWithoutArgs(&done_event, &base::WaitableEvent::Signal)));
+
+  media::VideoCaptureParams capture_params;
+  const gfx::Size high_def_16_by_9(1920, 1080);
+  ASSERT_GE(high_def_16_by_9.width(),
+            std::max(kTestFrameWidth1, kTestFrameWidth2));
+  ASSERT_GE(high_def_16_by_9.height(),
+            std::max(kTestFrameHeight1, kTestFrameHeight2));
+  capture_params.requested_format.frame_size = high_def_16_by_9;
+  capture_params.requested_format.frame_rate = kFrameRate;
+  capture_params.requested_format.pixel_format = media::PIXEL_FORMAT_I420;
+  capture_params.resolution_change_policy =
+      media::RESOLUTION_POLICY_FIXED_ASPECT_RATIO;
+
+  capture_device_->AllocateAndStart(
+      capture_params, client.Pass());
+
+  // Capture at least three frames, to ensure that the source frame size has
+  // changed to two different sizes while capturing.  The mock for
+  // OnIncomingCapturedData() will use FormatChecker to examine the format of
+  // each frame being delivered.
+  for (int i = 0; i < 3; ++i) {
+    EXPECT_TRUE(done_event.TimedWait(TestTimeouts::action_max_timeout()));
+    done_event.Reset();
+  }
+
+  capture_device_->StopAndDeAllocate();
 }
 
 // Test that screen capturer behaves correctly if the source frame size changes
@@ -319,38 +391,42 @@
 
   CreateScreenCaptureDevice(scoped_ptr<webrtc::DesktopCapturer>(mock_capturer));
 
-  media::VideoCaptureFormat format;
+  FormatChecker format_checker(gfx::Size(kTestFrameWidth1, kTestFrameHeight1),
+                               gfx::Size(kTestFrameWidth2, kTestFrameHeight2));
   base::WaitableEvent done_event(false, false);
 
   scoped_ptr<MockDeviceClient> client(new MockDeviceClient());
   EXPECT_CALL(*client, OnError(_)).Times(0);
   EXPECT_CALL(*client, OnIncomingCapturedData(_, _, _, _, _)).WillRepeatedly(
-      DoAll(SaveArg<2>(&format),
+      DoAll(WithArg<2>(Invoke(&format_checker,
+                              &FormatChecker::ExpectAcceptableSize)),
             InvokeWithoutArgs(&done_event, &base::WaitableEvent::Signal)));
 
   media::VideoCaptureParams capture_params;
-  capture_params.requested_format.frame_size.SetSize(kTestFrameWidth2,
-                                                     kTestFrameHeight2);
+  const gfx::Size high_def_16_by_9(1920, 1080);
+  ASSERT_GE(high_def_16_by_9.width(),
+            std::max(kTestFrameWidth1, kTestFrameWidth2));
+  ASSERT_GE(high_def_16_by_9.height(),
+            std::max(kTestFrameHeight1, kTestFrameHeight2));
+  capture_params.requested_format.frame_size = high_def_16_by_9;
   capture_params.requested_format.frame_rate = kFrameRate;
   capture_params.requested_format.pixel_format = media::PIXEL_FORMAT_I420;
+  capture_params.resolution_change_policy =
+      media::RESOLUTION_POLICY_ANY_WITHIN_LIMIT;
 
   capture_device_->AllocateAndStart(
       capture_params, client.Pass());
 
   // Capture at least three frames, to ensure that the source frame size has
-  // changed at least twice while capturing.
-  EXPECT_TRUE(done_event.TimedWait(TestTimeouts::action_max_timeout()));
-  done_event.Reset();
-  EXPECT_TRUE(done_event.TimedWait(TestTimeouts::action_max_timeout()));
-  done_event.Reset();
-  EXPECT_TRUE(done_event.TimedWait(TestTimeouts::action_max_timeout()));
+  // changed to two different sizes while capturing.  The mock for
+  // OnIncomingCapturedData() will use FormatChecker to examine the format of
+  // each frame being delivered.
+  for (int i = 0; i < 3; ++i) {
+    EXPECT_TRUE(done_event.TimedWait(TestTimeouts::action_max_timeout()));
+    done_event.Reset();
+  }
 
   capture_device_->StopAndDeAllocate();
-
-  EXPECT_EQ(kTestFrameWidth1, format.frame_size.width());
-  EXPECT_EQ(kTestFrameHeight1, format.frame_size.height());
-  EXPECT_EQ(kFrameRate, format.frame_rate);
-  EXPECT_EQ(media::PIXEL_FORMAT_ARGB, format.pixel_format);
 }
 
 // This test verifies that an unpacked frame is converted to a packed frame.
diff --git a/content/browser/media/capture/web_contents_audio_input_stream.cc b/content/browser/media/capture/web_contents_audio_input_stream.cc
index 629d106..8fd1f97 100644
--- a/content/browser/media/capture/web_contents_audio_input_stream.cc
+++ b/content/browser/media/capture/web_contents_audio_input_stream.cc
@@ -91,7 +91,7 @@
 
   // Called by WebContentsTracker when the target of the audio mirroring has
   // changed.
-  void OnTargetChanged(RenderWidgetHost* target);
+  void OnTargetChanged(bool had_target);
 
   // Injected dependencies.
   const int initial_render_process_id_;
@@ -305,11 +305,10 @@
   delete stream;
 }
 
-void WebContentsAudioInputStream::Impl::OnTargetChanged(
-    RenderWidgetHost* target) {
+void WebContentsAudioInputStream::Impl::OnTargetChanged(bool had_target) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
-  is_target_lost_ = !target;
+  is_target_lost_ = !had_target;
 
   if (state_ == MIRRORING) {
     if (is_target_lost_) {
diff --git a/content/browser/media/capture/web_contents_audio_input_stream_unittest.cc b/content/browser/media/capture/web_contents_audio_input_stream_unittest.cc
index ffe8b4b5..0eebd7a8 100644
--- a/content/browser/media/capture/web_contents_audio_input_stream_unittest.cc
+++ b/content/browser/media/capture/web_contents_audio_input_stream_unittest.cc
@@ -356,13 +356,7 @@
  private:
   void SimulateChangeCallback(int render_process_id, int render_frame_id) {
     ASSERT_FALSE(change_callback_.is_null());
-    if (render_process_id == -1 || render_frame_id == -1) {
-      change_callback_.Run(NULL);
-    } else {
-      // For our tests, any non-NULL value will suffice since it will not be
-      // dereferenced.
-      change_callback_.Run(reinterpret_cast<RenderWidgetHost*>(0xdeadbee5));
-    }
+    change_callback_.Run(render_process_id != -1 && render_frame_id != -1);
   }
 
   scoped_ptr<TestBrowserThreadBundle> thread_bundle_;
diff --git a/content/browser/media/capture/web_contents_tracker.cc b/content/browser/media/capture/web_contents_tracker.cc
index a9e161f..5007a583 100644
--- a/content/browser/media/capture/web_contents_tracker.cc
+++ b/content/browser/media/capture/web_contents_tracker.cc
@@ -44,6 +44,7 @@
   DCHECK(task_runner_->BelongsToCurrentThread());
 
   callback_.Reset();
+  resize_callback_.Reset();
 
   if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
     WebContentsObserver::Observe(NULL);
@@ -78,6 +79,12 @@
   return rwh;
 }
 
+void WebContentsTracker::SetResizeChangeCallback(
+    const base::Closure& callback) {
+  DCHECK(!task_runner_.get() || task_runner_->BelongsToCurrentThread());
+  resize_callback_ = callback;
+}
+
 void WebContentsTracker::OnPossibleTargetChange(bool force_callback_run) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
@@ -89,19 +96,29 @@
   last_target_ = rwh;
 
   if (task_runner_->BelongsToCurrentThread()) {
-    MaybeDoCallback(rwh);
-  } else {
-    task_runner_->PostTask(
-        FROM_HERE,
-        base::Bind(&WebContentsTracker::MaybeDoCallback, this, rwh));
+    MaybeDoCallback(rwh != nullptr);
+    return;
   }
+
+  task_runner_->PostTask(
+      FROM_HERE,
+      base::Bind(&WebContentsTracker::MaybeDoCallback, this, rwh != nullptr));
 }
 
-void WebContentsTracker::MaybeDoCallback(RenderWidgetHost* rwh) {
+void WebContentsTracker::MaybeDoCallback(bool was_still_tracking) {
   DCHECK(task_runner_->BelongsToCurrentThread());
 
   if (!callback_.is_null())
-    callback_.Run(rwh);
+    callback_.Run(was_still_tracking);
+  if (was_still_tracking)
+    MaybeDoResizeCallback();
+}
+
+void WebContentsTracker::MaybeDoResizeCallback() {
+  DCHECK(task_runner_->BelongsToCurrentThread());
+
+  if (!resize_callback_.is_null())
+    resize_callback_.Run();
 }
 
 void WebContentsTracker::StartObservingWebContents(int render_process_id,
@@ -128,6 +145,19 @@
   OnPossibleTargetChange(false);
 }
 
+void WebContentsTracker::MainFrameWasResized(bool width_changed) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+  if (task_runner_->BelongsToCurrentThread()) {
+    MaybeDoResizeCallback();
+    return;
+  }
+
+  task_runner_->PostTask(
+      FROM_HERE,
+      base::Bind(&WebContentsTracker::MaybeDoResizeCallback, this));
+}
+
 void WebContentsTracker::WebContentsDestroyed() {
   Observe(NULL);
   OnPossibleTargetChange(false);
diff --git a/content/browser/media/capture/web_contents_tracker.h b/content/browser/media/capture/web_contents_tracker.h
index 613c971..591c5e3 100644
--- a/content/browser/media/capture/web_contents_tracker.h
+++ b/content/browser/media/capture/web_contents_tracker.h
@@ -40,15 +40,15 @@
   explicit WebContentsTracker(bool track_fullscreen_rwh);
 
   // Callback to indicate a new RenderWidgetHost should be targeted for capture.
-  // This is also invoked with NULL to indicate tracking will not continue
+  // This is also invoked with false to indicate tracking will not continue
   // (i.e., the WebContents instance was not found or has been destroyed).
-  typedef base::Callback<void(RenderWidgetHost* rwh)> ChangeCallback;
+  typedef base::Callback<void(bool was_still_tracking)> ChangeCallback;
 
   // Start tracking.  The last-known |render_process_id| and
   // |main_render_frame_id| are provided, and |callback| will be run once to
-  // indicate the current capture target (this may occur during the invocation
-  // of Start(), or in the future).  The callback will be invoked on the same
-  // thread calling Start().
+  // indicate whether tracking successfully started (this may occur during the
+  // invocation of Start(), or in the future).  The callback will be invoked on
+  // the same thread calling Start().
   virtual void Start(int render_process_id, int main_render_frame_id,
                      const ChangeCallback& callback);
 
@@ -59,6 +59,12 @@
   // Current target.  This must only be called on the UI BrowserThread.
   RenderWidgetHost* GetTargetRenderWidgetHost() const;
 
+  // Set a callback that is run whenever the main frame of the WebContents is
+  // resized.  This method must be called on the same thread that calls
+  // Start()/Stop(), and |callback| will be run on that same thread.  Calling
+  // the Stop() method guarantees the callback will never be invoked again.
+  void SetResizeChangeCallback(const base::Closure& callback);
+
  protected:
   friend class base::RefCountedThreadSafe<WebContentsTracker>;
   ~WebContentsTracker() override;
@@ -72,7 +78,12 @@
 
   // Called on the thread that Start()/Stop() are called on.  Checks whether the
   // callback is still valid and, if so, runs it.
-  void MaybeDoCallback(RenderWidgetHost* rwh);
+  void MaybeDoCallback(bool was_still_tracking);
+
+  // Called on the thread that Start()/Stop() are called on.  Checks whether the
+  // callback is still valid and, if so, runs it to indicate the main frame has
+  // changed in size.
+  void MaybeDoResizeCallback();
 
   // Look-up the current WebContents instance associated with the given
   // |render_process_id| and |main_render_frame_id| and begin observing it.
@@ -86,6 +97,10 @@
   void RenderFrameHostChanged(RenderFrameHost* old_host,
                               RenderFrameHost* new_host) override;
 
+  // WebContentsObserver override to notify the client that the source size has
+  // changed.
+  void MainFrameWasResized(bool width_changed) override;
+
   // WebContentsObserver override to notify the client that the capture target
   // has been permanently lost.
   void WebContentsDestroyed() override;
@@ -109,6 +124,9 @@
   // This is used to eliminate duplicate callback runs.
   RenderWidgetHost* last_target_;
 
+  // Callback to run when the target RenderWidgetHost has resized.
+  base::Closure resize_callback_;
+
   DISALLOW_COPY_AND_ASSIGN(WebContentsTracker);
 };
 
diff --git a/content/browser/media/capture/web_contents_video_capture_device.cc b/content/browser/media/capture/web_contents_video_capture_device.cc
index 8380682f..292d856 100644
--- a/content/browser/media/capture/web_contents_video_capture_device.cc
+++ b/content/browser/media/capture/web_contents_video_capture_device.cc
@@ -79,7 +79,6 @@
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/gfx/display.h"
-#include "ui/gfx/geometry/size.h"
 #include "ui/gfx/geometry/size_conversions.h"
 #include "ui/gfx/screen.h"
 
@@ -87,20 +86,6 @@
 
 namespace {
 
-// Compute a letterbox region, aligned to even coordinates.
-gfx::Rect ComputeYV12LetterboxRegion(const gfx::Rect& visible_rect,
-                                     const gfx::Size& content_size) {
-
-  gfx::Rect result = media::ComputeLetterboxRegion(visible_rect, content_size);
-
-  result.set_x(MakeEven(result.x()));
-  result.set_y(MakeEven(result.y()));
-  result.set_width(std::max(kMinFrameWidth, MakeEven(result.width())));
-  result.set_height(std::max(kMinFrameHeight, MakeEven(result.height())));
-
-  return result;
-}
-
 void DeleteOnWorkerThread(scoped_ptr<base::Thread> render_thread,
                           const base::Closure& callback) {
   render_thread.reset();
@@ -254,8 +239,12 @@
           deliver_frame_cb,
       bool success);
 
-  // Remove the old subscription, and start a new one if |rwh| is not NULL.
-  void RenewFrameSubscription(RenderWidgetHost* rwh);
+  // Remove the old subscription, and attempt to start a new one if |had_target|
+  // is true.
+  void RenewFrameSubscription(bool had_target);
+
+  // Called whenever the render widget is resized.
+  void UpdateCaptureSize();
 
   // Parameters saved in constructor.
   const int initial_render_process_id_;
@@ -396,7 +385,7 @@
 
   // Calculate the width and height of the content region in the |output|, based
   // on the aspect ratio of |input|.
-  gfx::Rect region_in_frame = ComputeYV12LetterboxRegion(
+  const gfx::Rect region_in_frame = media::ComputeLetterboxRegion(
       output->visible_rect(), gfx::Size(input.width(), input.height()));
 
   // Scale the bitmap to the required size, if necessary.
@@ -425,12 +414,20 @@
 
   TRACE_EVENT_ASYNC_STEP_INTO0("gpu.capture", "Capture", output.get(), "YUV");
   {
-    SkAutoLockPixels scaled_bitmap_locker(scaled_bitmap);
+    // Align to 2x2 pixel boundaries, as required by
+    // media::CopyRGBToVideoFrame().
+    const gfx::Rect region_in_yv12_frame(region_in_frame.x() & ~1,
+                                         region_in_frame.y() & ~1,
+                                         region_in_frame.width() & ~1,
+                                         region_in_frame.height() & ~1);
+    if (region_in_yv12_frame.IsEmpty())
+      return;
 
+    SkAutoLockPixels scaled_bitmap_locker(scaled_bitmap);
     media::CopyRGBToVideoFrame(
         reinterpret_cast<uint8*>(scaled_bitmap.getPixels()),
         scaled_bitmap.rowBytes(),
-        region_in_frame,
+        region_in_yv12_frame,
         output.get());
   }
 
@@ -501,6 +498,9 @@
 
   // Note: Creation of the first WeakPtr in the following statement will cause
   // IsStarted() to return true from now on.
+  tracker_->SetResizeChangeCallback(
+      base::Bind(&WebContentsCaptureMachine::UpdateCaptureSize,
+                 weak_ptr_factory_.GetWeakPtr()));
   tracker_->Start(initial_render_process_id_, initial_main_render_frame_id_,
                   base::Bind(&WebContentsCaptureMachine::RenewFrameSubscription,
                              weak_ptr_factory_.GetWeakPtr()));
@@ -522,7 +522,7 @@
 
   // Note: RenewFrameSubscription() must be called before stopping |tracker_| so
   // the web_contents() can be notified that the capturing is ending.
-  RenewFrameSubscription(NULL);
+  RenewFrameSubscription(false);
   tracker_->Stop();
 
   // The render thread cannot be stopped on the UI thread, so post a message
@@ -551,11 +551,6 @@
   }
 
   gfx::Size view_size = view->GetViewBounds().size();
-  gfx::Size fitted_size;
-  if (!view_size.IsEmpty()) {
-    fitted_size = ComputeYV12LetterboxRegion(target->visible_rect(),
-                                             view_size).size();
-  }
   if (view_size != last_view_size_) {
     last_view_size_ = view_size;
 
@@ -574,6 +569,8 @@
                    weak_ptr_factory_.GetWeakPtr(),
                    start_time, deliver_frame_cb));
   } else {
+    const gfx::Size fitted_size = view_size.IsEmpty() ? gfx::Size() :
+        media::ComputeLetterboxRegion(target->visible_rect(), view_size).size();
     rwh->CopyFromBackingStore(
         gfx::Rect(),
         fitted_size,  // Size here is a request not always honored.
@@ -589,7 +586,10 @@
 gfx::Size WebContentsCaptureMachine::ComputeOptimalTargetSize() const {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
-  gfx::Size optimal_size = oracle_proxy_->GetCaptureSize();
+  // TODO(miu): Propagate capture frame size changes as new "preferred size"
+  // updates, rather than just using the max frame size.
+  // http://crbug.com/350491
+  gfx::Size optimal_size = oracle_proxy_->max_frame_size();
 
   // If the ratio between physical and logical pixels is greater than 1:1,
   // shrink |optimal_size| by that amount.  Then, when external code resizes the
@@ -657,9 +657,12 @@
   deliver_frame_cb.Run(start_time, success);
 }
 
-void WebContentsCaptureMachine::RenewFrameSubscription(RenderWidgetHost* rwh) {
+void WebContentsCaptureMachine::RenewFrameSubscription(bool had_target) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
+  RenderWidgetHost* const rwh =
+      had_target ? tracker_->GetTargetRenderWidgetHost() : nullptr;
+
   // Always destroy the old subscription before creating a new one.
   const bool had_subscription = !!subscription_;
   subscription_.reset();
@@ -688,6 +691,18 @@
                  weak_ptr_factory_.GetWeakPtr())));
 }
 
+void WebContentsCaptureMachine::UpdateCaptureSize() {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+  if (!oracle_proxy_)
+    return;
+  RenderWidgetHost* const rwh = tracker_->GetTargetRenderWidgetHost();
+  RenderWidgetHostView* const view = rwh ? rwh->GetView() : nullptr;
+  if (!view)
+    return;
+  oracle_proxy_->UpdateCaptureSize(view->GetViewBounds().size());
+}
+
 }  // namespace
 
 WebContentsVideoCaptureDevice::WebContentsVideoCaptureDevice(
diff --git a/content/browser/media/capture/web_contents_video_capture_device_unittest.cc b/content/browser/media/capture/web_contents_video_capture_device_unittest.cc
index ab430a7..02b297f3 100644
--- a/content/browser/media/capture/web_contents_video_capture_device_unittest.cc
+++ b/content/browser/media/capture/web_contents_video_capture_device_unittest.cc
@@ -11,11 +11,13 @@
 #include "base/time/time.h"
 #include "base/timer/timer.h"
 #include "content/browser/browser_thread_impl.h"
+#include "content/browser/frame_host/render_frame_host_impl.h"
 #include "content/browser/media/capture/video_capture_oracle.h"
 #include "content/browser/media/capture/web_contents_capture_util.h"
 #include "content/browser/renderer_host/media/video_capture_buffer_pool.h"
 #include "content/browser/renderer_host/render_view_host_factory.h"
 #include "content/browser/renderer_host/render_widget_host_impl.h"
+#include "content/browser/web_contents/web_contents_impl.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/notification_types.h"
 #include "content/public/browser/render_widget_host_view_frame_subscriber.h"
@@ -77,7 +79,6 @@
 // counted.
 class CaptureTestSourceController {
  public:
-
   CaptureTestSourceController()
       : color_(SK_ColorMAGENTA),
         copy_result_size_(kTestWidth, kTestHeight),
@@ -162,13 +163,22 @@
   explicit CaptureTestView(RenderWidgetHostImpl* rwh,
                            CaptureTestSourceController* controller)
       : TestRenderWidgetHostView(rwh),
-        controller_(controller) {}
+        controller_(controller),
+        fake_bounds_(100, 100, 100 + kTestWidth, 100 + kTestHeight) {}
 
   ~CaptureTestView() override {}
 
   // TestRenderWidgetHostView overrides.
   gfx::Rect GetViewBounds() const override {
-    return gfx::Rect(100, 100, 100 + kTestWidth, 100 + kTestHeight);
+    return fake_bounds_;
+  }
+
+  void SetSize(const gfx::Size& size) override {
+    SetBounds(gfx::Rect(fake_bounds_.origin(), size));
+  }
+
+  void SetBounds(const gfx::Rect& rect) override {
+    fake_bounds_ = rect;
   }
 
   bool CanCopyToVideoFrame() const override {
@@ -213,6 +223,7 @@
  private:
   scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber_;
   CaptureTestSourceController* const controller_;
+  gfx::Rect fake_bounds_;
 
   DISALLOW_IMPLICIT_CONSTRUCTORS(CaptureTestView);
 };
@@ -308,9 +319,10 @@
 // WebContentsVideoCaptureDevice.
 class StubClient : public media::VideoCaptureDevice::Client {
  public:
-  StubClient(const base::Callback<void(SkColor)>& color_callback,
-             const base::Closure& error_callback)
-      : color_callback_(color_callback),
+  StubClient(
+      const base::Callback<void(SkColor, const gfx::Size&)>& report_callback,
+      const base::Closure& error_callback)
+      : report_callback_(report_callback),
         error_callback_(error_callback) {
     buffer_pool_ = new VideoCaptureBufferPool(2);
   }
@@ -360,20 +372,29 @@
       scoped_ptr<Buffer> buffer,
       const scoped_refptr<media::VideoFrame>& frame,
       const base::TimeTicks& timestamp) override {
-    EXPECT_EQ(gfx::Size(kTestWidth, kTestHeight), frame->visible_rect().size());
+    EXPECT_FALSE(frame->visible_rect().IsEmpty());
     EXPECT_EQ(media::VideoFrame::I420, frame->format());
     double frame_rate = 0;
     EXPECT_TRUE(
         frame->metadata()->GetDouble(media::VideoFrameMetadata::FRAME_RATE,
                                      &frame_rate));
     EXPECT_EQ(kTestFramesPerSecond, frame_rate);
-    uint8 yuv[3];
-    for (int plane = 0; plane < 3; ++plane)
-      yuv[plane] = frame->visible_data(plane)[0];
-    // TODO(nick): We just look at the first pixel presently, because if
-    // the analysis is too slow, the backlog of frames will grow without bound
-    // and trouble erupts. http://crbug.com/174519
-    color_callback_.Run((SkColorSetRGB(yuv[0], yuv[1], yuv[2])));
+
+    // TODO(miu): We just look at the center pixel presently, because if the
+    // analysis is too slow, the backlog of frames will grow without bound and
+    // trouble erupts. http://crbug.com/174519
+    using media::VideoFrame;
+    const gfx::Point center = frame->visible_rect().CenterPoint();
+    const int center_offset_y =
+        (frame->stride(VideoFrame::kYPlane) * center.y()) + center.x();
+    const int center_offset_uv =
+        (frame->stride(VideoFrame::kUPlane) * (center.y() / 2)) +
+            (center.x() / 2);
+    report_callback_.Run(
+        SkColorSetRGB(frame->data(VideoFrame::kYPlane)[center_offset_y],
+                      frame->data(VideoFrame::kUPlane)[center_offset_uv],
+                      frame->data(VideoFrame::kVPlane)[center_offset_uv]),
+        frame->visible_rect().size());
   }
 
   void OnError(const std::string& reason) override { error_callback_.Run(); }
@@ -407,7 +428,7 @@
   };
 
   scoped_refptr<VideoCaptureBufferPool> buffer_pool_;
-  base::Callback<void(SkColor)> color_callback_;
+  base::Callback<void(SkColor, const gfx::Size&)> report_callback_;
   base::Closure error_callback_;
 
   DISALLOW_COPY_AND_ASSIGN(StubClient);
@@ -417,9 +438,11 @@
  public:
   StubClientObserver()
       : error_encountered_(false),
-        wait_color_yuv_(0xcafe1950) {
+        wait_color_yuv_(0xcafe1950),
+        wait_size_(kTestWidth, kTestHeight) {
     client_.reset(new StubClient(
-        base::Bind(&StubClientObserver::OnColor, base::Unretained(this)),
+        base::Bind(&StubClientObserver::DidDeliverFrame,
+                   base::Unretained(this)),
         base::Bind(&StubClientObserver::OnError, base::Unretained(this))));
   }
 
@@ -429,16 +452,30 @@
     return client_.Pass();
   }
 
-  void QuitIfConditionMet(SkColor color) {
+  void QuitIfConditionsMet(SkColor color, const gfx::Size& size) {
     base::AutoLock guard(lock_);
-    if (wait_color_yuv_ == color || error_encountered_)
+    if (error_encountered_)
+      base::MessageLoop::current()->Quit();
+    else if (wait_color_yuv_ == color && wait_size_.IsEmpty())
+      base::MessageLoop::current()->Quit();
+    else if (wait_color_yuv_ == color && wait_size_ == size)
       base::MessageLoop::current()->Quit();
   }
 
+  // Run the current loop until a frame is delivered with the |expected_color|
+  // and any non-empty frame size.
   void WaitForNextColor(SkColor expected_color) {
+    WaitForNextColorAndFrameSize(expected_color, gfx::Size());
+  }
+
+  // Run the current loop until a frame is delivered with the |expected_color|
+  // and is of the |expected_size|.
+  void WaitForNextColorAndFrameSize(SkColor expected_color,
+                                    const gfx::Size& expected_size) {
     {
       base::AutoLock guard(lock_);
       wait_color_yuv_ = ConvertRgbToYuv(expected_color);
+      wait_size_ = expected_size;
       error_encountered_ = false;
     }
     RunCurrentLoopWithDeadline();
@@ -452,6 +489,7 @@
     {
       base::AutoLock guard(lock_);
       wait_color_yuv_ = kNotInterested;
+      wait_size_ = gfx::Size();
       error_encountered_ = false;
     }
     RunCurrentLoopWithDeadline();
@@ -472,22 +510,25 @@
       error_encountered_ = true;
     }
     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
-        &StubClientObserver::QuitIfConditionMet,
+        &StubClientObserver::QuitIfConditionsMet,
         base::Unretained(this),
-        kNothingYet));
+        kNothingYet,
+        gfx::Size()));
   }
 
-  void OnColor(SkColor color) {
+  void DidDeliverFrame(SkColor color, const gfx::Size& size) {
     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
-        &StubClientObserver::QuitIfConditionMet,
+        &StubClientObserver::QuitIfConditionsMet,
         base::Unretained(this),
-        color));
+        color,
+        size));
   }
 
  private:
   base::Lock lock_;
   bool error_encountered_;
   SkColor wait_color_yuv_;
+  gfx::Size wait_size_;
   scoped_ptr<StubClient> client_;
 
   DISALLOW_COPY_AND_ASSIGN(StubClientObserver);
@@ -622,6 +663,22 @@
     }
   }
 
+  void SimulateSourceSizeChange(const gfx::Size& size) {
+    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+    CaptureTestView* test_view = static_cast<CaptureTestView*>(
+        web_contents_->GetRenderViewHost()->GetView());
+    test_view->SetSize(size);
+    // Normally, RenderWidgetHostImpl would notify WebContentsImpl that the size
+    // has changed.  However, in this test setup where there is no render
+    // process, we must notify WebContentsImpl directly.
+    WebContentsImpl* const as_web_contents_impl =
+        static_cast<WebContentsImpl*>(web_contents_.get());
+    RenderWidgetHostDelegate* const as_rwh_delegate =
+        static_cast<RenderWidgetHostDelegate*>(as_web_contents_impl);
+    as_rwh_delegate->RenderWidgetWasResized(
+        as_web_contents_impl->GetMainFrame()->GetRenderWidgetHost(), true);
+  }
+
   void DestroyVideoCaptureDevice() { device_.reset(); }
 
   StubClientObserver* client_observer() {
@@ -879,5 +936,158 @@
   device()->StopAndDeAllocate();
 }
 
+// Tests that, when configured with the FIXED_ASPECT_RATIO resolution change
+// policy, the source size changes result in video frames of possibly varying
+// resolutions, but all with the same aspect ratio.
+TEST_F(WebContentsVideoCaptureDeviceTest, VariableResolution_FixedAspectRatio) {
+  media::VideoCaptureParams capture_params;
+  capture_params.requested_format.frame_size.SetSize(kTestWidth, kTestHeight);
+  capture_params.requested_format.frame_rate = kTestFramesPerSecond;
+  capture_params.requested_format.pixel_format = media::PIXEL_FORMAT_I420;
+  capture_params.resolution_change_policy =
+      media::RESOLUTION_POLICY_FIXED_ASPECT_RATIO;
+
+  device()->AllocateAndStart(capture_params, client_observer()->PassClient());
+
+  for (int i = 0; i < 6; i++) {
+    const char* name = NULL;
+    switch (i % 3) {
+      case 0:
+        source()->SetCanCopyToVideoFrame(true);
+        source()->SetUseFrameSubscriber(false);
+        name = "VideoFrame";
+        break;
+      case 1:
+        source()->SetCanCopyToVideoFrame(false);
+        source()->SetUseFrameSubscriber(true);
+        name = "Subscriber";
+        break;
+      case 2:
+        source()->SetCanCopyToVideoFrame(false);
+        source()->SetUseFrameSubscriber(false);
+        name = "SkBitmap";
+        break;
+      default:
+        FAIL();
+    }
+
+    SCOPED_TRACE(base::StringPrintf("Using %s path, iteration #%d", name, i));
+
+    // Source size equals maximum size.  Expect delivered frames to be
+    // kTestWidth by kTestHeight.
+    source()->SetSolidColor(SK_ColorRED);
+    SimulateSourceSizeChange(gfx::Size(kTestWidth, kTestHeight));
+    SimulateDrawEvent();
+    ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColorAndFrameSize(
+        SK_ColorRED, gfx::Size(kTestWidth, kTestHeight)));
+
+    // Source size is half in both dimensions.  Expect delivered frames to be of
+    // the same aspect ratio as kTestWidth by kTestHeight, but larger than the
+    // half size because the minimum height is 180 lines.
+    source()->SetSolidColor(SK_ColorGREEN);
+    SimulateSourceSizeChange(gfx::Size(kTestWidth / 2, kTestHeight / 2));
+    SimulateDrawEvent();
+    ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColorAndFrameSize(
+        SK_ColorGREEN, gfx::Size(180 * kTestWidth / kTestHeight, 180)));
+
+    // Source size changes aspect ratio.  Expect delivered frames to be padded
+    // in the horizontal dimension to preserve aspect ratio.
+    source()->SetSolidColor(SK_ColorBLUE);
+    SimulateSourceSizeChange(gfx::Size(kTestWidth / 2, kTestHeight));
+    SimulateDrawEvent();
+    ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColorAndFrameSize(
+        SK_ColorBLUE, gfx::Size(kTestWidth, kTestHeight)));
+
+    // Source size changes aspect ratio again.  Expect delivered frames to be
+    // padded in the vertical dimension to preserve aspect ratio.
+    source()->SetSolidColor(SK_ColorBLACK);
+    SimulateSourceSizeChange(gfx::Size(kTestWidth, kTestHeight / 2));
+    SimulateDrawEvent();
+    ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColorAndFrameSize(
+        SK_ColorBLACK, gfx::Size(kTestWidth, kTestHeight)));
+  }
+
+  device()->StopAndDeAllocate();
+}
+
+// Tests that, when configured with the ANY_WITHIN_LIMIT resolution change
+// policy, the source size changes result in video frames of possibly varying
+// resolutions.
+TEST_F(WebContentsVideoCaptureDeviceTest, VariableResolution_AnyWithinLimits) {
+  media::VideoCaptureParams capture_params;
+  capture_params.requested_format.frame_size.SetSize(kTestWidth, kTestHeight);
+  capture_params.requested_format.frame_rate = kTestFramesPerSecond;
+  capture_params.requested_format.pixel_format = media::PIXEL_FORMAT_I420;
+  capture_params.resolution_change_policy =
+      media::RESOLUTION_POLICY_ANY_WITHIN_LIMIT;
+
+  device()->AllocateAndStart(capture_params, client_observer()->PassClient());
+
+  for (int i = 0; i < 6; i++) {
+    const char* name = NULL;
+    switch (i % 3) {
+      case 0:
+        source()->SetCanCopyToVideoFrame(true);
+        source()->SetUseFrameSubscriber(false);
+        name = "VideoFrame";
+        break;
+      case 1:
+        source()->SetCanCopyToVideoFrame(false);
+        source()->SetUseFrameSubscriber(true);
+        name = "Subscriber";
+        break;
+      case 2:
+        source()->SetCanCopyToVideoFrame(false);
+        source()->SetUseFrameSubscriber(false);
+        name = "SkBitmap";
+        break;
+      default:
+        FAIL();
+    }
+
+    SCOPED_TRACE(base::StringPrintf("Using %s path, iteration #%d", name, i));
+
+    // Source size equals maximum size.  Expect delivered frames to be
+    // kTestWidth by kTestHeight.
+    source()->SetSolidColor(SK_ColorRED);
+    SimulateSourceSizeChange(gfx::Size(kTestWidth, kTestHeight));
+    SimulateDrawEvent();
+    ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColorAndFrameSize(
+        SK_ColorRED, gfx::Size(kTestWidth, kTestHeight)));
+
+    // Source size is half in both dimensions.  Expect delivered frames to also
+    // be half in both dimensions.
+    source()->SetSolidColor(SK_ColorGREEN);
+    SimulateSourceSizeChange(gfx::Size(kTestWidth / 2, kTestHeight / 2));
+    SimulateDrawEvent();
+    ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColorAndFrameSize(
+        SK_ColorGREEN, gfx::Size(kTestWidth / 2, kTestHeight / 2)));
+
+    // Source size changes to something arbitrary.  Since the source size is
+    // less than the maximum size, expect delivered frames to be the same size
+    // as the source size.
+    source()->SetSolidColor(SK_ColorBLUE);
+    gfx::Size arbitrary_source_size(kTestWidth / 2 + 42, kTestHeight - 10);
+    SimulateSourceSizeChange(arbitrary_source_size);
+    SimulateDrawEvent();
+    ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColorAndFrameSize(
+        SK_ColorBLUE, arbitrary_source_size));
+
+    // Source size changes to something arbitrary that exceeds the maximum frame
+    // size.  Since the source size exceeds the maximum size, expect delivered
+    // frames to be downscaled.
+    source()->SetSolidColor(SK_ColorBLACK);
+    arbitrary_source_size = gfx::Size(kTestWidth * 2 + 99, kTestHeight / 2);
+    SimulateSourceSizeChange(arbitrary_source_size);
+    SimulateDrawEvent();
+    ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColorAndFrameSize(
+        SK_ColorBLACK, gfx::Size(kTestWidth,
+                                 kTestWidth * arbitrary_source_size.height() /
+                                     arbitrary_source_size.width())));
+  }
+
+  device()->StopAndDeAllocate();
+}
+
 }  // namespace
 }  // namespace content
diff --git a/content/browser/media/cdm/browser_cdm_manager.cc b/content/browser/media/cdm/browser_cdm_manager.cc
index 1c6c77a..813a8bad 100644
--- a/content/browser/media/cdm/browser_cdm_manager.cc
+++ b/content/browser/media/cdm/browser_cdm_manager.cc
@@ -35,6 +35,11 @@
 
 namespace {
 
+#if defined(OS_ANDROID)
+// Android only supports 128-bit key IDs.
+const size_t kAndroidKeyIdBytes = 128 / 8;
+#endif
+
 // The ID used in this class is a concatenation of |render_frame_id| and
 // |cdm_id|, i.e. (render_frame_id << 32) + cdm_id.
 
@@ -345,6 +350,15 @@
     promise->reject(MediaKeys::INVALID_ACCESS_ERROR, 0, "Init data too long.");
     return;
   }
+#if defined(OS_ANDROID)
+  // 'webm' initData is a single key ID. On Android the length is restricted.
+  if (init_data_type == INIT_DATA_TYPE_WEBM &&
+      init_data.size() != kAndroidKeyIdBytes) {
+    promise->reject(MediaKeys::INVALID_ACCESS_ERROR, 0,
+                    "'webm' initData is not the correct length.");
+    return;
+  }
+#endif
 
   media::EmeInitDataType eme_init_data_type;
   switch (init_data_type) {
diff --git a/content/browser/media/cdm/browser_cdm_manager.h b/content/browser/media/cdm/browser_cdm_manager.h
index e58d459..57684da 100644
--- a/content/browser/media/cdm/browser_cdm_manager.h
+++ b/content/browser/media/cdm/browser_cdm_manager.h
@@ -31,8 +31,6 @@
 
 namespace content {
 
-struct InitializeCdmParameters;
-
 // This class manages all CDM objects. It receives control operations from the
 // the render process, and forwards them to corresponding CDM object. Callbacks
 // from CDM objects are converted to IPCs and then sent to the render process.
diff --git a/content/browser/media/webrtc_browsertest.cc b/content/browser/media/webrtc_browsertest.cc
index 5506d8e..e69d4c9 100644
--- a/content/browser/media/webrtc_browsertest.cc
+++ b/content/browser/media/webrtc_browsertest.cc
@@ -144,15 +144,9 @@
 }
 
 // Flaky on TSAN v2. http://crbug.com/408006
-#if defined(THREAD_SANITIZER)
-#define MAYBE_CanSetupVideoCallAndDisableLocalVideo \
-  DISABLED_CanSetupVideoCallAndDisableLocalVideo
-#else
-#define MAYBE_CanSetupVideoCallAndDisableLocalVideo \
-  CanSetupVideoCallAndDisableLocalVideo
-#endif
+// Flaky everywhere: http://crbug.com/477498
 IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
-                       MAYBE_CanSetupVideoCallAndDisableLocalVideo) {
+                       DISABLED_CanSetupVideoCallAndDisableLocalVideo) {
   const std::string javascript =
       "callAndDisableLocalVideo({video: true});";
   MakeTypicalPeerConnectionCall(javascript);
diff --git a/content/browser/net/quota_policy_cookie_store_unittest.cc b/content/browser/net/quota_policy_cookie_store_unittest.cc
index d4a036a..070d524 100644
--- a/content/browser/net/quota_policy_cookie_store_unittest.cc
+++ b/content/browser/net/quota_policy_cookie_store_unittest.cc
@@ -37,7 +37,8 @@
  public:
   QuotaPolicyCookieStoreTest()
       : pool_owner_(new base::SequencedWorkerPoolOwner(3, "Background Pool")),
-        loaded_event_(false, false) {
+        loaded_event_(false, false),
+        destroy_event_(false, false) {
   }
 
   void OnLoaded(const CanonicalCookieVector& cookies) {
@@ -53,6 +54,20 @@
     *cookies = cookies_;
   }
 
+  void ReleaseStore() {
+    EXPECT_TRUE(background_task_runner()->RunsTasksOnCurrentThread());
+    store_ = nullptr;
+    destroy_event_.Signal();
+  }
+
+  void DestroyStoreOnBackgroundThread() {
+    background_task_runner()->PostTask(
+        FROM_HERE, base::Bind(&QuotaPolicyCookieStoreTest::ReleaseStore,
+                              base::Unretained(this)));
+    destroy_event_.Wait();
+    DestroyStore();
+  }
+
  protected:
   scoped_refptr<base::SequencedTaskRunner> background_task_runner() {
     return pool_owner_->pool()->GetSequencedTaskRunner(
@@ -111,6 +126,7 @@
   TestBrowserThreadBundle bundle_;
   scoped_ptr<base::SequencedWorkerPoolOwner> pool_owner_;
   base::WaitableEvent loaded_event_;
+  base::WaitableEvent destroy_event_;
   base::ScopedTempDir temp_dir_;
   scoped_refptr<QuotaPolicyCookieStore> store_;
   CanonicalCookieVector cookies_;
@@ -127,9 +143,10 @@
   t += base::TimeDelta::FromInternalValue(10);
   AddCookie("A", "B", "persistent.com", "/", t);
 
-  // Replace the store effectively destroying the current one and forcing it
-  // to write its data to disk. Then we can see if after loading it again it
-  // is still there.
+  // Replace the store, which forces the current store to flush data to
+  // disk. Then, after reloading the store, confirm that the data was flushed by
+  // making sure it loads successfully.  This ensures that all pending commits
+  // are made to the store before allowing it to be closed.
   DestroyStore();
 
   // Reload and test for persistence.
@@ -172,9 +189,10 @@
   t += base::TimeDelta::FromInternalValue(10);
   AddCookie("A", "B", "nonpersistent.com", "/", t);
 
-  // Replace the store effectively destroying the current one and forcing it
-  // to write its data to disk. Then we can see if after loading it again it
-  // is still there.
+  // Replace the store, which forces the current store to flush data to
+  // disk. Then, after reloading the store, confirm that the data was flushed by
+  // making sure it loads successfully.  This ensures that all pending commits
+  // are made to the store before allowing it to be closed.
   DestroyStore();
   // Specify storage policy that makes "nonpersistent.com" session only.
   scoped_refptr<content::MockSpecialStoragePolicy> storage_policy =
@@ -182,7 +200,7 @@
   storage_policy->AddSessionOnly(
       net::cookie_util::CookieOriginToURL("nonpersistent.com", false));
 
-  // Reload and test for persistence
+  // Reload and test for persistence.
   STLDeleteElements(&cookies);
   CreateAndLoad(storage_policy.get(), &cookies);
   EXPECT_EQ(3U, cookies.size());
@@ -240,5 +258,35 @@
   STLDeleteElements(&cookies);
 }
 
+// Tests that the special storage policy is properly applied even when the store
+// is destroyed on a background thread.
+TEST_F(QuotaPolicyCookieStoreTest, TestDestroyOnBackgroundThread) {
+  // Specify storage policy that makes "nonpersistent.com" session only.
+  scoped_refptr<content::MockSpecialStoragePolicy> storage_policy =
+      new content::MockSpecialStoragePolicy();
+  storage_policy->AddSessionOnly(
+      net::cookie_util::CookieOriginToURL("nonpersistent.com", false));
+
+  CanonicalCookieVector cookies;
+  CreateAndLoad(storage_policy.get(), &cookies);
+  ASSERT_EQ(0U, cookies.size());
+
+  base::Time t = base::Time::Now();
+  AddCookie("A", "B", "nonpersistent.com", "/", t);
+
+  // Replace the store, which forces the current store to flush data to
+  // disk. Then, after reloading the store, confirm that the data was flushed by
+  // making sure it loads successfully.  This ensures that all pending commits
+  // are made to the store before allowing it to be closed.
+  DestroyStoreOnBackgroundThread();
+
+  // Reload and test for persistence.
+  STLDeleteElements(&cookies);
+  CreateAndLoad(storage_policy.get(), &cookies);
+  EXPECT_EQ(0U, cookies.size());
+
+  STLDeleteElements(&cookies);
+}
+
 }  // namespace
 }  // namespace content
diff --git a/content/browser/power_save_blocker_x11.cc b/content/browser/power_save_blocker_x11.cc
index 9cd6113e..bc20e02 100644
--- a/content/browser/power_save_blocker_x11.cc
+++ b/content/browser/power_save_blocker_x11.cc
@@ -93,6 +93,11 @@
   void ApplyBlock(DBusAPI api);
   void RemoveBlock(DBusAPI api);
 
+  // Asynchronous callback functions for ApplyBlock and RemoveBlock.
+  // Functions do not receive ownership of |response|.
+  void ApplyBlockFinished(DBusAPI api, dbus::Response* response);
+  void RemoveBlockFinished(dbus::Response* response);
+
   // If DPMS (the power saving system in X11) is not enabled, then we don't want
   // to try to disable power saving, since on some desktop environments that may
   // enable DPMS with very poor default settings (e.g. turning off the display
@@ -115,6 +120,15 @@
   bool enqueue_apply_;
   base::Lock lock_;
 
+  // Indicates that a D-Bus power save blocking request is in flight.
+  bool block_inflight_;
+  // Used to detect erronous redundant calls to RemoveBlock().
+  bool unblock_inflight_;
+  // Indicates that RemoveBlock() is called before ApplyBlock() has finished.
+  // If it's true, then the RemoveBlock() call will be processed immediately
+  // after ApplyBlock() has finished.
+  bool enqueue_unblock_;
+
   scoped_refptr<dbus::Bus> bus_;
 
   // The cookie that identifies our inhibit request,
@@ -139,6 +153,9 @@
   base::AutoLock lock(lock_);
   DCHECK(!enqueue_apply_);
   enqueue_apply_ = true;
+  block_inflight_ = false;
+  unblock_inflight_ = false;
+  enqueue_unblock_ = false;
   BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
                           base::Bind(&Delegate::InitOnUIThread, this));
 }
@@ -172,7 +189,8 @@
 
 void PowerSaveBlockerImpl::Delegate::ApplyBlock(DBusAPI api) {
   DCHECK_CURRENTLY_ON(BrowserThread::FILE);
-  DCHECK(!bus_.get());  // ApplyBlock() should only be called once.
+  DCHECK(!bus_);  // ApplyBlock() should only be called once.
+  DCHECK(!block_inflight_);
 
   dbus::Bus::Options options;
   options.bus_type = dbus::Bus::SESSION;
@@ -233,26 +251,53 @@
       break;
   }
 
-  // We could do this method call asynchronously, but if we did, we'd need to
-  // handle the case where we want to cancel the block before we get a reply.
-  // We're on the FILE thread so it should be OK to block briefly here.
-  scoped_ptr<dbus::Response> response(object_proxy->CallMethodAndBlock(
-      method_call.get(), dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
+  block_inflight_ = true;
+  object_proxy->CallMethod(
+      method_call.get(), dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+      base::Bind(&PowerSaveBlockerImpl::Delegate::ApplyBlockFinished, this,
+                 api));
+}
+
+void PowerSaveBlockerImpl::Delegate::ApplyBlockFinished(
+    DBusAPI api,
+    dbus::Response* response) {
+  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+  DCHECK(bus_);
+  DCHECK(block_inflight_);
+  block_inflight_ = false;
+
   if (response) {
     // The method returns an inhibit_cookie, used to uniquely identify
     // this request. It should be used as an argument to Uninhibit()
     // in order to remove the request.
-    dbus::MessageReader message_reader(response.get());
+    dbus::MessageReader message_reader(response);
     if (!message_reader.PopUint32(&inhibit_cookie_))
       LOG(ERROR) << "Invalid Inhibit() response: " << response->ToString();
   } else {
     LOG(ERROR) << "No response to Inhibit() request!";
   }
+
+  if (enqueue_unblock_) {
+    enqueue_unblock_ = false;
+    // RemoveBlock() was called while the Inhibit operation was in flight,
+    // so go ahead and remove the block now.
+    BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
+                            base::Bind(&Delegate::RemoveBlock, this, api_));
+  }
 }
 
 void PowerSaveBlockerImpl::Delegate::RemoveBlock(DBusAPI api) {
   DCHECK_CURRENTLY_ON(BrowserThread::FILE);
-  DCHECK(bus_.get());  // RemoveBlock() should only be called once.
+  DCHECK(bus_);  // RemoveBlock() should only be called once.
+  DCHECK(!unblock_inflight_);
+
+  if (block_inflight_) {
+    DCHECK(!enqueue_unblock_);
+    // Can't call RemoveBlock until ApplyBlock's async operation has
+    // finished. Enqueue it for execution once ApplyBlock is done.
+    enqueue_unblock_ = true;
+    return;
+  }
 
   scoped_refptr<dbus::ObjectProxy> object_proxy;
   scoped_ptr<dbus::MethodCall> method_call;
@@ -279,8 +324,18 @@
 
   dbus::MessageWriter message_writer(method_call.get());
   message_writer.AppendUint32(inhibit_cookie_);
-  scoped_ptr<dbus::Response> response(object_proxy->CallMethodAndBlock(
-      method_call.get(), dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
+  unblock_inflight_ = true;
+  object_proxy->CallMethod(
+      method_call.get(), dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+      base::Bind(&PowerSaveBlockerImpl::Delegate::RemoveBlockFinished, this));
+}
+
+void PowerSaveBlockerImpl::Delegate::RemoveBlockFinished(
+    dbus::Response* response) {
+  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+  DCHECK(bus_);
+  unblock_inflight_ = false;
+
   if (!response)
     LOG(ERROR) << "No response to Uninhibit() request!";
   // We don't care about checking the result. We assume it works; we can't
diff --git a/content/browser/presentation/presentation_service_impl.cc b/content/browser/presentation/presentation_service_impl.cc
index 7a0bab8..916dded 100644
--- a/content/browser/presentation/presentation_service_impl.cc
+++ b/content/browser/presentation/presentation_service_impl.cc
@@ -18,8 +18,17 @@
 #include "content/public/common/frame_navigate_params.h"
 #include "content/public/common/presentation_constants.h"
 
+namespace content {
+
 namespace {
 
+const int kInvalidRequestSessionId = -1;
+
+int GetNextRequestSessionId() {
+  static int next_request_session_id = 0;
+  return ++next_request_session_id;
+}
+
 // The return value takes ownership of the contents of |input|.
 presentation::SessionMessagePtr ToMojoSessionMessage(
     content::PresentationSessionMessage* input) {
@@ -76,9 +85,15 @@
   return output.Pass();
 }
 
-} // namespace
+void InvokeNewSessionMojoCallbackWithError(
+    const NewSessionMojoCallback& callback) {
+  callback.Run(
+        presentation::PresentationSessionInfoPtr(),
+        presentation::PresentationError::From(
+            PresentationError(PRESENTATION_ERROR_UNKNOWN, "Internal error")));
+}
 
-namespace content {
+} // namespace
 
 PresentationServiceImpl::PresentationServiceImpl(
     RenderFrameHost* render_frame_host,
@@ -86,8 +101,7 @@
     PresentationServiceDelegate* delegate)
     : WebContentsObserver(web_contents),
       delegate_(delegate),
-      is_start_session_pending_(false),
-      next_request_session_id_(0),
+      start_session_request_id_(kInvalidRequestSessionId),
       weak_factory_(this) {
   DCHECK(render_frame_host);
   DCHECK(web_contents);
@@ -103,7 +117,6 @@
 PresentationServiceImpl::~PresentationServiceImpl() {
   if (delegate_)
     delegate_->RemoveObserver(render_process_id_, render_frame_id_);
-  FlushNewSessionCallbacks();
 }
 
 // static
@@ -213,13 +226,21 @@
     return;
   }
 
-  if (is_start_session_pending_) {
-    queued_start_session_requests_.push_back(make_linked_ptr(
-        new StartSessionRequest(presentation_url, presentation_id, callback)));
+  // Currently not processing a request, so no need for queueing.
+  if (start_session_request_id_ == kInvalidRequestSessionId) {
+    DoStartSession(make_scoped_ptr(new StartSessionRequest(
+        presentation_url, presentation_id, callback)));
     return;
   }
 
-  DoStartSession(presentation_url, presentation_id, callback);
+  if (queued_start_session_requests_.size() >= kMaxNumQueuedSessionRequests) {
+    InvokeNewSessionMojoCallbackWithError(callback);
+    return;
+  }
+
+  queued_start_session_requests_.push_back(
+      make_linked_ptr(new StartSessionRequest(
+          presentation_url, presentation_id, callback)));
 }
 
 void PresentationServiceImpl::JoinSession(
@@ -232,98 +253,120 @@
     return;
   }
 
-  int request_session_id = RegisterNewSessionCallback(callback);
+  int request_session_id = RegisterJoinSessionCallback(callback);
+  if (request_session_id == kInvalidRequestSessionId) {
+    InvokeNewSessionMojoCallbackWithError(callback);
+    return;
+  }
   delegate_->JoinSession(
       render_process_id_,
       render_frame_id_,
       presentation_url,
       presentation_id,
-      base::Bind(&PresentationServiceImpl::OnStartOrJoinSessionSucceeded,
-                 weak_factory_.GetWeakPtr(), false, request_session_id),
-      base::Bind(&PresentationServiceImpl::OnStartOrJoinSessionError,
-                 weak_factory_.GetWeakPtr(), false, request_session_id));
+      base::Bind(&PresentationServiceImpl::OnJoinSessionSucceeded,
+                 weak_factory_.GetWeakPtr(), request_session_id),
+      base::Bind(&PresentationServiceImpl::OnJoinSessionError,
+                 weak_factory_.GetWeakPtr(), request_session_id));
 }
 
 void PresentationServiceImpl::HandleQueuedStartSessionRequests() {
-  if (queued_start_session_requests_.empty()) {
-    is_start_session_pending_ = false;
+  if (queued_start_session_requests_.empty())
     return;
-  }
+
   linked_ptr<StartSessionRequest> request =
       queued_start_session_requests_.front();
   queued_start_session_requests_.pop_front();
-  DoStartSession(request->presentation_url(),
-                 request->presentation_id(),
-                 request->PassCallback());
+  DoStartSession(make_scoped_ptr(request.release()));
 }
 
-int PresentationServiceImpl::RegisterNewSessionCallback(
+int PresentationServiceImpl::RegisterJoinSessionCallback(
     const NewSessionMojoCallback& callback) {
-  ++next_request_session_id_;
-  pending_session_cbs_[next_request_session_id_].reset(
-      new NewSessionMojoCallback(callback));
-  return next_request_session_id_;
-}
+  if (pending_join_session_cbs_.size() >= kMaxNumQueuedSessionRequests)
+    return kInvalidRequestSessionId;
 
-void PresentationServiceImpl::FlushNewSessionCallbacks() {
-  for (auto& pending_entry : pending_session_cbs_) {
-    InvokeNewSessionMojoCallbackWithError(*pending_entry.second);
-  }
-  pending_session_cbs_.clear();
+  int request_id = GetNextRequestSessionId();
+  pending_join_session_cbs_[request_id].reset(
+      new NewSessionMojoCallbackWrapper(callback));
+  return request_id;
 }
 
 void PresentationServiceImpl::DoStartSession(
-    const std::string& presentation_url,
-    const std::string& presentation_id,
-    const NewSessionMojoCallback& callback) {
-  int request_session_id = RegisterNewSessionCallback(callback);
-  is_start_session_pending_ = true;
+    scoped_ptr<StartSessionRequest> request) {
+  DCHECK_EQ(kInvalidRequestSessionId, start_session_request_id_);
+  DCHECK(!pending_start_session_cb_.get());
+
+  int request_session_id = GetNextRequestSessionId();
+  start_session_request_id_ = request_session_id;
+  pending_start_session_cb_ = request->PassCallback();
+
   delegate_->StartSession(
       render_process_id_,
       render_frame_id_,
-      presentation_url,
-      presentation_id,
-      base::Bind(&PresentationServiceImpl::OnStartOrJoinSessionSucceeded,
-                 weak_factory_.GetWeakPtr(), true, request_session_id),
-      base::Bind(&PresentationServiceImpl::OnStartOrJoinSessionError,
-                 weak_factory_.GetWeakPtr(), true, request_session_id));
+      request->presentation_url(),
+      request->presentation_id(),
+      base::Bind(&PresentationServiceImpl::OnStartSessionSucceeded,
+                 weak_factory_.GetWeakPtr(), request_session_id),
+      base::Bind(&PresentationServiceImpl::OnStartSessionError,
+                 weak_factory_.GetWeakPtr(), request_session_id));
 }
 
-void PresentationServiceImpl::OnStartOrJoinSessionSucceeded(
-    bool is_start_session,
+void PresentationServiceImpl::OnStartSessionSucceeded(
     int request_session_id,
     const PresentationSessionInfo& session_info) {
-  RunAndEraseNewSessionMojoCallback(
+  if (request_session_id == start_session_request_id_) {
+    CHECK(pending_start_session_cb_.get());
+    pending_start_session_cb_->Run(
+        presentation::PresentationSessionInfo::From(session_info),
+        presentation::PresentationErrorPtr());
+    pending_start_session_cb_.reset();
+    start_session_request_id_ = kInvalidRequestSessionId;
+    HandleQueuedStartSessionRequests();
+  }
+}
+
+void PresentationServiceImpl::OnStartSessionError(
+    int request_session_id,
+    const PresentationError& error) {
+  if (request_session_id == start_session_request_id_) {
+    CHECK(pending_start_session_cb_.get());
+    pending_start_session_cb_->Run(
+        presentation::PresentationSessionInfoPtr(),
+        presentation::PresentationError::From(error));
+    pending_start_session_cb_.reset();
+    start_session_request_id_ = kInvalidRequestSessionId;
+    HandleQueuedStartSessionRequests();
+  }
+}
+
+void PresentationServiceImpl::OnJoinSessionSucceeded(
+    int request_session_id,
+    const PresentationSessionInfo& session_info) {
+  RunAndEraseJoinSessionMojoCallback(
       request_session_id,
       presentation::PresentationSessionInfo::From(session_info),
       presentation::PresentationErrorPtr());
-  if (is_start_session)
-    HandleQueuedStartSessionRequests();
 }
 
-void PresentationServiceImpl::OnStartOrJoinSessionError(
-    bool is_start_session,
+void PresentationServiceImpl::OnJoinSessionError(
     int request_session_id,
     const PresentationError& error) {
-  RunAndEraseNewSessionMojoCallback(
+  RunAndEraseJoinSessionMojoCallback(
       request_session_id,
       presentation::PresentationSessionInfoPtr(),
       presentation::PresentationError::From(error));
-  if (is_start_session)
-    HandleQueuedStartSessionRequests();
 }
 
-void PresentationServiceImpl::RunAndEraseNewSessionMojoCallback(
+void PresentationServiceImpl::RunAndEraseJoinSessionMojoCallback(
     int request_session_id,
     presentation::PresentationSessionInfoPtr session,
     presentation::PresentationErrorPtr error) {
-  auto it = pending_session_cbs_.find(request_session_id);
-  if (it == pending_session_cbs_.end())
+  auto it = pending_join_session_cbs_.find(request_session_id);
+  if (it == pending_join_session_cbs_.end())
     return;
 
   DCHECK(it->second.get());
   it->second->Run(session.Pass(), error.Pass());
-  pending_session_cbs_.erase(it);
+  pending_join_session_cbs_.erase(it);
 }
 
 void PresentationServiceImpl::SetDefaultPresentationURL(
@@ -489,15 +532,23 @@
 
   default_presentation_url_.clear();
   default_presentation_id_.clear();
+
   screen_availability_listener_.reset();
+
   queued_start_session_requests_.clear();
-  FlushNewSessionCallbacks();
+  start_session_request_id_ = kInvalidRequestSessionId;
+  pending_start_session_cb_.reset();
+
+  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>());
     on_session_messages_callback_.reset();
   }
+
   if (send_message_callback_) {
     // Run the callback with false, indicating the renderer to stop sending
     // the requests and invalidate all pending requests.
@@ -506,15 +557,6 @@
   }
 }
 
-// static
-void PresentationServiceImpl::InvokeNewSessionMojoCallbackWithError(
-    const NewSessionMojoCallback& callback) {
-  callback.Run(
-        presentation::PresentationSessionInfoPtr(),
-        presentation::PresentationError::From(
-            PresentationError(PRESENTATION_ERROR_UNKNOWN, "Internal error")));
-}
-
 void PresentationServiceImpl::OnDelegateDestroyed() {
   DVLOG(2) << "PresentationServiceImpl::OnDelegateDestroyed";
   delegate_ = nullptr;
@@ -551,26 +593,40 @@
   service_->client_->OnScreenAvailabilityUpdated(available);
 }
 
+PresentationServiceImpl::NewSessionMojoCallbackWrapper
+::NewSessionMojoCallbackWrapper(const NewSessionMojoCallback& callback)
+    : callback_(callback) {
+}
+
+PresentationServiceImpl::NewSessionMojoCallbackWrapper
+::~NewSessionMojoCallbackWrapper() {
+  if (!callback_.is_null())
+    InvokeNewSessionMojoCallbackWithError(callback_);
+}
+
+void PresentationServiceImpl::NewSessionMojoCallbackWrapper::Run(
+    presentation::PresentationSessionInfoPtr session,
+    presentation::PresentationErrorPtr error) {
+  DCHECK(!callback_.is_null());
+  callback_.Run(session.Pass(), error.Pass());
+  callback_.reset();
+}
+
 PresentationServiceImpl::StartSessionRequest::StartSessionRequest(
     const std::string& presentation_url,
     const std::string& presentation_id,
     const NewSessionMojoCallback& callback)
     : presentation_url_(presentation_url),
       presentation_id_(presentation_id),
-      callback_(callback) {
+      callback_wrapper_(new NewSessionMojoCallbackWrapper(callback)) {
 }
 
 PresentationServiceImpl::StartSessionRequest::~StartSessionRequest() {
-  // Ensure that a pending callback is not dropped.
-  if (!callback_.is_null())
-    InvokeNewSessionMojoCallbackWithError(callback_);
 }
 
-PresentationServiceImpl::NewSessionMojoCallback
+scoped_ptr<PresentationServiceImpl::NewSessionMojoCallbackWrapper>
 PresentationServiceImpl::StartSessionRequest::PassCallback() {
-  NewSessionMojoCallback callback = callback_;
-  callback_.reset();
-  return callback;
+  return callback_wrapper_.Pass();
 }
 
 PresentationServiceImpl::DefaultSessionStartContext
diff --git a/content/browser/presentation/presentation_service_impl.h b/content/browser/presentation/presentation_service_impl.h
index aeb32f0..9d4f5a12 100644
--- a/content/browser/presentation/presentation_service_impl.h
+++ b/content/browser/presentation/presentation_service_impl.h
@@ -31,6 +31,10 @@
 struct PresentationSessionMessage;
 class RenderFrameHost;
 
+using NewSessionMojoCallback = mojo::Callback<
+    void(presentation::PresentationSessionInfoPtr,
+         presentation::PresentationErrorPtr)>;
+
 // Implementation of Mojo PresentationService.
 // It handles Presentation API requests coming from Blink / renderer process
 // and delegates the requests to the embedder's media router via
@@ -78,10 +82,14 @@
       DefaultSessionStartReset);
   FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest,
                            ReceiveSessionMessagesAfterReset);
+  FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest,
+                           MaxPendingStartSessionRequests);
+  FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest,
+                           MaxPendingJoinSessionRequests);
 
-  using NewSessionMojoCallback =
-      mojo::Callback<void(presentation::PresentationSessionInfoPtr,
-          presentation::PresentationErrorPtr)>;
+  // Maximum number of queued StartSession or JoinSession requests.
+  static const int kMaxNumQueuedSessionRequests = 10;
+
   using DefaultSessionMojoCallback =
       mojo::Callback<void(presentation::PresentationSessionInfoPtr)>;
   using SessionStateCallback =
@@ -133,7 +141,24 @@
     scoped_ptr<PresentationSessionInfo> session_;
   };
 
-  // Context for a StartSession request.
+  // Ensures the provided NewSessionMojoCallback is invoked exactly once
+  // before it goes out of scope.
+  class NewSessionMojoCallbackWrapper {
+   public:
+    explicit NewSessionMojoCallbackWrapper(
+        const NewSessionMojoCallback& callback);
+    ~NewSessionMojoCallbackWrapper();
+
+    void Run(presentation::PresentationSessionInfoPtr session,
+             presentation::PresentationErrorPtr error);
+
+   private:
+    NewSessionMojoCallback callback_;
+
+    DISALLOW_COPY_AND_ASSIGN(NewSessionMojoCallbackWrapper);
+  };
+
+  // Context for a queued StartSession request.
   class CONTENT_EXPORT StartSessionRequest {
    public:
     StartSessionRequest(const std::string& presentation_url,
@@ -141,9 +166,7 @@
                         const NewSessionMojoCallback& callback);
     ~StartSessionRequest();
 
-    // Retrieves the pending callback from this request, transferring ownership
-    // to the caller.
-    NewSessionMojoCallback PassCallback();
+    scoped_ptr<NewSessionMojoCallbackWrapper> PassCallback();
 
     const std::string& presentation_url() const { return presentation_url_; }
     const std::string& presentation_id() const { return presentation_id_; }
@@ -151,7 +174,9 @@
    private:
     const std::string presentation_url_;
     const std::string presentation_id_;
-    NewSessionMojoCallback callback_;
+    scoped_ptr<NewSessionMojoCallbackWrapper> callback_wrapper_;
+
+    DISALLOW_COPY_AND_ASSIGN(StartSessionRequest);
   };
 
   // |render_frame_host|: The RFH this instance is associated with.
@@ -210,10 +235,11 @@
   void OnDefaultPresentationStarted(const PresentationSessionInfo& session)
       override;
 
-  // Finds the callback from |pending_session_cbs_| using |request_session_id|.
+  // Finds the callback from |pending_join_session_cbs_| using
+  // |request_session_id|.
   // If it exists, invoke it with |session| and |error|, then erase it from
-  // |pending_session_cbs_|.
-  void RunAndEraseNewSessionMojoCallback(
+  // |pending_join_session_cbs_|.
+  void RunAndEraseJoinSessionMojoCallback(
       int request_session_id,
       presentation::PresentationSessionInfoPtr session,
       presentation::PresentationErrorPtr error);
@@ -229,21 +255,22 @@
   // These functions are bound as base::Callbacks and passed to
   // embedder's implementation of PresentationServiceDelegate for later
   // invocation.
-  void OnStartOrJoinSessionSucceeded(
-      bool is_start_session,
+  void OnStartSessionSucceeded(
       int request_session_id,
       const PresentationSessionInfo& session_info);
-  void OnStartOrJoinSessionError(
-      bool is_start_session,
+  void OnStartSessionError(
+      int request_session_id,
+      const PresentationError& error);
+  void OnJoinSessionSucceeded(
+      int request_session_id,
+      const PresentationSessionInfo& session_info);
+  void OnJoinSessionError(
       int request_session_id,
       const PresentationError& error);
   void OnSendMessageCallback();
 
   // Requests delegate to start a session.
-  void DoStartSession(
-      const std::string& presentation_url,
-      const std::string& presentation_id,
-      const NewSessionMojoCallback& callback);
+  void DoStartSession(scoped_ptr<StartSessionRequest> request);
 
   // Passed to embedder's implementation of PresentationServiceDelegate for
   // later invocation when session messages arrive.
@@ -258,16 +285,10 @@
   // the first one in the queue.
   void HandleQueuedStartSessionRequests();
 
-  // Associates |callback| with a unique request ID and stores it in a map.
-  int RegisterNewSessionCallback(
-    const NewSessionMojoCallback& callback);
-
-  // Flushes all pending new session callbacks with error responses.
-  void FlushNewSessionCallbacks();
-
-  // Invokes |callback| with an error.
-  static void InvokeNewSessionMojoCallbackWithError(
-      const NewSessionMojoCallback& callback);
+  // Associates a JoinSession |callback| with a unique request ID and
+  // stores it in a map.
+  // Returns a positive value on success.
+  int RegisterJoinSessionCallback(const NewSessionMojoCallback& callback);
 
   // Returns true if this object is associated with |render_frame_host|.
   bool FrameMatches(content::RenderFrameHost* render_frame_host) const;
@@ -290,11 +311,14 @@
   // it is removed from head of the queue.
   std::deque<linked_ptr<StartSessionRequest>> queued_start_session_requests_;
 
-  // Indicates that a StartSession request is currently being processed.
-  bool is_start_session_pending_;
+  // For StartSession requests.
+  // Set to a positive value when a StartSession request is being processed.
+  int start_session_request_id_;
+  scoped_ptr<NewSessionMojoCallbackWrapper> pending_start_session_cb_;
 
-  int next_request_session_id_;
-  base::hash_map<int, linked_ptr<NewSessionMojoCallback>> pending_session_cbs_;
+  // For JoinSession requests.
+  base::hash_map<int, linked_ptr<NewSessionMojoCallbackWrapper>>
+      pending_join_session_cbs_;
 
   scoped_ptr<DefaultSessionStartContext> default_session_start_context_;
 
diff --git a/content/browser/presentation/presentation_service_impl_unittest.cc b/content/browser/presentation/presentation_service_impl_unittest.cc
index 177da86..677418f 100644
--- a/content/browser/presentation/presentation_service_impl_unittest.cc
+++ b/content/browser/presentation/presentation_service_impl_unittest.cc
@@ -43,6 +43,11 @@
          expected->data.Equals(actual->data);
 }
 
+void DoNothing(
+    presentation::PresentationSessionInfoPtr info,
+    presentation::PresentationErrorPtr error) {
+}
+
 }  // namespace
 
 class MockPresentationServiceDelegate : public PresentationServiceDelegate {
@@ -124,8 +129,7 @@
 
 class PresentationServiceImplTest : public RenderViewHostImplTestHarness {
  public:
-  PresentationServiceImplTest()
-      : default_session_started_count_(0) {}
+  PresentationServiceImplTest() : default_session_started_count_(0) {}
 
   void SetUp() override {
     RenderViewHostImplTestHarness::SetUp();
@@ -784,4 +788,53 @@
   SaveQuitClosureAndRunLoop();
 }
 
+TEST_F(PresentationServiceImplTest, MaxPendingStartSessionRequests) {
+  const char* presentation_url = "http://fooUrl%d";
+  const char* presentation_id = "presentationId%d";
+  int num_requests = PresentationServiceImpl::kMaxNumQueuedSessionRequests + 1;
+  int i = 0;
+  // First request will be processed. The subsequent
+  // |kMaxNumQueuedSessionRequests| requests will be queued.
+  EXPECT_CALL(mock_delegate_, StartSession(_, _, _, _, _, _)).Times(1);
+  for (; i < num_requests; ++i) {
+    service_ptr_->StartSession(
+        base::StringPrintf(presentation_url, i),
+        base::StringPrintf(presentation_id, i),
+        base::Bind(&DoNothing));
+  }
+
+  // Exceeded maximum queue size, should invoke mojo callback with error.
+  service_ptr_->StartSession(
+        base::StringPrintf(presentation_url, i),
+        base::StringPrintf(presentation_id, i),
+        base::Bind(
+            &PresentationServiceImplTest::ExpectNewSessionMojoCallbackError,
+            base::Unretained(this)));
+  SaveQuitClosureAndRunLoop();
+}
+
+TEST_F(PresentationServiceImplTest, MaxPendingJoinSessionRequests) {
+  const char* presentation_url = "http://fooUrl%d";
+  const char* presentation_id = "presentationId%d";
+  int num_requests = PresentationServiceImpl::kMaxNumQueuedSessionRequests;
+  int i = 0;
+  EXPECT_CALL(mock_delegate_, JoinSession(_, _, _, _, _, _))
+      .Times(num_requests);
+  for (; i < num_requests; ++i) {
+    service_ptr_->JoinSession(
+        base::StringPrintf(presentation_url, i),
+        base::StringPrintf(presentation_id, i),
+        base::Bind(&DoNothing));
+  }
+
+  // Exceeded maximum queue size, should invoke mojo callback with error.
+  service_ptr_->JoinSession(
+        base::StringPrintf(presentation_url, i),
+        base::StringPrintf(presentation_id, i),
+        base::Bind(
+            &PresentationServiceImplTest::ExpectNewSessionMojoCallbackError,
+            base::Unretained(this)));
+  SaveQuitClosureAndRunLoop();
+}
+
 }  // namespace content
diff --git a/content/browser/service_worker/service_worker_disk_cache.cc b/content/browser/service_worker/service_worker_disk_cache.cc
index 4b6237f..925bdcf 100644
--- a/content/browser/service_worker/service_worker_disk_cache.cc
+++ b/content/browser/service_worker/service_worker_disk_cache.cc
@@ -6,6 +6,10 @@
 
 namespace content {
 
+ServiceWorkerDiskCache::ServiceWorkerDiskCache()
+    : AppCacheDiskCache(true /* use_simple_cache */) {
+}
+
 ServiceWorkerResponseReader::ServiceWorkerResponseReader(
     int64 response_id, ServiceWorkerDiskCache* disk_cache)
     : AppCacheResponseReader(response_id, 0, disk_cache) {
diff --git a/content/browser/service_worker/service_worker_disk_cache.h b/content/browser/service_worker/service_worker_disk_cache.h
index 7b9b4e4..1ba34b44 100644
--- a/content/browser/service_worker/service_worker_disk_cache.h
+++ b/content/browser/service_worker/service_worker_disk_cache.h
@@ -18,6 +18,8 @@
 
 class CONTENT_EXPORT ServiceWorkerDiskCache
     : public AppCacheDiskCache {
+ public:
+  ServiceWorkerDiskCache();
 };
 
 class CONTENT_EXPORT ServiceWorkerResponseReader
diff --git a/content/browser/service_worker/service_worker_metrics.cc b/content/browser/service_worker/service_worker_metrics.cc
index dc3c157..c0d882d3 100644
--- a/content/browser/service_worker/service_worker_metrics.cc
+++ b/content/browser/service_worker/service_worker_metrics.cc
@@ -107,4 +107,13 @@
                             SERVICE_WORKER_ERROR_MAX_VALUE);
 }
 
+void ServiceWorkerMetrics::RecordEventStatus(size_t fired_events,
+                                             size_t handled_events) {
+  if (!fired_events)
+    return;
+  int unhandled_ratio = (fired_events - handled_events) * 100 / fired_events;
+  UMA_HISTOGRAM_PERCENTAGE("ServiceWorker.UnhandledEventRatio",
+                           unhandled_ratio);
+}
+
 }  // namespace content
diff --git a/content/browser/service_worker/service_worker_metrics.h b/content/browser/service_worker/service_worker_metrics.h
index 7b477af..400cd7e 100644
--- a/content/browser/service_worker/service_worker_metrics.h
+++ b/content/browser/service_worker/service_worker_metrics.h
@@ -65,6 +65,10 @@
   static void RecordActivateEventStatus(ServiceWorkerStatusCode status);
   static void RecordInstallEventStatus(ServiceWorkerStatusCode status);
 
+  // Records the ratio of unhandled events to the all events fired during
+  // the lifetime of ServiceWorker.
+  static void RecordEventStatus(size_t fired_events, size_t handled_events);
+
  private:
   DISALLOW_IMPLICIT_CONSTRUCTORS(ServiceWorkerMetrics);
 };
diff --git a/content/browser/service_worker/service_worker_version.cc b/content/browser/service_worker/service_worker_version.cc
index 9504bef..4299a26c 100644
--- a/content/browser/service_worker/service_worker_version.cc
+++ b/content/browser/service_worker/service_worker_version.cc
@@ -366,6 +366,25 @@
 const int ServiceWorkerVersion::kStartWorkerTimeoutMinutes = 5;
 const int ServiceWorkerVersion::kRequestTimeoutMinutes = 5;
 
+class ServiceWorkerVersion::ServiceWorkerEventMetrics {
+ public:
+  ServiceWorkerEventMetrics() {}
+  ~ServiceWorkerEventMetrics() {
+    ServiceWorkerMetrics::RecordEventStatus(fired_events, handled_events);
+  }
+
+  void RecordEventStatus(bool handled) {
+    ++fired_events;
+    if (handled)
+      ++handled_events;
+  }
+
+ private:
+  size_t fired_events = 0;
+  size_t handled_events = 0;
+  DISALLOW_COPY_AND_ASSIGN(ServiceWorkerEventMetrics);
+};
+
 ServiceWorkerVersion::ServiceWorkerVersion(
     ServiceWorkerRegistration* registration,
     const GURL& script_url,
@@ -379,6 +398,7 @@
       context_(context),
       script_cache_map_(this, context),
       ping_state_(NOT_PINGING),
+      metrics_(new ServiceWorkerEventMetrics),
       weak_factory_(this) {
   DCHECK(context_);
   DCHECK(registration);
@@ -1185,6 +1205,10 @@
     return;
   }
 
+  // TODO(kinuko): Record other event statuses too.
+  const bool handled = (result == SERVICE_WORKER_FETCH_EVENT_RESULT_RESPONSE);
+  metrics_->RecordEventStatus(handled);
+
   scoped_refptr<ServiceWorkerVersion> protect(this);
   callback->Run(SERVICE_WORKER_OK, result, response);
   RemoveCallbackAndStopIfRedundant(&fetch_callbacks_, request_id);
diff --git a/content/browser/service_worker/service_worker_version.h b/content/browser/service_worker/service_worker_version.h
index b020c25214..af011e5 100644
--- a/content/browser/service_worker/service_worker_version.h
+++ b/content/browser/service_worker/service_worker_version.h
@@ -329,6 +329,8 @@
   FRIEND_TEST_ALL_PREFIXES(ServiceWorkerVersionBrowserTest,
                            TimeoutWorkerInEvent);
 
+  class ServiceWorkerEventMetrics;
+
   typedef ServiceWorkerVersion self;
   using ServiceWorkerClients = std::vector<ServiceWorkerClientInfo>;
 
@@ -553,6 +555,8 @@
   // running |start_callbacks_|.
   ServiceWorkerStatusCode start_worker_status_ = SERVICE_WORKER_OK;
 
+  scoped_ptr<ServiceWorkerEventMetrics> metrics_;
+
   base::WeakPtrFactory<ServiceWorkerVersion> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(ServiceWorkerVersion);
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc
index 3ae902e..c09d429 100644
--- a/content/browser/site_per_process_browsertest.cc
+++ b/content/browser/site_per_process_browsertest.cc
@@ -1505,16 +1505,10 @@
   TestNavigationObserver observer(shell()->web_contents());
 
   // Navigate the first subframe to a cross-site page with two subframes.
-  // NavigateFrameToURL can't be used here because it doesn't guarantee that
-  // FrameTreeNodes will have been created for child frames when it returns.
-  RenderFrameHostCreatedObserver frame_observer(shell()->web_contents(), 4);
   GURL foo_url(
       embedded_test_server()->GetURL("foo.com", "/frame_tree/1-1.html"));
-  NavigationController::LoadURLParams params(foo_url);
-  params.transition_type = ui::PAGE_TRANSITION_LINK;
-  params.frame_tree_node_id = root->child_at(0)->frame_tree_node_id();
-  root->child_at(0)->navigator()->GetController()->LoadURLWithParams(params);
-  frame_observer.Wait();
+  NavigateFrameToURL(root->child_at(0), foo_url);
+  EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
 
   // We can't use a TestNavigationObserver to verify the URL here,
   // since the frame has children that may have clobbered it in the observer.
@@ -1591,13 +1585,11 @@
   TestNavigationObserver observer(shell()->web_contents());
 
   // Navigate the second (sandboxed) subframe to a cross-site page with a
-  // subframe. Use RenderFrameHostCreatedObserver to guarantee that all
-  // FrameTreeNodes are created for child frames.
-  RenderFrameHostCreatedObserver frame_observer(shell()->web_contents(), 4);
+  // subframe.
   GURL foo_url(
       embedded_test_server()->GetURL("foo.com", "/frame_tree/1-1.html"));
   NavigateFrameToURL(root->child_at(1), foo_url);
-  frame_observer.Wait();
+  EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
 
   // We can't use a TestNavigationObserver to verify the URL here,
   // since the frame has children that may have clobbered it in the observer.
diff --git a/content/browser/tracing/tracing_ui.cc b/content/browser/tracing/tracing_ui.cc
index 58fbb75..546fd74d 100644
--- a/content/browser/tracing/tracing_ui.cc
+++ b/content/browser/tracing/tracing_ui.cc
@@ -40,14 +40,14 @@
 
 void OnGotCategories(const WebUIDataSource::GotDataCallback& callback,
                      const std::set<std::string>& categorySet) {
-  scoped_ptr<base::ListValue> category_list(new base::ListValue());
+  base::ListValue category_list;
   for (std::set<std::string>::const_iterator it = categorySet.begin();
        it != categorySet.end(); it++) {
-    category_list->AppendString(*it);
+    category_list.AppendString(*it);
   }
 
   base::RefCountedString* res = new base::RefCountedString();
-  base::JSONWriter::Write(category_list.get(), &res->data());
+  base::JSONWriter::Write(category_list, &res->data());
   callback.Run(res);
 }
 
@@ -133,12 +133,12 @@
 void OnTraceBufferStatusResult(const WebUIDataSource::GotDataCallback& callback,
                                float percent_full,
                                size_t approximate_event_count) {
-  scoped_ptr<base::DictionaryValue> status(new base::DictionaryValue());
-  status->SetDouble("percentFull", percent_full);
-  status->SetInteger("approximateEventCount", approximate_event_count);
+  base::DictionaryValue status;
+  status.SetDouble("percentFull", percent_full);
+  status.SetInteger("approximateEventCount", approximate_event_count);
 
   std::string status_json;
-  base::JSONWriter::Write(status.get(), &status_json);
+  base::JSONWriter::Write(status, &status_json);
 
   base::RefCountedString* status_base64 = new base::RefCountedString();
   base::Base64Encode(status_json, &status_base64->data());
@@ -177,18 +177,17 @@
   TracingController::GetInstance()->GetMonitoringStatus(
       &is_monitoring, &category_filter, &options);
 
-  scoped_ptr<base::DictionaryValue>
-    monitoring_options(new base::DictionaryValue());
-  monitoring_options->SetBoolean("isMonitoring", is_monitoring);
-  monitoring_options->SetString("categoryFilter", category_filter.ToString());
-  monitoring_options->SetBoolean("useSystemTracing", options.enable_systrace);
-  monitoring_options->SetBoolean(
+  base::DictionaryValue monitoring_options;
+  monitoring_options.SetBoolean("isMonitoring", is_monitoring);
+  monitoring_options.SetString("categoryFilter", category_filter.ToString());
+  monitoring_options.SetBoolean("useSystemTracing", options.enable_systrace);
+  monitoring_options.SetBoolean(
       "useContinuousTracing",
       options.record_mode == base::trace_event::RECORD_CONTINUOUSLY);
-  monitoring_options->SetBoolean("useSampling", options.enable_sampling);
+  monitoring_options.SetBoolean("useSampling", options.enable_sampling);
 
   std::string monitoring_options_json;
-  base::JSONWriter::Write(monitoring_options.get(), &monitoring_options_json);
+  base::JSONWriter::Write(monitoring_options, &monitoring_options_json);
 
   base::RefCountedString* monitoring_options_base64 =
     new base::RefCountedString();
diff --git a/content/browser/web_contents/web_contents_android.cc b/content/browser/web_contents/web_contents_android.cc
index 7600035..dc23623c 100644
--- a/content/browser/web_contents/web_contents_android.cc
+++ b/content/browser/web_contents/web_contents_android.cc
@@ -46,7 +46,7 @@
                               const base::Value* result) {
   JNIEnv* env = base::android::AttachCurrentThread();
   std::string json;
-  base::JSONWriter::Write(result, &json);
+  base::JSONWriter::Write(*result, &json);
   ScopedJavaLocalRef<jstring> j_json = ConvertUTF8ToJavaString(env, json);
   Java_WebContentsImpl_onEvaluateJavaScriptResult(
       env, j_json.obj(), callback.obj());
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 269b4716..d8bdf924 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -3347,14 +3347,6 @@
   FOR_EACH_OBSERVER(WebContentsObserver, observers_,
                     RenderViewHostChanged(old_host, new_host));
 
-  // TODO(avi): Remove. http://crbug.com/170921
-  std::pair<RenderViewHost*, RenderViewHost*> details =
-      std::make_pair(old_host, new_host);
-  NotificationService::current()->Notify(
-      NOTIFICATION_RENDER_VIEW_HOST_CHANGED,
-      Source<WebContents>(this),
-      Details<std::pair<RenderViewHost*, RenderViewHost*> >(&details));
-
   // Ensure that the associated embedder gets cleared after a RenderViewHost
   // gets swapped, so we don't reuse the same embedder next time a
   // RenderViewHost is attached to this WebContents.
diff --git a/content/browser/webui/web_ui_impl.cc b/content/browser/webui/web_ui_impl.cc
index a9194a9..1f953a2 100644
--- a/content/browser/webui/web_ui_impl.cc
+++ b/content/browser/webui/web_ui_impl.cc
@@ -36,7 +36,7 @@
     if (i > 0)
       parameters += base::char16(',');
 
-    base::JSONWriter::Write(arg_list[i], &json);
+    base::JSONWriter::Write(*arg_list[i], &json);
     parameters += base::UTF8ToUTF16(json);
   }
   return base::ASCIIToUTF16(function_name) +
diff --git a/content/child/DEPS b/content/child/DEPS
index 6670427..f677068 100644
--- a/content/child/DEPS
+++ b/content/child/DEPS
@@ -9,6 +9,6 @@
 
   "+content/app/strings/grit",  # For generated headers
   "+content/public/child",
-  "+media/base/android",
+  "+media/base",
   "+v8/include/v8.h"
 ]
diff --git a/content/child/assert_matching_enums.cc b/content/child/assert_matching_enums.cc
index 0d087ed..0fc87bf 100644
--- a/content/child/assert_matching_enums.cc
+++ b/content/child/assert_matching_enums.cc
@@ -8,7 +8,7 @@
 #include "base/macros.h"
 #include "cc/animation/animation.h"
 #include "content/public/common/screen_orientation_values.h"
-#include "net/base/mime_util.h"
+#include "media/base/mime_util.h"
 #include "third_party/WebKit/public/platform/WebCompositorAnimation.h"
 #include "third_party/WebKit/public/platform/WebMimeRegistry.h"
 #include "third_party/WebKit/public/platform/WebScreenOrientationLockType.h"
@@ -40,11 +40,11 @@
 
 // SupportsType
 STATIC_ASSERT_MATCHING_ENUM(blink::WebMimeRegistry::IsNotSupported,
-    net::IsNotSupported);
+    media::IsNotSupported);
 STATIC_ASSERT_MATCHING_ENUM(blink::WebMimeRegistry::IsSupported,
-    net::IsSupported);
+    media::IsSupported);
 STATIC_ASSERT_MATCHING_ENUM(blink::WebMimeRegistry::MayBeSupported,
-    net::MayBeSupported);
+    media::MayBeSupported);
 
 // TargetProperty
 STATIC_ASSERT_MATCHING_ENUM(
diff --git a/content/child/background_sync/background_sync_provider.cc b/content/child/background_sync/background_sync_provider.cc
index 3a445d8..cdf0353 100644
--- a/content/child/background_sync/background_sync_provider.cc
+++ b/content/child/background_sync/background_sync_provider.cc
@@ -213,6 +213,7 @@
                             registrations[i]).release();
       }
       callbacks->onSuccess(results);
+      break;
     case BACKGROUND_SYNC_ERROR_NOT_FOUND:
       // This error should never be returned from
       // BackgroundSyncManager::GetRegistrations
diff --git a/content/child/background_sync/background_sync_provider_thread_proxy.cc b/content/child/background_sync/background_sync_provider_thread_proxy.cc
index 2361c4b..378c45c 100644
--- a/content/child/background_sync/background_sync_provider_thread_proxy.cc
+++ b/content/child/background_sync/background_sync_provider_thread_proxy.cc
@@ -40,7 +40,7 @@
     WorkerTaskRunner::Instance()->PostTask(
         worker_thread_id_,
         base::Bind(&blink::WebCallbacks<S, T>::onSuccess,
-                   base::Unretained(callbacks_.get()), results));
+                   base::Owned(callbacks_.release()), results));
   }
 
   virtual void onError(T* error) {
@@ -49,7 +49,7 @@
     WorkerTaskRunner::Instance()->PostTask(
         worker_thread_id_,
         base::Bind(&blink::WebCallbacks<S, T>::onError,
-                   base::Unretained(callbacks_.get()), error));
+                   base::Owned(callbacks_.release()), error));
   }
 
  private:
diff --git a/content/common/frame_messages.h b/content/common/frame_messages.h
index 5271e4e1..8fa0063 100644
--- a/content/common/frame_messages.h
+++ b/content/common/frame_messages.h
@@ -61,12 +61,14 @@
   IPC_STRUCT_TRAITS_MEMBER(unfiltered_link_url)
   IPC_STRUCT_TRAITS_MEMBER(src_url)
   IPC_STRUCT_TRAITS_MEMBER(has_image_contents)
+  IPC_STRUCT_TRAITS_MEMBER(properties)
   IPC_STRUCT_TRAITS_MEMBER(page_url)
   IPC_STRUCT_TRAITS_MEMBER(keyword_url)
   IPC_STRUCT_TRAITS_MEMBER(frame_url)
   IPC_STRUCT_TRAITS_MEMBER(frame_page_state)
   IPC_STRUCT_TRAITS_MEMBER(media_flags)
   IPC_STRUCT_TRAITS_MEMBER(selection_text)
+  IPC_STRUCT_TRAITS_MEMBER(title_text)
   IPC_STRUCT_TRAITS_MEMBER(suggested_filename)
   IPC_STRUCT_TRAITS_MEMBER(misspelled_word)
   IPC_STRUCT_TRAITS_MEMBER(misspelling_hash)
diff --git a/content/common/gpu/client/context_provider_command_buffer.cc b/content/common/gpu/client/context_provider_command_buffer.cc
index 2f00de1..58e34b64 100644
--- a/content/common/gpu/client/context_provider_command_buffer.cc
+++ b/content/common/gpu/client/context_provider_command_buffer.cc
@@ -137,7 +137,7 @@
   gr_context_.reset(new GrContextForWebGraphicsContext3D(context3d_.get()));
 
   // If GlContext is already lost, also abandon the new GrContext.
-  if (IsContextLost())
+  if (gr_context_->get() && IsContextLost())
     gr_context_->get()->abandonContext();
 
   return gr_context_->get();
diff --git a/content/common/gpu/gpu_command_buffer_stub.cc b/content/common/gpu/gpu_command_buffer_stub.cc
index 5c878fca..bb4044a 100644
--- a/content/common/gpu/gpu_command_buffer_stub.cc
+++ b/content/common/gpu/gpu_command_buffer_stub.cc
@@ -118,7 +118,7 @@
 
   void AppendAsTraceFormat(std::string* out) const override {
     std::string tmp;
-    base::JSONWriter::Write(value_.get(), &tmp);
+    base::JSONWriter::Write(*value_, &tmp);
     *out += tmp;
   }
 
diff --git a/content/common/origin_util_unittest.cc b/content/common/origin_util_unittest.cc
index 2991a9d9..49598f65 100644
--- a/content/common/origin_util_unittest.cc
+++ b/content/common/origin_util_unittest.cc
@@ -20,6 +20,12 @@
   EXPECT_FALSE(IsOriginSecure(GURL("ws://example.com/fun.html")));
 
   EXPECT_TRUE(IsOriginSecure(GURL("http://localhost/fun.html")));
+  EXPECT_TRUE(IsOriginSecure(GURL("http://pumpkin.localhost/fun.html")));
+  EXPECT_TRUE(
+      IsOriginSecure(GURL("http://crumpet.pumpkin.localhost/fun.html")));
+  EXPECT_TRUE(IsOriginSecure(GURL("http://pumpkin.localhost:8080/fun.html")));
+  EXPECT_TRUE(
+      IsOriginSecure(GURL("http://crumpet.pumpkin.localhost:3000/fun.html")));
   EXPECT_FALSE(IsOriginSecure(GURL("http://localhost.com/fun.html")));
   EXPECT_TRUE(IsOriginSecure(GURL("https://localhost.com/fun.html")));
 
diff --git a/content/content_browser.gypi b/content/content_browser.gypi
index c3c9dcd..63fef96 100644
--- a/content/content_browser.gypi
+++ b/content/content_browser.gypi
@@ -91,7 +91,6 @@
       'public/browser/browser_plugin_guest_manager.cc',
       'public/browser/browser_plugin_guest_manager.h',
       'public/browser/browser_ppapi_host.h',
-      'public/browser/browser_shutdown.h',
       'public/browser/browser_thread.h',
       'public/browser/browser_thread_delegate.h',
       'public/browser/browser_url_handler.h',
@@ -974,6 +973,8 @@
       'browser/media/capture/animated_content_sampler.h',
       'browser/media/capture/audio_mirroring_manager.cc',
       'browser/media/capture/audio_mirroring_manager.h',
+      'browser/media/capture/capture_resolution_chooser.cc',
+      'browser/media/capture/capture_resolution_chooser.h',
       'browser/media/capture/content_video_capture_device_core.cc',
       'browser/media/capture/content_video_capture_device_core.h',
       'browser/media/capture/feedback_signal_accumulator.cc',
diff --git a/content/content_renderer.gypi b/content/content_renderer.gypi
index f6a9eee..52ce045 100644
--- a/content/content_renderer.gypi
+++ b/content/content_renderer.gypi
@@ -561,11 +561,6 @@
       'renderer/pepper/url_request_info_util.h',
       'renderer/pepper/url_response_info_util.cc',
       'renderer/pepper/url_response_info_util.h',
-      'renderer/pepper/usb_key_code_conversion.cc',
-      'renderer/pepper/usb_key_code_conversion.h',
-      'renderer/pepper/usb_key_code_conversion_linux.cc',
-      'renderer/pepper/usb_key_code_conversion_mac.cc',
-      'renderer/pepper/usb_key_code_conversion_win.cc',
       'renderer/pepper/v8_var_converter.cc',
       'renderer/pepper/v8_var_converter.h',
       'renderer/pepper/v8object_var.cc',
diff --git a/content/content_shell.gypi b/content/content_shell.gypi
index 65ca72b..08e1ca0 100644
--- a/content/content_shell.gypi
+++ b/content/content_shell.gypi
@@ -1119,6 +1119,7 @@
     ['OS=="win"', {
       'targets': [
         {
+          # GN version: //content/shell:crash_service
           'target_name': 'content_shell_crash_service',
           'type': 'executable',
           'dependencies': [
diff --git a/content/content_tests.gypi b/content/content_tests.gypi
index 61bdc91..82b1554a 100644
--- a/content/content_tests.gypi
+++ b/content/content_tests.gypi
@@ -471,6 +471,7 @@
       'browser/media/audio_stream_monitor_unittest.cc',
       'browser/media/capture/animated_content_sampler_unittest.cc',
       'browser/media/capture/audio_mirroring_manager_unittest.cc',
+      'browser/media/capture/capture_resolution_chooser_unittest.cc',
       'browser/media/capture/feedback_signal_accumulator_unittest.cc',
       'browser/media/capture/smooth_event_sampler_unittest.cc',
       'browser/media/capture/video_capture_oracle_unittest.cc',
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeChildFrameTest.java b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeChildFrameTest.java
index 2d494d0..40ea4ae 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeChildFrameTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeChildFrameTest.java
@@ -13,6 +13,10 @@
 import org.chromium.content_public.browser.NavigationController;
 import org.chromium.content_public.browser.WebContents;
 
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
 /**
  * Part of the test suite for the WebView's Java Bridge.
  *
@@ -105,6 +109,63 @@
                         "queryProperties(window.frames[0])"));
     }
 
+    // Regression test for crbug.com/484927 -- make sure that existence of transient
+    // objects held by multiple RenderFrames doesn't cause an infinite loop when one
+    // of them gets removed.
+    @SmallTest
+    @Feature({"AndroidWebView", "Android-JavaBridge"})
+    public void testRemovingTransientObjectHolders() throws Throwable {
+        class Test {
+            private Object mInner = new Object();
+            // Expecting the inner object to be retrieved twice.
+            private CountDownLatch mLatch = new CountDownLatch(2);
+            @JavascriptInterface
+            public Object getInner() {
+                mLatch.countDown();
+                return mInner;
+            }
+            public void waitForInjection() throws Throwable {
+                if (!mLatch.await(5, TimeUnit.SECONDS)) {
+                    throw new TimeoutException();
+                }
+            }
+        }
+        final Test testObject = new Test();
+
+        // Due to crbug.com/486262, Java objects are sometimes not injected
+        // into newly added frames. To work around this, we load the page first, so
+        // all the frames got created, then inject the object.
+        // Thus, the script code fails on the first execution (as no Java object is
+        // injected yet), but then works just fine after reload.
+        loadDataSync(getWebContents().getNavigationController(),
+                "<html>"
+                + "<head><script>window.inner_ref = test.getInner()</script></head>"
+                + "<body>"
+                + "   <iframe id='frame' "
+                + "       srcdoc='<script>window.inner_ref = test.getInner()</script>'>"
+                + "   </iframe>"
+                + "</body></html>", "text/html", false);
+        injectObjectAndReload(testObject, "test");
+        testObject.waitForInjection();
+        // Just in case, check that the object wrappers are in place.
+        assertEquals("\"object\"",
+                executeJavaScriptAndGetResult(getWebContents(), "typeof inner_ref"));
+        assertEquals("\"object\"",
+                executeJavaScriptAndGetResult(getWebContents(),
+                        "typeof window.frames[0].inner_ref"));
+        // Remove the iframe, this will trigger a removal of RenderFrame, which was causing
+        // the bug condition, as the transient object still has a holder -- the main window.
+        assertEquals("{}",
+                executeJavaScriptAndGetResult(getWebContents(),
+                        "(function(){ "
+                        + "var f = document.getElementById('frame');"
+                        + "f.parentNode.removeChild(f); return f; })()"));
+        // Just in case, check that the remaining wrapper is still accessible.
+        assertEquals("\"object\"",
+                executeJavaScriptAndGetResult(getWebContents(),
+                        "typeof inner_ref"));
+    }
+
     private String executeJavaScriptAndGetResult(final WebContents webContents,
             final String script) throws Throwable {
         final String[] result = new String[1];
diff --git a/content/public/browser/browser_shutdown.h b/content/public/browser/browser_shutdown.h
deleted file mode 100644
index 7581533..0000000
--- a/content/public/browser/browser_shutdown.h
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright (c) 2012 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_PUBLIC_BROWSER_BROWSER_SHUTDOWN_H_
-#define CONTENT_PUBLIC_BROWSER_BROWSER_SHUTDOWN_H_
-
-#include "content/common/content_export.h"
-
-namespace content {
-
-// This can be used for as-fast-as-possible shutdown, in cases where
-// time for shutdown is limited and we just need to write out as much
-// data as possible before our time runs out.
-//
-// This causes the shutdown sequence embodied by
-// BrowserMainParts::PostMainMessageLoopRun through
-// BrowserMainParts::PostDestroyThreads to occur, i.e. we pretend the
-// message loop finished, all threads are stopped in sequence and then
-// PostDestroyThreads is called.
-//
-// As this violates the normal order of shutdown, likely leaving the
-// process in a bad state, the last thing this function does is
-// terminate the process (right after calling
-// BrowserMainParts::PostDestroyThreads).
-CONTENT_EXPORT void ImmediateShutdownAndExitProcess();
-
-}  // namespace content
-
-#endif  // CONTENT_PUBLIC_BROWSER_BROWSER_SHUTDOWN_H_
diff --git a/content/public/browser/notification_types.h b/content/public/browser/notification_types.h
index 08ffd33..a7043153 100644
--- a/content/public/browser/notification_types.h
+++ b/content/public/browser/notification_types.h
@@ -112,13 +112,6 @@
   // DEPRECATED: Use WebContentsObserver::RenderViewReady()
   NOTIFICATION_WEB_CONTENTS_CONNECTED,
 
-  // This notification is sent when a WebContents swaps its render view host
-  // with another one, possibly changing processes. The source is a
-  // Source<WebContents> with a pointer to the WebContents, details is a
-  // std::pair::<old RenderViewHost, new RenderViewHost>.
-  // DEPRECATED: Use WebContentsObserver::RenderViewHostChanged()
-  NOTIFICATION_RENDER_VIEW_HOST_CHANGED,
-
   // This message is sent after a WebContents is disconnected from the
   // renderer process.  The source is a Source<WebContents> with a pointer to
   // the WebContents (the pointer is usable).  No details are expected.
diff --git a/content/public/common/context_menu_params.h b/content/public/common/context_menu_params.h
index 9fe170a0..e45ad0a 100644
--- a/content/public/common/context_menu_params.h
+++ b/content/public/common/context_menu_params.h
@@ -5,6 +5,7 @@
 #ifndef CONTENT_PUBLIC_COMMON_CONTEXT_MENU_PARAMS_H_
 #define CONTENT_PUBLIC_COMMON_CONTEXT_MENU_PARAMS_H_
 
+#include <map>
 #include <string>
 #include <vector>
 
@@ -104,6 +105,10 @@
   // This is the text of the selection that the context menu was invoked on.
   base::string16 selection_text;
 
+  // This is the title or alt (if title not available) text of the selection
+  // that the context menu was invoked on.
+  base::string16 title_text;
+
   // This is the suggested filename to be used when saving file through "Save
   // Link As" option of context menu.
   base::string16 suggested_filename;
@@ -151,6 +156,9 @@
 
   ui::MenuSourceType source_type;
 
+  // Extra properties for the context menu.
+  std::map<std::string, std::string> properties;
+
 #if defined(OS_ANDROID)
   // Points representing the coordinates in the document space of the start and
   // end of the selection, if there is one.
diff --git a/content/public/renderer/content_renderer_client.h b/content/public/renderer/content_renderer_client.h
index 9e1e7d7..1d4a47e 100644
--- a/content/public/renderer/content_renderer_client.h
+++ b/content/public/renderer/content_renderer_client.h
@@ -5,6 +5,7 @@
 #ifndef CONTENT_PUBLIC_RENDERER_CONTENT_RENDERER_CLIENT_H_
 #define CONTENT_PUBLIC_RENDERER_CONTENT_RENDERER_CLIENT_H_
 
+#include <map>
 #include <string>
 #include <vector>
 
@@ -47,6 +48,7 @@
 class WebSpeechSynthesizer;
 class WebSpeechSynthesizerClient;
 class WebThemeEngine;
+class WebURLResponse;
 class WebURLRequest;
 class WebWorkerContentSettingsClientProxy;
 struct WebPluginParams;
@@ -305,6 +307,12 @@
   // Allows an embedder to provide a blink::WebAppBannerClient.
   virtual scoped_ptr<blink::WebAppBannerClient> CreateAppBannerClient(
       RenderFrame* render_frame);
+
+  // Gives the embedder a chance to add properties to the context menu.
+  // Currently only called when the context menu is for an image.
+  virtual void AddImageContextMenuProperties(
+      const blink::WebURLResponse& response,
+      std::map<std::string, std::string>* properties) {}
 };
 
 }  // namespace content
diff --git a/content/public/test/browser_test_utils.cc b/content/public/test/browser_test_utils.cc
index 4132af4..9513d0e 100644
--- a/content/public/test/browser_test_utils.cc
+++ b/content/public/test/browser_test_utils.cc
@@ -43,6 +43,7 @@
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/compositor/test/draw_waiter_for_test.h"
 #include "ui/events/gesture_detection/gesture_configuration.h"
+#include "ui/events/keycodes/dom/dom_code.h"
 #include "ui/events/keycodes/dom/keycode_converter.h"
 #include "ui/resources/grit/webui_resources.h"
 
@@ -445,7 +446,8 @@
                               bool shift,
                               bool alt,
                               bool command) {
-  int native_key_code = ui::KeycodeConverter::CodeToNativeKeycode(code);
+  int native_key_code = ui::KeycodeConverter::DomCodeToNativeKeycode(
+      ui::KeycodeConverter::CodeStringToDomCode(code));
 
   int modifiers = 0;
 
@@ -453,96 +455,75 @@
   // For our simulation we can use either the left keys or the right keys.
   if (control) {
     modifiers |= blink::WebInputEvent::ControlKey;
-    InjectRawKeyEvent(web_contents,
-                      blink::WebInputEvent::RawKeyDown,
-                      ui::VKEY_CONTROL,
-                      ui::KeycodeConverter::CodeToNativeKeycode("ControlLeft"),
-                      modifiers);
+    InjectRawKeyEvent(
+        web_contents, blink::WebInputEvent::RawKeyDown, ui::VKEY_CONTROL,
+        ui::KeycodeConverter::DomCodeToNativeKeycode(ui::DomCode::CONTROL_LEFT),
+        modifiers);
   }
 
   if (shift) {
     modifiers |= blink::WebInputEvent::ShiftKey;
-    InjectRawKeyEvent(web_contents,
-                      blink::WebInputEvent::RawKeyDown,
-                      ui::VKEY_SHIFT,
-                      ui::KeycodeConverter::CodeToNativeKeycode("ShiftLeft"),
-                      modifiers);
+    InjectRawKeyEvent(
+        web_contents, blink::WebInputEvent::RawKeyDown, ui::VKEY_SHIFT,
+        ui::KeycodeConverter::DomCodeToNativeKeycode(ui::DomCode::SHIFT_LEFT),
+        modifiers);
   }
 
   if (alt) {
     modifiers |= blink::WebInputEvent::AltKey;
-    InjectRawKeyEvent(web_contents,
-                      blink::WebInputEvent::RawKeyDown,
-                      ui::VKEY_MENU,
-                      ui::KeycodeConverter::CodeToNativeKeycode("AltLeft"),
-                      modifiers);
+    InjectRawKeyEvent(
+        web_contents, blink::WebInputEvent::RawKeyDown, ui::VKEY_MENU,
+        ui::KeycodeConverter::DomCodeToNativeKeycode(ui::DomCode::ALT_LEFT),
+        modifiers);
   }
 
   if (command) {
     modifiers |= blink::WebInputEvent::MetaKey;
-    InjectRawKeyEvent(web_contents,
-                      blink::WebInputEvent::RawKeyDown,
-                      ui::VKEY_COMMAND,
-                      ui::KeycodeConverter::CodeToNativeKeycode("OSLeft"),
-                      modifiers);
+    InjectRawKeyEvent(
+        web_contents, blink::WebInputEvent::RawKeyDown, ui::VKEY_COMMAND,
+        ui::KeycodeConverter::DomCodeToNativeKeycode(ui::DomCode::OS_LEFT),
+        modifiers);
   }
+  InjectRawKeyEvent(web_contents, blink::WebInputEvent::RawKeyDown, key_code,
+                    native_key_code, modifiers);
 
-  InjectRawKeyEvent(
-      web_contents,
-      blink::WebInputEvent::RawKeyDown,
-      key_code,
-      native_key_code,
-      modifiers);
+  InjectRawKeyEvent(web_contents, blink::WebInputEvent::Char, key_code,
+                    native_key_code, modifiers);
 
-  InjectRawKeyEvent(
-      web_contents,
-      blink::WebInputEvent::Char,
-      key_code,
-      native_key_code,
-      modifiers);
-
-  InjectRawKeyEvent(
-      web_contents,
-      blink::WebInputEvent::KeyUp,
-      key_code,
-      native_key_code,
-      modifiers);
+  InjectRawKeyEvent(web_contents, blink::WebInputEvent::KeyUp, key_code,
+                    native_key_code, modifiers);
 
   // The order of these key releases shouldn't matter for our simulation.
   if (control) {
     modifiers &= ~blink::WebInputEvent::ControlKey;
-    InjectRawKeyEvent(web_contents,
-                      blink::WebInputEvent::KeyUp,
-                      ui::VKEY_CONTROL,
-                      ui::KeycodeConverter::CodeToNativeKeycode("ControlLeft"),
-                      modifiers);
+    InjectRawKeyEvent(
+        web_contents, blink::WebInputEvent::KeyUp, ui::VKEY_CONTROL,
+        ui::KeycodeConverter::DomCodeToNativeKeycode(ui::DomCode::CONTROL_LEFT),
+        modifiers);
   }
 
   if (shift) {
     modifiers &= ~blink::WebInputEvent::ShiftKey;
-    InjectRawKeyEvent(web_contents,
-                      blink::WebInputEvent::KeyUp,
-                      ui::VKEY_SHIFT,
-                      ui::KeycodeConverter::CodeToNativeKeycode("ShiftLeft"),
-                      modifiers);
+    InjectRawKeyEvent(
+        web_contents, blink::WebInputEvent::KeyUp, ui::VKEY_SHIFT,
+        ui::KeycodeConverter::DomCodeToNativeKeycode(ui::DomCode::SHIFT_LEFT),
+        modifiers);
   }
 
   if (alt) {
     modifiers &= ~blink::WebInputEvent::AltKey;
-    InjectRawKeyEvent(web_contents,
-                      blink::WebInputEvent::KeyUp,
-                      ui::VKEY_MENU,
-                      ui::KeycodeConverter::CodeToNativeKeycode("AltLeft"),
-                      modifiers);
+    InjectRawKeyEvent(
+        web_contents, blink::WebInputEvent::KeyUp, ui::VKEY_MENU,
+        ui::KeycodeConverter::DomCodeToNativeKeycode(ui::DomCode::ALT_LEFT),
+        modifiers);
   }
 
   if (command) {
     modifiers &= ~blink::WebInputEvent::MetaKey;
-    InjectRawKeyEvent(web_contents,
-                      blink::WebInputEvent::KeyUp,
-                      ui::VKEY_COMMAND,
-                      ui::KeycodeConverter::CodeToNativeKeycode("OSLeft"),
-                      modifiers);
+    InjectRawKeyEvent(
+        web_contents, blink::WebInputEvent::KeyUp, ui::VKEY_COMMAND,
+        ui::KeycodeConverter::DomCodeToNativeKeycode(ui::DomCode::OS_LEFT),
+        modifiers);
   }
 
   ASSERT_EQ(modifiers, 0);
diff --git a/content/renderer/context_menu_params_builder.cc b/content/renderer/context_menu_params_builder.cc
index 63dcd4d..1e4df2e 100644
--- a/content/renderer/context_menu_params_builder.cc
+++ b/content/renderer/context_menu_params_builder.cc
@@ -7,6 +7,7 @@
 #include "base/logging.h"
 #include "content/common/ssl_status_serialization.h"
 #include "content/public/common/context_menu_params.h"
+#include "content/public/renderer/content_renderer_client.h"
 #include "content/renderer/dom_utils.h"
 #include "content/renderer/history_serialization.h"
 #include "content/renderer/menu_item_builder.h"
@@ -31,6 +32,7 @@
   params.frame_url = data.frameURL;
   params.media_flags = data.mediaFlags;
   params.selection_text = data.selectedText;
+  params.title_text = data.titleText;
   params.misspelled_word = data.misspelledWord;
   params.misspelling_hash = data.misspellingHash;
   params.spellcheck_enabled = data.isSpellCheckingEnabled;
@@ -43,6 +45,11 @@
   params.referrer_policy = data.referrerPolicy;
   params.suggested_filename = data.suggestedFilename;
 
+  if (!data.imageResponse.isNull()) {
+    GetContentClient()->renderer()->AddImageContextMenuProperties(
+        data.imageResponse, &params.properties);
+  }
+
   for (size_t i = 0; i < data.dictionarySuggestions.size(); ++i)
     params.dictionary_suggestions.push_back(data.dictionarySuggestions[i]);
 
@@ -59,7 +66,7 @@
     blink::WebNode selectedNode = DomUtils::ExtractParentAnchorNode(data.node);
     blink::WebElement selectedElement = selectedNode.to<blink::WebElement>();
     if (!selectedElement.isNull() && selectedNode.isLink()) {
-      params.link_text = selectedElement.innerText();
+      params.link_text = selectedElement.textContent();
     } else {
       LOG(ERROR) << "Creating a ContextMenuParams for a node that has a link"
                  << "url but is not an ElementNode or does not have an"
diff --git a/content/renderer/dom_serializer_browsertest.cc b/content/renderer/dom_serializer_browsertest.cc
index b1759421..2cb395c 100644
--- a/content/renderer/dom_serializer_browsertest.cc
+++ b/content/renderer/dom_serializer_browsertest.cc
@@ -582,8 +582,9 @@
       '%', 0x2285, 0x00b9, '\'', 0
     };
     WebString value = body_element.getAttribute("title");
+    WebString content = doc.contentAsTextForTesting();
     ASSERT_TRUE(base::UTF16ToWide(value) == parsed_value);
-    ASSERT_TRUE(base::UTF16ToWide(body_element.innerText()) == parsed_value);
+    ASSERT_TRUE(base::UTF16ToWide(content) == parsed_value);
 
     // Do serialization.
     SerializeDomForURL(file_url, false);
diff --git a/content/renderer/gpu/frame_swap_message_queue.cc b/content/renderer/gpu/frame_swap_message_queue.cc
index 5a31382..84fcdd4e 100644
--- a/content/renderer/gpu/frame_swap_message_queue.cc
+++ b/content/renderer/gpu/frame_swap_message_queue.cc
@@ -146,13 +146,17 @@
   GetSubQueue(policy)->QueueMessage(source_frame_number, msg.Pass(), is_first);
 }
 
-void FrameSwapMessageQueue::DidSwap(int source_frame_number) {
+void FrameSwapMessageQueue::DidActivate(int source_frame_number) {
   base::AutoLock lock(lock_);
-
   visual_state_queue_->DrainMessages(source_frame_number,
                                      &next_drain_messages_);
 }
 
+void FrameSwapMessageQueue::DidSwap(int source_frame_number) {
+  base::AutoLock lock(lock_);
+  swap_queue_->DrainMessages(0, &next_drain_messages_);
+}
+
 void FrameSwapMessageQueue::DidNotSwap(int source_frame_number,
                                        cc::SwapPromise::DidNotSwapReason reason,
                                        ScopedVector<IPC::Message>* messages) {
@@ -164,21 +168,18 @@
       visual_state_queue_->DrainMessages(source_frame_number, messages);
       break;
     case cc::SwapPromise::COMMIT_FAILS:
-      // Do not queue any responses here.
-      // If COMMIT_FAILS the renderer is shutting down, which will
-      // result in the RenderFrameHostImpl destructor firing the
-      // remaining response callbacks itself.
+    case cc::SwapPromise::ACTIVATION_FAILS:
+      // Do not queue any responses here. If ACTIVATION_FAILS or
+      // COMMIT_FAILS the renderer is shutting down, which will result
+      // in the RenderFrameHostImpl destructor firing the remaining
+      // response callbacks itself.
       break;
-    default:
-      NOTREACHED();
   }
 }
 
 void FrameSwapMessageQueue::DrainMessages(
     ScopedVector<IPC::Message>* messages) {
   lock_.AssertAcquired();
-
-  swap_queue_->DrainMessages(0, messages);
   messages->insert(messages->end(),
                    next_drain_messages_.begin(),
                    next_drain_messages_.end());
diff --git a/content/renderer/gpu/frame_swap_message_queue.h b/content/renderer/gpu/frame_swap_message_queue.h
index 51eb229e..b12b417 100644
--- a/content/renderer/gpu/frame_swap_message_queue.h
+++ b/content/renderer/gpu/frame_swap_message_queue.h
@@ -52,14 +52,19 @@
   // Returns true if there are no messages in the queue.
   bool Empty() const;
 
-  // Should be called when a successful swap occurs. The messages for that swap
-  // can be obtained by calling DrainMessages.
+  // Should be called when a successful activation occurs. The messages for
+  // that activation can be obtained by calling DrainMessages.
+  //
+  // |source_frame_number| frame number for which the activate occurred.
+  void DidActivate(int source_frame_number);
+
+  // Should be called when a successful swap occurs. The messages for that
+  // swap can be obtained by calling DrainMessages.
   //
   // |source_frame_number| frame number for which the swap occurred.
   void DidSwap(int source_frame_number);
 
-  // Should be called when we know a swap will not occur. This also means we
-  // won't be expecting a DrainMessages call.
+  // Should be called when we know a swap will not occur.
   //
   // |source_frame_number| frame number for which the swap will not occur.
   // |reason| reason for the which the swap will not occur.
diff --git a/content/renderer/gpu/frame_swap_message_queue_unittest.cc b/content/renderer/gpu/frame_swap_message_queue_unittest.cc
index dc802c0..8040598 100644
--- a/content/renderer/gpu/frame_swap_message_queue_unittest.cc
+++ b/content/renderer/gpu/frame_swap_message_queue_unittest.cc
@@ -47,6 +47,7 @@
   void DrainMessages(int source_frame_number,
                      ScopedVector<IPC::Message>* messages) {
     messages->clear();
+    queue_->DidActivate(source_frame_number);
     queue_->DidSwap(source_frame_number);
     scoped_ptr<FrameSwapMessageQueue::SendMessageScope> send_message_scope =
         queue_->AcquireSendMessageScope();
@@ -92,6 +93,7 @@
   ASSERT_TRUE(queue_->Empty());
   QueueVisualStateMessage(1, CloneMessage(first_message_));
   ASSERT_FALSE(queue_->Empty());
+  queue_->DidActivate(1);
   queue_->DidSwap(1);
   ASSERT_FALSE(queue_->Empty());
 }
@@ -208,17 +210,31 @@
   QueueNextSwapMessage(CloneMessage(first_message_));
   QueueVisualStateMessage(2, CloneMessage(second_message_));
   QueueVisualStateMessage(3, CloneMessage(third_message_));
+  const int rid[] = {first_message_.routing_id(),
+                     second_message_.routing_id(),
+                     third_message_.routing_id()};
 
-  queue_->DidNotSwap(2, cc::SwapPromise::COMMIT_NO_UPDATE, &messages);
-  ASSERT_EQ(2u, messages.size());
-  ASSERT_TRUE(HasMessageForId(messages, first_message_.routing_id()));
-  ASSERT_TRUE(HasMessageForId(messages, second_message_.routing_id()));
+  bool msg_delivered = reason != cc::SwapPromise::COMMIT_FAILS &&
+                       reason != cc::SwapPromise::ACTIVATION_FAILS;
+
+  queue_->DidNotSwap(2, reason, &messages);
+  ASSERT_TRUE(msg_delivered == HasMessageForId(messages, rid[0]));
+  ASSERT_TRUE(msg_delivered == HasMessageForId(messages, rid[1]));
+  ASSERT_FALSE(HasMessageForId(messages, rid[2]));
   messages.clear();
 
-  queue_->DidNotSwap(3, cc::SwapPromise::COMMIT_NO_UPDATE, &messages);
-  ASSERT_EQ(1u, messages.size());
-  ASSERT_TRUE(HasMessageForId(messages, third_message_.routing_id()));
+  queue_->DidNotSwap(3, reason, &messages);
+  ASSERT_FALSE(HasMessageForId(messages, rid[0]));
+  ASSERT_FALSE(HasMessageForId(messages, rid[1]));
+  ASSERT_TRUE(msg_delivered == HasMessageForId(messages, rid[2]));
   messages.clear();
+
+  // all undelivered messages should still be available for RenderFrameHostImpl
+  // to deliver.
+  DrainMessages(3, &messages);
+  ASSERT_TRUE(msg_delivered != HasMessageForId(messages, rid[0]));
+  ASSERT_TRUE(msg_delivered != HasMessageForId(messages, rid[1]));
+  ASSERT_TRUE(msg_delivered != HasMessageForId(messages, rid[2]));
 }
 
 TEST_F(FrameSwapMessageQueueTest, TestDidNotSwapNoUpdate) {
@@ -230,23 +246,11 @@
 }
 
 TEST_F(FrameSwapMessageQueueTest, TestDidNotSwapCommitFails) {
-  ScopedVector<IPC::Message> messages;
+  TestDidNotSwap(cc::SwapPromise::COMMIT_FAILS);
+}
 
-  QueueNextSwapMessage(CloneMessage(first_message_));
-  QueueVisualStateMessage(2, CloneMessage(second_message_));
-  QueueVisualStateMessage(3, CloneMessage(third_message_));
-
-  queue_->DidNotSwap(2, cc::SwapPromise::COMMIT_FAILS, &messages);
-  ASSERT_EQ(0u, messages.size());
-  messages.clear();
-
-  queue_->DidNotSwap(3, cc::SwapPromise::COMMIT_FAILS, &messages);
-  ASSERT_EQ(0u, messages.size());
-  messages.clear();
-
-  DrainMessages(1, &messages);
-  ASSERT_EQ(1u, messages.size());
-  ASSERT_TRUE(HasMessageForId(messages, first_message_.routing_id()));
+TEST_F(FrameSwapMessageQueueTest, TestDidNotSwapActivationFails) {
+  TestDidNotSwap(cc::SwapPromise::ACTIVATION_FAILS);
 }
 
 class NotifiesDeletionMessage : public IPC::Message {
@@ -281,6 +285,7 @@
   QueueVisualStateMessage(1,
                           make_scoped_ptr(new NotifiesDeletionMessage(
                               &message_deleted, first_message_)));
+  queue_->DidActivate(1);
   queue_->DidSwap(1);
   queue_ = NULL;
   ASSERT_TRUE(message_deleted);
diff --git a/content/renderer/gpu/queue_message_swap_promise.cc b/content/renderer/gpu/queue_message_swap_promise.cc
index c8abf899..ff524418 100644
--- a/content/renderer/gpu/queue_message_swap_promise.cc
+++ b/content/renderer/gpu/queue_message_swap_promise.cc
@@ -32,6 +32,14 @@
 #endif
 }
 
+void QueueMessageSwapPromise::DidActivate() {
+#if DCHECK_IS_ON()
+  DCHECK(!completed_);
+#endif
+  message_queue_->DidActivate(source_frame_number_);
+  // The OutputSurface will take care of the Drain+Send.
+}
+
 void QueueMessageSwapPromise::DidSwap(cc::CompositorFrameMetadata* metadata) {
 #if DCHECK_IS_ON()
   DCHECK(!completed_);
diff --git a/content/renderer/gpu/queue_message_swap_promise.h b/content/renderer/gpu/queue_message_swap_promise.h
index e0fcf8c..37198b2 100644
--- a/content/renderer/gpu/queue_message_swap_promise.h
+++ b/content/renderer/gpu/queue_message_swap_promise.h
@@ -6,7 +6,6 @@
 #define CONTENT_RENDERER_GPU_QUEUE_MESSAGE_SWAP_PROMISE_H_
 
 #include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
 #include "cc/output/swap_promise.h"
 
 namespace IPC {
@@ -25,8 +24,8 @@
 
   ~QueueMessageSwapPromise() override;
 
+  void DidActivate() override;
   void DidSwap(cc::CompositorFrameMetadata* metadata) override;
-
   void DidNotSwap(DidNotSwapReason reason) override;
 
   int64 TraceId() const override;
diff --git a/content/renderer/gpu/queue_message_swap_promise_unittest.cc b/content/renderer/gpu/queue_message_swap_promise_unittest.cc
index ab640bf..1261cb2 100644
--- a/content/renderer/gpu/queue_message_swap_promise_unittest.cc
+++ b/content/renderer/gpu/queue_message_swap_promise_unittest.cc
@@ -115,8 +115,10 @@
     for (ScopedVector<cc::SwapPromise>::iterator i = promises_.begin();
          i != promises_.end();
          ++i) {
-      if (*i)
+      if (*i) {
+        (*i)->DidActivate();
         (*i)->DidSwap(NULL);
+      }
     }
   }
 
@@ -144,11 +146,13 @@
   QueueMessages(data, arraysize(data));
 
   ASSERT_TRUE(promises_[0]);
+  promises_[0]->DidActivate();
+  promises_[0]->DidSwap(NULL);
+
   EXPECT_TRUE(DirectSendMessages().empty());
   EXPECT_FALSE(frame_swap_message_queue_->Empty());
+  // frame_swap_message_queue_->DidSwap(1);
   EXPECT_TRUE(NextSwapHasMessage(messages_[0]));
-
-  CleanupPromises();
 }
 
 TEST_F(QueueMessageSwapPromiseTest, NextSwapPolicyNeedsAtMostOnePromise) {
@@ -201,6 +205,7 @@
   promises_[0]->DidNotSwap(cc::SwapPromise::COMMIT_FAILS);
   EXPECT_TRUE(DirectSendMessages().empty());
   EXPECT_FALSE(frame_swap_message_queue_->Empty());
+  frame_swap_message_queue_->DidSwap(2);
   EXPECT_TRUE(NextSwapHasMessage(messages_[0]));
 }
 
@@ -236,7 +241,7 @@
   CleanupPromises();
 }
 
-TEST_F(QueueMessageSwapPromiseTest, VisualStateSwapPromiseDidSwap) {
+TEST_F(QueueMessageSwapPromiseTest, VisualStateSwapPromiseDidActivate) {
   QueueMessageData data[] = {
     /* { policy, source_frame_number } */
     {MESSAGE_DELIVERY_POLICY_WITH_VISUAL_STATE, 1},
@@ -245,6 +250,7 @@
   };
   QueueMessages(data, arraysize(data));
 
+  promises_[0]->DidActivate();
   promises_[0]->DidSwap(NULL);
   ASSERT_FALSE(promises_[1]);
   ScopedVector<IPC::Message> messages;
@@ -254,7 +260,8 @@
   EXPECT_TRUE(ContainsMessage(messages, messages_[1]));
   EXPECT_FALSE(ContainsMessage(messages, messages_[2]));
 
-  promises_[2]->DidSwap(NULL);
+  promises_[2]->DidActivate();
+  promises_[2]->DidNotSwap(cc::SwapPromise::SWAP_FAILS);
   messages.swap(NextSwapMessages());
   EXPECT_EQ(1u, messages.size());
   EXPECT_TRUE(ContainsMessage(messages, messages_[2]));
@@ -274,59 +281,43 @@
   };
   QueueMessages(data, arraysize(data));
 
+  // If we fail to swap with COMMIT_FAILS or ACTIVATE_FAILS, then
+  // messages are delivered by the RenderFrameHostImpl destructor,
+  // rather than directly by the swap promise.
+  bool msg_delivered = reason != cc::SwapPromise::COMMIT_FAILS &&
+                       reason != cc::SwapPromise::ACTIVATION_FAILS;
+
   promises_[0]->DidNotSwap(reason);
   ASSERT_FALSE(promises_[1]);
   EXPECT_TRUE(NextSwapMessages().empty());
-  EXPECT_EQ(2u, DirectSendMessages().size());
-  EXPECT_TRUE(ContainsMessage(DirectSendMessages(), messages_[0]));
-  EXPECT_TRUE(ContainsMessage(DirectSendMessages(), messages_[1]));
+  EXPECT_EQ(msg_delivered, ContainsMessage(DirectSendMessages(), messages_[0]));
+  EXPECT_EQ(msg_delivered, ContainsMessage(DirectSendMessages(), messages_[1]));
   EXPECT_FALSE(ContainsMessage(DirectSendMessages(), messages_[2]));
 
   promises_[2]->DidNotSwap(reason);
   EXPECT_TRUE(NextSwapMessages().empty());
-  EXPECT_TRUE(ContainsMessage(DirectSendMessages(), messages_[2]));
+  EXPECT_EQ(msg_delivered, ContainsMessage(DirectSendMessages(), messages_[2]));
 
   EXPECT_TRUE(NextSwapMessages().empty());
-  EXPECT_TRUE(frame_swap_message_queue_->Empty());
+  EXPECT_EQ(msg_delivered, frame_swap_message_queue_->Empty());
 }
 
-TEST_F(QueueMessageSwapPromiseTest, VisalStateSwapPromiseDidNotSwapNoUpdate) {
+TEST_F(QueueMessageSwapPromiseTest, VisualStateSwapPromiseDidNotSwapNoUpdate) {
   VisualStateSwapPromiseDidNotSwap(cc::SwapPromise::COMMIT_NO_UPDATE);
 }
 
 TEST_F(QueueMessageSwapPromiseTest,
        VisualStateSwapPromiseDidNotSwapCommitFails) {
-  // COMMIT_FAILS is treated differently:
-  //    If we fail to swap with COMMIT_FAILS, then the renderer is
-  //    shutting down, which implies that the RenderFrameHostImpl
-  //    destructor will eventually be called, firing the remaining
-  //    response callbacks (with swap_success = false) itself.
-  QueueMessageData data[] = {
-    /* { policy, source_frame_number } */
-    {MESSAGE_DELIVERY_POLICY_WITH_VISUAL_STATE, 1},
-    {MESSAGE_DELIVERY_POLICY_WITH_VISUAL_STATE, 1},
-    {MESSAGE_DELIVERY_POLICY_WITH_VISUAL_STATE, 2},
-  };
-  QueueMessages(data, arraysize(data));
-
-  promises_[0]->DidNotSwap(cc::SwapPromise::COMMIT_FAILS);
-  ASSERT_FALSE(promises_[1]);
-  EXPECT_TRUE(NextSwapMessages().empty());
-  EXPECT_EQ(0u, DirectSendMessages().size());
-  EXPECT_FALSE(ContainsMessage(DirectSendMessages(), messages_[0]));
-  EXPECT_FALSE(ContainsMessage(DirectSendMessages(), messages_[1]));
-  EXPECT_FALSE(ContainsMessage(DirectSendMessages(), messages_[2]));
-
-  promises_[2]->DidNotSwap(cc::SwapPromise::COMMIT_FAILS);
-  EXPECT_TRUE(NextSwapMessages().empty());
-  EXPECT_FALSE(ContainsMessage(DirectSendMessages(), messages_[2]));
-
-  EXPECT_TRUE(NextSwapMessages().empty());
-  EXPECT_FALSE(frame_swap_message_queue_->Empty());
+  VisualStateSwapPromiseDidNotSwap(cc::SwapPromise::COMMIT_FAILS);
 }
 
-TEST_F(QueueMessageSwapPromiseTest, VisalStateSwapPromiseDidNotSwapSwapFails) {
+TEST_F(QueueMessageSwapPromiseTest, VisualStateSwapPromiseDidNotSwapSwapFails) {
   VisualStateSwapPromiseDidNotSwap(cc::SwapPromise::SWAP_FAILS);
 }
 
+TEST_F(QueueMessageSwapPromiseTest,
+       VisualStateSwapPromiseDidNotSwapActivationFails) {
+  VisualStateSwapPromiseDidNotSwap(cc::SwapPromise::ACTIVATION_FAILS);
+}
+
 }  // namespace content
diff --git a/content/renderer/media/crypto/ppapi_decryptor.cc b/content/renderer/media/crypto/ppapi_decryptor.cc
index 81abba65..b828de5 100644
--- a/content/renderer/media/crypto/ppapi_decryptor.cc
+++ b/content/renderer/media/crypto/ppapi_decryptor.cc
@@ -44,6 +44,7 @@
     base::MessageLoopProxy::current()->PostTask(
         FROM_HERE, base::Bind(cdm_created_cb, nullptr,
                               "Plugin instance creation failed."));
+    return;
   }
 
   scoped_ptr<PpapiDecryptor> ppapi_decryptor(
diff --git a/content/renderer/media/webrtc_audio_capturer.cc b/content/renderer/media/webrtc_audio_capturer.cc
index c59695a..df46265 100644
--- a/content/renderer/media/webrtc_audio_capturer.cc
+++ b/content/renderer/media/webrtc_audio_capturer.cc
@@ -14,6 +14,7 @@
 #include "content/renderer/media/media_stream_audio_processor.h"
 #include "content/renderer/media/media_stream_audio_processor_options.h"
 #include "content/renderer/media/media_stream_audio_source.h"
+#include "content/renderer/media/media_stream_constraints_util.h"
 #include "content/renderer/media/webrtc_audio_device_impl.h"
 #include "content/renderer/media/webrtc_local_audio_track.h"
 #include "content/renderer/media/webrtc_logging.h"
@@ -23,6 +24,11 @@
 
 namespace {
 
+// Audio buffer sizes are specified in milliseconds.
+const char kAudioLatency[] = "latencyMs";
+const int kMinAudioLatencyMs = 0;
+const int kMaxAudioLatencyMs = 10000;
+
 // Method to check if any of the data in |audio_source| has energy.
 bool HasDataEnergy(const media::AudioBus& audio_source) {
   for (int ch = 0; ch < audio_source.channels(); ++ch) {
@@ -89,7 +95,7 @@
   // Wrapper which allows to use std::find_if() when adding and removing
   // sinks to/from the list.
   struct TrackWrapper {
-    TrackWrapper(WebRtcLocalAudioTrack* track) : track_(track) {}
+    explicit TrackWrapper(WebRtcLocalAudioTrack* track) : track_(track) {}
     bool operator()(
         const scoped_refptr<WebRtcAudioCapturer::TrackOwner>& owner) const {
       return owner->IsEqual(track_);
@@ -199,10 +205,27 @@
                          device_info_.device.input.sample_rate);
   }
 
+  // Initialize the buffer size to zero, which means it wasn't specified.
+  // If it is out of range, we return it to zero.
+  int buffer_size_ms = 0;
+  int buffer_size_samples = 0;
+  GetConstraintValueAsInteger(constraints_, kAudioLatency, &buffer_size_ms);
+  if (buffer_size_ms < kMinAudioLatencyMs ||
+      buffer_size_ms > kMaxAudioLatencyMs) {
+    DVLOG(1) << "Ignoring out of range buffer size " << buffer_size_ms;
+  } else {
+    buffer_size_samples =
+        device_info_.device.input.sample_rate * buffer_size_ms / 1000;
+  }
+  DVLOG_IF(1, buffer_size_samples > 0)
+      << "Custom audio buffer size: " << buffer_size_samples << " samples";
+
   // Create and configure the default audio capturing source.
   SetCapturerSourceInternal(
-      AudioDeviceFactory::NewInputDevice(render_frame_id_), channel_layout,
-      static_cast<float>(device_info_.device.input.sample_rate));
+      AudioDeviceFactory::NewInputDevice(render_frame_id_),
+      channel_layout,
+      device_info_.device.input.sample_rate,
+      buffer_size_samples);
 
   // Add the capturer to the WebRtcAudioDeviceImpl since it needs some hardware
   // information from the capturer.
@@ -287,7 +310,8 @@
 void WebRtcAudioCapturer::SetCapturerSourceInternal(
     const scoped_refptr<media::AudioCapturerSource>& source,
     media::ChannelLayout channel_layout,
-    float sample_rate) {
+    int sample_rate,
+    int buffer_size) {
   DCHECK(thread_checker_.CalledOnValidThread());
   DVLOG(1) << "SetCapturerSource(channel_layout=" << channel_layout << ","
            << "sample_rate=" << sample_rate << ")";
@@ -308,15 +332,21 @@
   if (old_source.get())
     old_source->Stop();
 
+  // If the buffer size is zero, it has not been specified.
+  // We either default to 10ms, or use the hardware buffer size.
+  if (buffer_size == 0)
+    buffer_size = GetBufferSize(sample_rate);
+
   // Dispatch the new parameters both to the sink(s) and to the new source,
   // also apply the new |constraints|.
   // The idea is to get rid of any dependency of the microphone parameters
   // which would normally be used by default.
   // bits_per_sample is always 16 for now.
-  int buffer_size = GetBufferSize(sample_rate);
   media::AudioParameters params(media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
-                                channel_layout, sample_rate,
-                                16, buffer_size,
+                                channel_layout,
+                                sample_rate,
+                                16,
+                                buffer_size,
                                 device_info_.device.input.effects);
 
   {
@@ -365,7 +395,8 @@
   // WebRtc native buffer size.
   SetCapturerSourceInternal(AudioDeviceFactory::NewInputDevice(render_frame_id),
                             input_params.channel_layout(),
-                            static_cast<float>(input_params.sample_rate()));
+                            input_params.sample_rate(),
+                            0);
 }
 
 void WebRtcAudioCapturer::Start() {
@@ -588,8 +619,10 @@
     const scoped_refptr<media::AudioCapturerSource>& source,
     media::AudioParameters params) {
   // Create a new audio stream as source which uses the new source.
-  SetCapturerSourceInternal(source, params.channel_layout(),
-                            static_cast<float>(params.sample_rate()));
+  SetCapturerSourceInternal(source,
+                            params.channel_layout(),
+                            params.sample_rate(),
+                            0);
 }
 
 }  // namespace content
diff --git a/content/renderer/media/webrtc_audio_capturer.h b/content/renderer/media/webrtc_audio_capturer.h
index ca10ff2a..f1ada132 100644
--- a/content/renderer/media/webrtc_audio_capturer.h
+++ b/content/renderer/media/webrtc_audio_capturer.h
@@ -139,10 +139,12 @@
   // desires to provide their own captured audio data. Client is responsible
   // for calling Start() on its own source to get the ball rolling.
   // Called on the main render thread.
+  // buffer_size is optional. Set to 0 to let it be chosen automatically.
   void SetCapturerSourceInternal(
       const scoped_refptr<media::AudioCapturerSource>& source,
       media::ChannelLayout channel_layout,
-      float sample_rate);
+      int sample_rate,
+      int buffer_size);
 
   // Starts recording audio.
   // Triggered by AddSink() on the main render thread or a Libjingle working
diff --git a/content/renderer/pepper/event_conversion.cc b/content/renderer/pepper/event_conversion.cc
index 164e33e..becef7b 100644
--- a/content/renderer/pepper/event_conversion.cc
+++ b/content/renderer/pepper/event_conversion.cc
@@ -13,13 +13,13 @@
 #include "base/strings/utf_string_conversion_utils.h"
 #include "base/strings/utf_string_conversions.h"
 #include "content/common/input/web_touch_event_traits.h"
-#include "content/renderer/pepper/usb_key_code_conversion.h"
 #include "ppapi/c/pp_input_event.h"
 #include "ppapi/shared_impl/ppb_input_event_shared.h"
 #include "ppapi/shared_impl/time_conversion.h"
 #include "third_party/WebKit/public/platform/WebGamepads.h"
 #include "third_party/WebKit/public/platform/WebString.h"
 #include "third_party/WebKit/public/web/WebInputEvent.h"
+#include "ui/events/keycodes/dom/keycode_converter.h"
 
 using ppapi::EventTimeToPPTimeTicks;
 using ppapi::InputEventData;
@@ -135,7 +135,8 @@
   InputEventData result = GetEventWithCommonFieldsAndType(event);
   result.event_modifiers = key_event.modifiers;
   result.key_code = key_event.windowsKeyCode;
-  result.code = CodeForKeyboardEvent(key_event);
+  result.code = ui::KeycodeConverter::DomCodeToCodeString(
+      static_cast<ui::DomCode>(key_event.domCode));
   result_events->push_back(result);
 }
 
diff --git a/content/renderer/pepper/usb_key_code_conversion.cc b/content/renderer/pepper/usb_key_code_conversion.cc
deleted file mode 100644
index 129e663..0000000
--- a/content/renderer/pepper/usb_key_code_conversion.cc
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright (c) 2012 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 "content/renderer/pepper/usb_key_code_conversion.h"
-
-#include "build/build_config.h"
-
-using blink::WebKeyboardEvent;
-
-namespace content {
-
-#if !defined(OS_LINUX) && !defined(OS_MACOSX) && !defined(OS_WIN)
-
-uint32_t UsbKeyCodeForKeyboardEvent(const WebKeyboardEvent& key_event) {
-  return 0;
-}
-
-const char* CodeForKeyboardEvent(const WebKeyboardEvent& key_event) {
-  return NULL;
-}
-
-#endif
-
-}  // namespace content
diff --git a/content/renderer/pepper/usb_key_code_conversion.h b/content/renderer/pepper/usb_key_code_conversion.h
deleted file mode 100644
index 9554c572..0000000
--- a/content/renderer/pepper/usb_key_code_conversion.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright (c) 2012 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_RENDERER_PEPPER_USB_KEY_CODE_CONVERSION_H_
-#define CONTENT_RENDERER_PEPPER_USB_KEY_CODE_CONVERSION_H_
-
-#include "ppapi/c/pp_stdint.h"
-
-namespace blink {
-class WebKeyboardEvent;
-}  // namespace blink
-
-namespace content {
-
-// Returns a 32-bit "USB Key Code" for the key identifier by the supplied
-// WebKeyboardEvent. The supplied event must be a KeyDown or KeyUp.
-// The code consists of the USB Page (in the high-order 16-bit word) and
-// USB Usage Id of the key.  If no translation can be performed then zero
-// is returned.
-uint32_t UsbKeyCodeForKeyboardEvent(const blink::WebKeyboardEvent& key_event);
-
-// Returns a string that represents the UI Event |code| parameter as specified
-// in http://www.w3.org/TR/uievents/
-const char* CodeForKeyboardEvent(const blink::WebKeyboardEvent& key_event);
-
-}  // namespace content
-
-#endif  // CONTENT_RENDERER_PEPPER_USB_KEY_CODE_CONVERSION_H_
diff --git a/content/renderer/pepper/usb_key_code_conversion_linux.cc b/content/renderer/pepper/usb_key_code_conversion_linux.cc
index 26452b40..9164e7bf 100644
--- a/content/renderer/pepper/usb_key_code_conversion_linux.cc
+++ b/content/renderer/pepper/usb_key_code_conversion_linux.cc
@@ -22,7 +22,8 @@
 }
 
 const char* CodeForKeyboardEvent(const WebKeyboardEvent& key_event) {
-  return ui::KeycodeConverter::NativeKeycodeToCode(key_event.nativeKeyCode);
+  return ui::KeycodeConverter::DomCodeToCodeString(
+      ui::KeycodeConverter::NativeKeycodeToDomCode(key_event.nativeKeyCode));
 }
 
 }  // namespace content
diff --git a/content/renderer/pepper/usb_key_code_conversion_mac.cc b/content/renderer/pepper/usb_key_code_conversion_mac.cc
index 6448f7c..15e16da1 100644
--- a/content/renderer/pepper/usb_key_code_conversion_mac.cc
+++ b/content/renderer/pepper/usb_key_code_conversion_mac.cc
@@ -18,7 +18,8 @@
 }
 
 const char* CodeForKeyboardEvent(const WebKeyboardEvent& key_event) {
-  return ui::KeycodeConverter::NativeKeycodeToCode(key_event.nativeKeyCode);
+  return ui::KeycodeConverter::DomCodeToCodeString(
+      ui::KeycodeConverter::NativeKeycodeToDomCode(key_event.nativeKeyCode));
 }
 
 }  // namespace content
diff --git a/content/renderer/pepper/usb_key_code_conversion_win.cc b/content/renderer/pepper/usb_key_code_conversion_win.cc
index d270ff0..637a583 100644
--- a/content/renderer/pepper/usb_key_code_conversion_win.cc
+++ b/content/renderer/pepper/usb_key_code_conversion_win.cc
@@ -27,7 +27,8 @@
   if ((key_event.nativeKeyCode & (1 << 24)) != 0)
     scancode |= 0xe000;
 
-  return ui::KeycodeConverter::NativeKeycodeToCode(scancode);
+  return ui::KeycodeConverter::DomCodeToCodeString(
+      ui::KeycodeConverter::NativeKeycodeToDomCode(scancode));
 }
 
 }  // namespace content
diff --git a/content/renderer/renderer_blink_platform_impl.cc b/content/renderer/renderer_blink_platform_impl.cc
index 0e9864fd..4e3895d 100644
--- a/content/renderer/renderer_blink_platform_impl.cc
+++ b/content/renderer/renderer_blink_platform_impl.cc
@@ -14,6 +14,7 @@
 #include "base/numerics/safe_conversions.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
 #include "cc/blink/context_provider_web_context.h"
 #include "components/scheduler/child/web_scheduler_impl.h"
 #include "components/scheduler/renderer/renderer_scheduler.h"
@@ -63,9 +64,9 @@
 #include "media/audio/audio_output_device.h"
 #include "media/base/audio_hardware_config.h"
 #include "media/base/key_systems.h"
+#include "media/base/mime_util.h"
 #include "media/blink/webcontentdecryptionmodule_impl.h"
 #include "media/filters/stream_parser_factory.h"
-#include "net/base/mime_util.h"
 #include "net/base/net_util.h"
 #include "storage/common/database/database_identifier.h"
 #include "storage/common/quota/quota_types.h"
@@ -412,7 +413,7 @@
     const WebString& key_system) {
   const std::string mime_type_ascii = ToASCIIOrEmpty(mime_type);
   // Not supporting the container is a flat-out no.
-  if (!net::IsSupportedMediaMimeType(mime_type_ascii))
+  if (!media::IsSupportedMediaMimeType(mime_type_ascii))
     return IsNotSupported;
 
   if (!key_system.isEmpty()) {
@@ -425,7 +426,7 @@
     std::string key_system_ascii =
         media::GetUnprefixedKeySystemName(base::UTF16ToASCII(key_system));
     std::vector<std::string> strict_codecs;
-    net::ParseCodecString(ToASCIIOrEmpty(codecs), &strict_codecs, true);
+    media::ParseCodecString(ToASCIIOrEmpty(codecs), &strict_codecs, true);
 
     if (!media::PrefixedIsSupportedKeySystemWithMediaMimeType(
             mime_type_ascii, strict_codecs, key_system_ascii)) {
@@ -436,18 +437,18 @@
   }
 
   // Check list of strict codecs to see if it is supported.
-  if (net::IsStrictMediaMimeType(mime_type_ascii)) {
+  if (media::IsStrictMediaMimeType(mime_type_ascii)) {
     // Check if the codecs are a perfect match.
     std::vector<std::string> strict_codecs;
-    net::ParseCodecString(ToASCIIOrEmpty(codecs), &strict_codecs, false);
+    media::ParseCodecString(ToASCIIOrEmpty(codecs), &strict_codecs, false);
     return static_cast<WebMimeRegistry::SupportsType> (
-        net::IsSupportedStrictMediaMimeType(mime_type_ascii, strict_codecs));
+        media::IsSupportedStrictMediaMimeType(mime_type_ascii, strict_codecs));
   }
 
   // If we don't recognize the codec, it's possible we support it.
   std::vector<std::string> parsed_codecs;
-  net::ParseCodecString(ToASCIIOrEmpty(codecs), &parsed_codecs, true);
-  if (!net::AreSupportedMediaCodecs(parsed_codecs))
+  media::ParseCodecString(ToASCIIOrEmpty(codecs), &parsed_codecs, true);
+  if (!media::AreSupportedMediaCodecs(parsed_codecs))
     return MayBeSupported;
 
   // Otherwise we have a perfect match.
@@ -459,7 +460,7 @@
     const WebString& codecs) {
   const std::string mime_type_ascii = ToASCIIOrEmpty(mime_type);
   std::vector<std::string> parsed_codec_ids;
-  net::ParseCodecString(ToASCIIOrEmpty(codecs), &parsed_codec_ids, false);
+  media::ParseCodecString(ToASCIIOrEmpty(codecs), &parsed_codec_ids, false);
   if (mime_type_ascii.empty())
     return false;
   return media::StreamParserFactory::IsTypeSupported(
diff --git a/content/renderer/stats_collection_controller.cc b/content/renderer/stats_collection_controller.cc
index 6f42a02..9cbdab2b 100644
--- a/content/renderer/stats_collection_controller.cc
+++ b/content/renderer/stats_collection_controller.cc
@@ -66,7 +66,7 @@
     item.SetDouble("load_duration_ms",
         (load_stop_time - load_start_time).InMillisecondsF());
   }
-  base::JSONWriter::Write(&item, result);
+  base::JSONWriter::Write(item, result);
 }
 
 }  // namespace
diff --git a/content/shell/BUILD.gn b/content/shell/BUILD.gn
index 95450b5..e894419 100644
--- a/content/shell/BUILD.gn
+++ b/content/shell/BUILD.gn
@@ -555,3 +555,20 @@
     }
   }
 }
+
+if (is_win) {
+  # GYP version: content/content_shell_and_tests.gyp:content_shell_crash_service
+  executable("crash_service") {
+    sources = [
+      "tools/content_shell_crash_service.cc",
+    ]
+
+    deps = [
+      "//base",
+      "//components/crash/tools:crash_service",
+    ]
+
+    configs -= [ "//build/config/win:console" ]
+    configs += [ "//build/config/win:windowed" ]
+  }
+}
diff --git a/content/shell/DEPS b/content/shell/DEPS
index 552ba8e..fadafc0 100644
--- a/content/shell/DEPS
+++ b/content/shell/DEPS
@@ -29,6 +29,9 @@
 
   # For enabling media related features.
   "+media/base/media_switches.h",
+
+  # For media::RemoveProprietaryMediaTypesAndCodecsForTests.
+  "+media/base/mime_util.h",
 ]
 
 specific_include_rules = {
diff --git a/content/shell/app/shell_main_delegate.cc b/content/shell/app/shell_main_delegate.cc
index e5199f1..65a4fdf 100644
--- a/content/shell/app/shell_main_delegate.cc
+++ b/content/shell/app/shell_main_delegate.cc
@@ -12,6 +12,7 @@
 #include "base/lazy_instance.h"
 #include "base/logging.h"
 #include "base/path_service.h"
+#include "build/build_config.h"
 #include "cc/base/switches.h"
 #include "content/public/browser/browser_main_runner.h"
 #include "content/public/common/content_switches.h"
@@ -27,6 +28,7 @@
 #include "content/shell/renderer/layout_test/layout_test_content_renderer_client.h"
 #include "content/shell/renderer/shell_content_renderer_client.h"
 #include "media/base/media_switches.h"
+#include "media/base/mime_util.h"
 #include "net/cookies/cookie_monster.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/base/ui_base_paths.h"
@@ -206,7 +208,7 @@
     // Unless/until WebM files are added to the media layout tests, we need to
     // avoid removing MP4/H264/AAC so that layout tests can run on Android.
 #if !defined(OS_ANDROID)
-    net::RemoveProprietaryMediaTypesAndCodecsForTests();
+    media::RemoveProprietaryMediaTypesAndCodecsForTests();
 #endif
 
     if (!BlinkTestPlatformInitialize()) {
diff --git a/content/shell/browser/shell_devtools_frontend.cc b/content/shell/browser/shell_devtools_frontend.cc
index 0cd1c93..2ad0c2ed 100644
--- a/content/shell/browser/shell_devtools_frontend.cc
+++ b/content/shell/browser/shell_devtools_frontend.cc
@@ -267,9 +267,9 @@
 
   base::FundamentalValue total_size(static_cast<int>(message.length()));
   for (size_t pos = 0; pos < message.length(); pos += kMaxMessageChunkSize) {
-    base::StringValue message_value(message.substr(pos, kMaxMessageChunkSize));
     std::string param;
-    base::JSONWriter::Write(&message_value, &param);
+    base::JSONWriter::Write(
+        base::StringValue(message.substr(pos, kMaxMessageChunkSize)), &param);
     std::string code = "DevToolsAPI.dispatchMessageChunk(" + param + ");";
     base::string16 javascript = base::UTF8ToUTF16(code);
     web_contents()->GetMainFrame()->ExecuteJavaScript(javascript);
@@ -308,13 +308,13 @@
   std::string javascript = function_name + "(";
   if (arg1) {
     std::string json;
-    base::JSONWriter::Write(arg1, &json);
+    base::JSONWriter::Write(*arg1, &json);
     javascript.append(json);
     if (arg2) {
-      base::JSONWriter::Write(arg2, &json);
+      base::JSONWriter::Write(*arg2, &json);
       javascript.append(", ").append(json);
       if (arg3) {
-        base::JSONWriter::Write(arg3, &json);
+        base::JSONWriter::Write(*arg3, &json);
         javascript.append(", ").append(json);
       }
     }
diff --git a/content/shell/renderer/layout_test/leak_detector.cc b/content/shell/renderer/layout_test/leak_detector.cc
index a00fdba..41645bb 100644
--- a/content/shell/renderer/layout_test/leak_detector.cc
+++ b/content/shell/renderer/layout_test/leak_detector.cc
@@ -85,7 +85,7 @@
 
   if (!detail.empty()) {
     std::string detail_str;
-    base::JSONWriter::Write(&detail, &detail_str);
+    base::JSONWriter::Write(detail, &detail_str);
     report.detail = detail_str;
     report.leaked = true;
   }
diff --git a/content/shell/renderer/test_runner/test_interfaces.cc b/content/shell/renderer/test_runner/test_interfaces.cc
index fda79745..2dd3e418 100644
--- a/content/shell/renderer/test_runner/test_interfaces.cc
+++ b/content/shell/renderer/test_runner/test_interfaces.cc
@@ -119,7 +119,7 @@
     base::DictionaryValue settings;
     settings.SetString("testPath", base::GetQuotedJSONString(spec));
     std::string settings_string;
-    base::JSONWriter::Write(&settings, &settings_string);
+    base::JSONWriter::Write(settings, &settings_string);
     test_runner_->ShowDevTools(settings_string, std::string());
   }
   if (spec.find("/viewsource/") != std::string::npos) {
diff --git a/content/shell/renderer/test_runner/web_test_proxy.cc b/content/shell/renderer/test_runner/web_test_proxy.cc
index 8b3cfdee..6b97d39d 100644
--- a/content/shell/renderer/test_runner/web_test_proxy.cc
+++ b/content/shell/renderer/test_runner/web_test_proxy.cc
@@ -311,12 +311,7 @@
 }
 
 std::string DumpDocumentText(blink::WebFrame* frame) {
-  // We use the document element's text instead of the body text here because
-  // not all documents have a body, such as XML documents.
-  blink::WebElement document_element = frame->document().documentElement();
-  if (document_element.isNull())
-    return std::string();
-  return document_element.innerText().utf8();
+  return frame->document().contentAsTextForTesting().utf8();
 }
 
 std::string DumpFramesAsText(blink::WebFrame* frame, bool recursive) {
diff --git a/content/test/data/media/webrtc_test_utilities.js b/content/test/data/media/webrtc_test_utilities.js
index cf75ef6d..5fd3811 100644
--- a/content/test/data/media/webrtc_test_utilities.js
+++ b/content/test/data/media/webrtc_test_utilities.js
@@ -66,14 +66,9 @@
   var width = VIDEO_TAG_WIDTH;
   var height = VIDEO_TAG_HEIGHT;
   var videoElement = $(videoElementName);
+  var canvas = $(videoElementName + '-canvas');
   var oldPixels = [];
-  var startTimeMs = new Date().getTime();
   var waitVideo = setInterval(function() {
-    var canvas = $(videoElementName + '-canvas');
-    if (canvas == null) {
-      console.log('Waiting for ' + videoElementName + '-canvas' + ' to appear');
-      return;
-    }
     var context = canvas.getContext('2d');
     context.drawImage(videoElement, 0, 0, width, height);
     var pixels = context.getImageData(0, 0 , width, height / 3).data;
@@ -87,12 +82,6 @@
       callback(videoElement.videoWidth, videoElement.videoHeight);
     }
     oldPixels = pixels;
-
-    var elapsedTime = new Date().getTime() - startTimeMs;
-    if (elapsedTime > 3000) {
-      startTimeMs = new Date().getTime();
-      console.log('Still waiting for video to satisfy ' + predicate.toString());
-    }
   }, 200);
 }
 
@@ -197,19 +186,12 @@
   return false;
 }
 
-// Pixels is an array where pixels[0] is the R value for the first pixel,
-// pixels[1] is the G value, and so on.
 function isVideoBlack(pixels) {
   for (var i = 0; i < pixels.length; i++) {
-    if ((i + 1) % 4 == 0) {
-      // Ignore the alpha channel.
-      continue;
-    }
-
-    // A black pixel has 0 for R,G and B but allow a bit more here to account
-    // for rounding errors in libyuv.
-    if (pixels[i] > 3) {
-      console.log('Found nonblack pixel at ' + i + ', was ' + pixels[i]);
+    // |pixels| is in RGBA. Ignore the alpha channel.
+    // We allow it to be off by 1, to account for rounding errors in YUV
+    // conversion.
+    if (pixels[i] != 0 && pixels[i] != 1 && (i + 1) % 4 != 0) {
       return false;
     }
   }
diff --git a/content/test/gpu/gpu_tests/pixel_expectations.py b/content/test/gpu/gpu_tests/pixel_expectations.py
index a8b1dda..0ef5d92 100644
--- a/content/test/gpu/gpu_tests/pixel_expectations.py
+++ b/content/test/gpu/gpu_tests/pixel_expectations.py
@@ -11,4 +11,6 @@
     # Sample Usage:
     # self.Fail('Pixel.Canvas2DRedBox',
     #     ['mac', 'amd', ('nvidia', 0x1234)], bug=123)
-    pass
+    self.Fail('Pixel.Canvas2DRedBox', bug=485183)
+    self.Fail('Pixel.CSS3DBlueBox', bug=485183)
+    self.Fail('Pixel.WebGLGreenTriangle', bug=485183)
diff --git a/content/test/gpu/gpu_tests/webgl_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
index 52c7790..2e782df 100644
--- a/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
+++ b/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
@@ -80,6 +80,8 @@
         ['win', 'd3d9'], bug=896) # angle bug ID
     self.Skip('conformance/extensions/oes-texture-half-float-with-canvas.html',
         ['win', 'd3d9'], bug=896) # angle bug ID
+    self.Fail('conformance/glsl/bugs/conditional-discard-optimization.html',
+        ['win', 'd3d9'], bug=488552)
 
     # Mac failures
     self.Fail('conformance/glsl/misc/shaders-with-invariance.html',
diff --git a/content/test/gpu/page_sets/pixel_tests.py b/content/test/gpu/page_sets/pixel_tests.py
index e747d3c..877311d 100644
--- a/content/test/gpu/page_sets/pixel_tests.py
+++ b/content/test/gpu/page_sets/pixel_tests.py
@@ -30,19 +30,19 @@
       url='file://../../data/gpu/pixel_canvas2d.html',
       name=base_name + '.Canvas2DRedBox',
       test_rect=[0, 0, 300, 300],
-      revision=4,
+      revision=5,
       page_set=self))
 
     self.AddUserStory(PixelTestsPage(
       url='file://../../data/gpu/pixel_css3d.html',
       name=base_name + '.CSS3DBlueBox',
       test_rect=[0, 0, 300, 300],
-      revision=12,
+      revision=13,
       page_set=self))
 
     self.AddUserStory(PixelTestsPage(
       url='file://../../data/gpu/pixel_webgl.html',
       name=base_name + '.WebGLGreenTriangle',
       test_rect=[0, 0, 300, 300],
-      revision=9,
+      revision=10,
       page_set=self))
diff --git a/dbus/values_util.cc b/dbus/values_util.cc
index c27c272..c162878 100644
--- a/dbus/values_util.cc
+++ b/dbus/values_util.cc
@@ -48,10 +48,10 @@
     } else {
       // If the type of keys is not STRING, convert it to string.
       scoped_ptr<base::Value> key(PopDataAsValue(&entry_reader));
-      if (!key.get())
+      if (!key)
         return false;
       // Use JSONWriter to convert an arbitrary value to a string.
-      base::JSONWriter::Write(key.get(), &key_string);
+      base::JSONWriter::Write(*key, &key_string);
     }
     // Get the value and set the key-value pair.
     base::Value* value = PopDataAsValue(&entry_reader);
diff --git a/dbus/values_util_unittest.cc b/dbus/values_util_unittest.cc
index 27ec2d0..6abc56a 100644
--- a/dbus/values_util_unittest.cc
+++ b/dbus/values_util_unittest.cc
@@ -377,11 +377,9 @@
   // Create the expected value.
   base::DictionaryValue dictionary_value;
   for (size_t i = 0; i != values.size(); ++i) {
-    scoped_ptr<base::Value> key_value(new base::FundamentalValue(keys[i]));
     std::string key_string;
-    base::JSONWriter::Write(key_value.get(), &key_string);
-    dictionary_value.SetWithoutPathExpansion(
-        key_string, new base::FundamentalValue(values[i]));
+    base::JSONWriter::Write(base::FundamentalValue(keys[i]), &key_string);
+    dictionary_value.SetIntegerWithoutPathExpansion(key_string, values[i]);
   }
 
   // Pop a dictionary.
diff --git a/device/bluetooth/BUILD.gn b/device/bluetooth/BUILD.gn
index 3de7132..31b54e17 100644
--- a/device/bluetooth/BUILD.gn
+++ b/device/bluetooth/BUILD.gn
@@ -215,6 +215,8 @@
   sources = [
     "test/mock_bluetooth_adapter.cc",
     "test/mock_bluetooth_adapter.h",
+    "test/mock_bluetooth_advertisement.cc",
+    "test/mock_bluetooth_advertisement.h",
     "test/mock_bluetooth_device.cc",
     "test/mock_bluetooth_device.h",
     "test/mock_bluetooth_discovery_session.cc",
diff --git a/device/bluetooth/bluetooth.gyp b/device/bluetooth/bluetooth.gyp
index 4d734c52..d36a2ce 100644
--- a/device/bluetooth/bluetooth.gyp
+++ b/device/bluetooth/bluetooth.gyp
@@ -211,6 +211,8 @@
         # Note: file list duplicated in GN build.
         'test/mock_bluetooth_adapter.cc',
         'test/mock_bluetooth_adapter.h',
+        'test/mock_bluetooth_advertisement.cc',
+        'test/mock_bluetooth_advertisement.h',
         'test/mock_bluetooth_device.cc',
         'test/mock_bluetooth_device.h',
         'test/mock_bluetooth_discovery_session.cc',
diff --git a/device/bluetooth/test/mock_bluetooth_adapter.cc b/device/bluetooth/test/mock_bluetooth_adapter.cc
index 4b47579..46d8cb7c 100644
--- a/device/bluetooth/test/mock_bluetooth_adapter.cc
+++ b/device/bluetooth/test/mock_bluetooth_adapter.cc
@@ -4,6 +4,8 @@
 
 #include "device/bluetooth/test/mock_bluetooth_adapter.h"
 
+#include "device/bluetooth/test/mock_bluetooth_advertisement.h"
+
 namespace device {
 
 MockBluetoothAdapter::Observer::Observer() {}
@@ -50,6 +52,7 @@
     scoped_ptr<BluetoothAdvertisement::Data> advertisement_data,
     const CreateAdvertisementCallback& callback,
     const CreateAdvertisementErrorCallback& error_callback) {
+  callback.Run(new MockBluetoothAdvertisement);
 }
 
 }  // namespace device
diff --git a/device/bluetooth/test/mock_bluetooth_advertisement.cc b/device/bluetooth/test/mock_bluetooth_advertisement.cc
new file mode 100644
index 0000000..ddba516
--- /dev/null
+++ b/device/bluetooth/test/mock_bluetooth_advertisement.cc
@@ -0,0 +1,21 @@
+// 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 "device/bluetooth/test/mock_bluetooth_advertisement.h"
+
+namespace device {
+
+MockBluetoothAdvertisement::MockBluetoothAdvertisement() {
+}
+
+MockBluetoothAdvertisement::~MockBluetoothAdvertisement() {
+}
+
+void MockBluetoothAdvertisement::Unregister(
+    const SuccessCallback& success_callback,
+    const ErrorCallback& error_callback) {
+  success_callback.Run();
+}
+
+}  // namespace chromeos
diff --git a/device/bluetooth/test/mock_bluetooth_advertisement.h b/device/bluetooth/test/mock_bluetooth_advertisement.h
new file mode 100644
index 0000000..ddaeef4
--- /dev/null
+++ b/device/bluetooth/test/mock_bluetooth_advertisement.h
@@ -0,0 +1,29 @@
+// 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 DEVICE_BLUETOOTH_BLUETOOTH_ADVERTISEMENT_CHROMEOS_H_
+#define DEVICE_BLUETOOTH_BLUETOOTH_ADVERTISEMENT_CHROMEOS_H_
+
+#include "base/macros.h"
+#include "device/bluetooth/bluetooth_advertisement.h"
+
+namespace device {
+
+class MockBluetoothAdvertisement : public device::BluetoothAdvertisement {
+ public:
+  MockBluetoothAdvertisement();
+
+  // BluetoothAdvertisement overrides:
+  void Unregister(const SuccessCallback& success_callback,
+                  const ErrorCallback& error_callback) override;
+
+ private:
+  ~MockBluetoothAdvertisement() override;
+
+  DISALLOW_COPY_AND_ASSIGN(MockBluetoothAdvertisement);
+};
+
+}  // namespace chromeos
+
+#endif  // DEVICE_BLUETOOTH_BLUETOOTH_ADVERTISEMENT_CHROMEOS_H_
diff --git a/extensions/browser/api/bluetooth_low_energy/bluetooth_api_advertisement.cc b/extensions/browser/api/bluetooth_low_energy/bluetooth_api_advertisement.cc
new file mode 100644
index 0000000..c1a9248
--- /dev/null
+++ b/extensions/browser/api/bluetooth_low_energy/bluetooth_api_advertisement.cc
@@ -0,0 +1,35 @@
+// 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 "extensions/browser/api/bluetooth_low_energy/bluetooth_api_advertisement.h"
+
+#include "base/lazy_instance.h"
+#include "device/bluetooth/bluetooth_advertisement.h"
+#include "net/base/io_buffer.h"
+
+namespace extensions {
+
+// static
+static base::LazyInstance<BrowserContextKeyedAPIFactory<
+    ApiResourceManager<BluetoothApiAdvertisement>>> g_server_factory =
+    LAZY_INSTANCE_INITIALIZER;
+
+// static
+template <>
+BrowserContextKeyedAPIFactory<ApiResourceManager<BluetoothApiAdvertisement>>*
+ApiResourceManager<BluetoothApiAdvertisement>::GetFactoryInstance() {
+  return g_server_factory.Pointer();
+}
+
+BluetoothApiAdvertisement::BluetoothApiAdvertisement(
+    const std::string& owner_extension_id,
+    scoped_refptr<device::BluetoothAdvertisement> advertisement)
+    : ApiResource(owner_extension_id), advertisement_(advertisement) {
+  DCHECK(content::BrowserThread::CurrentlyOn(kThreadId));
+}
+
+BluetoothApiAdvertisement::~BluetoothApiAdvertisement() {
+}
+
+}  // namespace extensions
diff --git a/extensions/browser/api/bluetooth_low_energy/bluetooth_api_advertisement.h b/extensions/browser/api/bluetooth_low_energy/bluetooth_api_advertisement.h
new file mode 100644
index 0000000..6144bc27
--- /dev/null
+++ b/extensions/browser/api/bluetooth_low_energy/bluetooth_api_advertisement.h
@@ -0,0 +1,56 @@
+// 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 EXTENSIONS_BROWSER_API_BLUETOOTH_LOW_ENERGY_BLUETOOTH_API_ADVERTISEMENT_H_
+#define EXTENSIONS_BROWSER_API_BLUETOOTH_LOW_ENERGY_BLUETOOTH_API_ADVERTISEMENT_H_
+
+#include <string>
+
+#include "device/bluetooth/bluetooth_advertisement.h"
+#include "extensions/browser/api/api_resource.h"
+#include "extensions/browser/api/api_resource_manager.h"
+#include "extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_event_router.h"
+
+namespace device {
+class BluetoothAdvertisement;
+}  // namespace device
+
+namespace apibtle = extensions::core_api::bluetooth_low_energy;
+
+namespace extensions {
+
+// Representation of advertisement instances from the "bluetooth" namespace,
+// abstracting the underlying BluetoothAdvertisementXxx class. All methods
+// must be called on the |kThreadId| thread.
+class BluetoothApiAdvertisement : public ApiResource {
+ public:
+  BluetoothApiAdvertisement(const std::string& owner_extension_id,
+                            scoped_refptr<device::BluetoothAdvertisement>);
+  ~BluetoothApiAdvertisement() override;
+
+  device::BluetoothAdvertisement* advertisement() {
+    return advertisement_.get();
+  }
+
+  // Implementations of |BluetoothAdvertisement| require being called on the
+  // UI thread.
+  static const content::BrowserThread::ID kThreadId =
+      content::BrowserThread::UI;
+
+ private:
+  friend class ApiResourceManager<BluetoothApiAdvertisement>;
+
+  static const char* service_name() {
+    return "BluetoothApiAdvertisementManager";
+  }
+
+  // The underlying advertisement instance.
+  scoped_refptr<device::BluetoothAdvertisement> advertisement_;
+
+  DISALLOW_COPY_AND_ASSIGN(BluetoothApiAdvertisement);
+};
+
+}  // namespace extensions
+
+#endif  // EXTENSIONS_BROWSER_API_BLUETOOTH_LOW_ENERGY_BLUETOOTH_API_ADVERTISEMENT_H_
diff --git a/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_api.cc b/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_api.cc
index a072c0c8..9545d48 100644
--- a/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_api.cc
+++ b/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_api.cc
@@ -4,10 +4,13 @@
 
 #include "extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_api.h"
 
+#include <algorithm>
+
 #include "base/bind.h"
 #include "base/lazy_instance.h"
 #include "base/strings/stringprintf.h"
 #include "content/public/browser/browser_thread.h"
+#include "extensions/browser/api/bluetooth_low_energy/bluetooth_api_advertisement.h"
 #include "extensions/browser/api/bluetooth_low_energy/utils.h"
 #include "extensions/browser/event_router.h"
 #include "extensions/common/api/bluetooth/bluetooth_manifest_data.h"
@@ -44,6 +47,11 @@
 const char kErrorTimeout[] = "Operation timed out";
 const char kErrorUnsupportedDevice[] =
     "This device is not supported on the current platform";
+const char kErrorInvalidAdvertisementLength[] = "Invalid advertisement length";
+const char kStatusAdvertisementAlreadyExists[] =
+    "An advertisement is already advertising";
+const char kStatusAdvertisementDoesNotExist[] =
+    "This advertisement does not exist";
 
 // Returns the correct error string based on error status |status|. This is used
 // to set the value of |chrome.runtime.lastError.message| and should not be
@@ -100,6 +108,31 @@
   callback.Run();
 }
 
+scoped_ptr<device::BluetoothAdvertisement::ManufacturerData>
+CreateManufacturerData(
+    std::vector<linked_ptr<apibtle::ManufacturerData>>* manufacturer_data) {
+  scoped_ptr<device::BluetoothAdvertisement::ManufacturerData> created_data(
+      new device::BluetoothAdvertisement::ManufacturerData());
+  for (const auto& it : *manufacturer_data) {
+    std::vector<uint8_t> data(it->data.size());
+    std::copy(it->data.begin(), it->data.end(), data.begin());
+    (*created_data)[it->id] = data;
+  }
+  return created_data;
+}
+
+scoped_ptr<device::BluetoothAdvertisement::ServiceData> CreateServiceData(
+    std::vector<linked_ptr<apibtle::ServiceData>>* service_data) {
+  scoped_ptr<device::BluetoothAdvertisement::ServiceData> created_data(
+      new device::BluetoothAdvertisement::ServiceData());
+  for (const auto& it : *service_data) {
+    std::vector<uint8_t> data(it->data.size());
+    std::copy(it->data.begin(), it->data.end(), data.begin());
+    (*created_data)[it->uuid] = data;
+  }
+  return created_data;
+}
+
 }  // namespace
 
 
@@ -793,6 +826,44 @@
   SendResponse(false);
 }
 
+BluetoothLowEnergyAdvertisementFunction::
+    BluetoothLowEnergyAdvertisementFunction()
+    : advertisements_manager_(nullptr) {
+}
+
+BluetoothLowEnergyAdvertisementFunction::
+    ~BluetoothLowEnergyAdvertisementFunction() {
+}
+
+int BluetoothLowEnergyAdvertisementFunction::AddAdvertisement(
+    BluetoothApiAdvertisement* advertisement) {
+  DCHECK(advertisements_manager_);
+  return advertisements_manager_->Add(advertisement);
+}
+
+BluetoothApiAdvertisement*
+BluetoothLowEnergyAdvertisementFunction::GetAdvertisement(
+    int advertisement_id) {
+  DCHECK(advertisements_manager_);
+  return advertisements_manager_->Get(extension_id(), advertisement_id);
+}
+
+void BluetoothLowEnergyAdvertisementFunction::RemoveAdvertisement(
+    int advertisement_id) {
+  DCHECK(advertisements_manager_);
+  advertisements_manager_->Remove(extension_id(), advertisement_id);
+}
+
+bool BluetoothLowEnergyAdvertisementFunction::RunAsync() {
+  Initialize();
+  return BluetoothLowEnergyExtensionFunction::RunAsync();
+}
+
+void BluetoothLowEnergyAdvertisementFunction::Initialize() {
+  advertisements_manager_ =
+      ApiResourceManager<BluetoothApiAdvertisement>::Get(browser_context());
+}
+
 // RegisterAdvertisement:
 
 bool BluetoothLowEnergyRegisterAdvertisementFunction::DoWork() {
@@ -819,11 +890,65 @@
       apibtle::RegisterAdvertisement::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
 
-  // TODO(rkc): Implement this function.
+  scoped_ptr<device::BluetoothAdvertisement::Data> advertisement_data(
+      new device::BluetoothAdvertisement::Data(
+          params->advertisement.type ==
+                  apibtle::AdvertisementType::ADVERTISEMENT_TYPE_BROADCAST
+              ? device::BluetoothAdvertisement::AdvertisementType::
+                    ADVERTISEMENT_TYPE_BROADCAST
+              : device::BluetoothAdvertisement::AdvertisementType::
+                    ADVERTISEMENT_TYPE_PERIPHERAL));
+
+  advertisement_data->set_service_uuids(
+      params->advertisement.service_uuids.Pass());
+  advertisement_data->set_solicit_uuids(
+      params->advertisement.solicit_uuids.Pass());
+  if (params->advertisement.manufacturer_data) {
+    advertisement_data->set_manufacturer_data(
+        CreateManufacturerData(params->advertisement.manufacturer_data.get())
+            .Pass());
+  }
+  if (params->advertisement.service_data) {
+    advertisement_data->set_service_data(
+        CreateServiceData(params->advertisement.service_data.get()).Pass());
+  }
+
+  event_router->adapter()->RegisterAdvertisement(
+      advertisement_data.Pass(),
+      base::Bind(
+          &BluetoothLowEnergyRegisterAdvertisementFunction::SuccessCallback,
+          this),
+      base::Bind(
+          &BluetoothLowEnergyRegisterAdvertisementFunction::ErrorCallback,
+          this));
 
   return true;
 }
 
+void BluetoothLowEnergyRegisterAdvertisementFunction::SuccessCallback(
+    scoped_refptr<device::BluetoothAdvertisement> advertisement) {
+  results_ = apibtle::RegisterAdvertisement::Results::Create(AddAdvertisement(
+      new BluetoothApiAdvertisement(extension_id(), advertisement)));
+  SendResponse(true);
+}
+
+void BluetoothLowEnergyRegisterAdvertisementFunction::ErrorCallback(
+    device::BluetoothAdvertisement::ErrorCode status) {
+  switch (status) {
+    case device::BluetoothAdvertisement::ErrorCode::
+        ERROR_ADVERTISEMENT_ALREADY_EXISTS:
+      SetError(kStatusAdvertisementAlreadyExists);
+      break;
+    case device::BluetoothAdvertisement::ErrorCode::
+        ERROR_ADVERTISEMENT_INVALID_LENGTH:
+      SetError(kErrorInvalidAdvertisementLength);
+      break;
+    default:
+      SetError(kErrorOperationFailed);
+  }
+  SendResponse(false);
+}
+
 // UnregisterAdvertisement:
 
 bool BluetoothLowEnergyUnregisterAdvertisementFunction::DoWork() {
@@ -846,10 +971,45 @@
       apibtle::UnregisterAdvertisement::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
 
-  // TODO(rkc): Implement this function.
+  BluetoothApiAdvertisement* advertisement =
+      GetAdvertisement(params->advertisement_id);
+  if (!advertisement) {
+    error_ = kStatusAdvertisementDoesNotExist;
+    SendResponse(false);
+    return false;
+  }
+
+  advertisement->advertisement()->Unregister(
+      base::Bind(
+          &BluetoothLowEnergyUnregisterAdvertisementFunction::SuccessCallback,
+          this, params->advertisement_id),
+      base::Bind(
+          &BluetoothLowEnergyUnregisterAdvertisementFunction::ErrorCallback,
+          this, params->advertisement_id));
 
   return true;
 }
 
+void BluetoothLowEnergyUnregisterAdvertisementFunction::SuccessCallback(
+    int advertisement_id) {
+  RemoveAdvertisement(advertisement_id);
+  SendResponse(true);
+}
+
+void BluetoothLowEnergyUnregisterAdvertisementFunction::ErrorCallback(
+    int advertisement_id,
+    device::BluetoothAdvertisement::ErrorCode status) {
+  RemoveAdvertisement(advertisement_id);
+  switch (status) {
+    case device::BluetoothAdvertisement::ErrorCode::
+        ERROR_ADVERTISEMENT_DOES_NOT_EXIST:
+      SetError(kStatusAdvertisementDoesNotExist);
+      break;
+    default:
+      SetError(kErrorOperationFailed);
+  }
+  SendResponse(false);
+}
+
 }  // namespace core_api
 }  // namespace extensions
diff --git a/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_api.h b/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_api.h
index debb635c..b6e6f8f2 100644
--- a/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_api.h
+++ b/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_api.h
@@ -6,6 +6,8 @@
 #define EXTENSIONS_BROWSER_API_BLUETOOTH_LOW_ENERGY_BLUETOOTH_LOW_ENERGY_API_H_
 
 #include "base/memory/scoped_ptr.h"
+#include "device/bluetooth/bluetooth_advertisement.h"
+#include "extensions/browser/api/api_resource_manager.h"
 #include "extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_event_router.h"
 #include "extensions/browser/browser_context_keyed_api_factory.h"
 #include "extensions/browser/extension_function.h"
@@ -13,6 +15,7 @@
 
 namespace extensions {
 
+class BluetoothApiAdvertisement;
 class BluetoothLowEnergyEventRouter;
 
 // The profile-keyed service that manages the bluetoothLowEnergy extension API.
@@ -329,9 +332,33 @@
   std::string instance_id_;
 };
 
-class BluetoothLowEnergyRegisterAdvertisementFunction
+class BluetoothLowEnergyAdvertisementFunction
     : public BluetoothLowEnergyExtensionFunction {
  public:
+  BluetoothLowEnergyAdvertisementFunction();
+
+ protected:
+  ~BluetoothLowEnergyAdvertisementFunction() override;
+
+  // Takes ownership.
+  int AddAdvertisement(BluetoothApiAdvertisement* advertisement);
+  BluetoothApiAdvertisement* GetAdvertisement(int advertisement_id);
+  void RemoveAdvertisement(int advertisement_id);
+
+  // ExtensionFunction override.
+  bool RunAsync() override;
+
+ private:
+  void Initialize();
+
+  ApiResourceManager<BluetoothApiAdvertisement>* advertisements_manager_;
+
+  DISALLOW_COPY_AND_ASSIGN(BluetoothLowEnergyAdvertisementFunction);
+};
+
+class BluetoothLowEnergyRegisterAdvertisementFunction
+    : public BluetoothLowEnergyAdvertisementFunction {
+ public:
   DECLARE_EXTENSION_FUNCTION("bluetoothLowEnergy.registerAdvertisement",
                              BLUETOOTHLOWENERGY_REGISTERADVERTISEMENT);
 
@@ -342,17 +369,15 @@
   bool DoWork() override;
 
  private:
-  // Success and error callbacks, called by
-  // BluetoothLowEnergyEventRouter::WriteDescriptorValue.
-  void SuccessCallback();
-  void ErrorCallback(BluetoothLowEnergyEventRouter::Status status);
+  void SuccessCallback(scoped_refptr<device::BluetoothAdvertisement>);
+  void ErrorCallback(device::BluetoothAdvertisement::ErrorCode status);
 
   // The instance ID of the requested descriptor.
   std::string instance_id_;
 };
 
 class BluetoothLowEnergyUnregisterAdvertisementFunction
-    : public BluetoothLowEnergyExtensionFunction {
+    : public BluetoothLowEnergyAdvertisementFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("bluetoothLowEnergy.unregisterAdvertisement",
                              BLUETOOTHLOWENERGY_UNREGISTERADVERTISEMENT);
@@ -364,10 +389,9 @@
   bool DoWork() override;
 
  private:
-  // Success and error callbacks, called by
-  // BluetoothLowEnergyEventRouter::WriteDescriptorValue.
-  void SuccessCallback();
-  void ErrorCallback(BluetoothLowEnergyEventRouter::Status status);
+  void SuccessCallback(int advertisement_id);
+  void ErrorCallback(int advertisement_id,
+                     device::BluetoothAdvertisement::ErrorCode status);
 
   // The instance ID of the requested descriptor.
   std::string instance_id_;
diff --git a/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_apitest.cc b/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_apitest.cc
index d300dfa..398cca8e 100644
--- a/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_apitest.cc
+++ b/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_apitest.cc
@@ -1320,4 +1320,21 @@
       mock_adapter_, device0_.get(), service0_.get());
 }
 
+#if defined(OS_CHROMEOS)
+#define MAYBE_RegisterAdvertisement RegisterAdvertisement
+#else
+#define MAYBE_RegisterAdvertisement DISABLED_RegisterAdvertisement
+#endif
+
+IN_PROC_BROWSER_TEST_F(BluetoothLowEnergyApiTest, MAYBE_RegisterAdvertisement) {
+  ResultCatcher catcher;
+  catcher.RestrictToBrowserContext(browser()->profile());
+
+  // Run the test.
+  ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII(
+      "bluetooth_low_energy/register_advertisement")));
+
+  EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
+}
+
 }  // namespace
diff --git a/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_event_router.h b/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_event_router.h
index b6bad5c..f265505 100644
--- a/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_event_router.h
+++ b/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_event_router.h
@@ -268,6 +268,8 @@
                                   device::BluetoothGattDescriptor* descriptor,
                                   const std::vector<uint8>& value) override;
 
+  device::BluetoothAdapter* adapter() { return adapter_.get(); }
+
  private:
   // Called by BluetoothAdapterFactory.
   void OnGetAdapter(const base::Closure& callback,
diff --git a/extensions/browser/api/cast_channel/cast_channel_api.cc b/extensions/browser/api/cast_channel/cast_channel_api.cc
index e00646e..4ad8624b 100644
--- a/extensions/browser/api/cast_channel/cast_channel_api.cc
+++ b/extensions/browser/api/cast_channel/cast_channel_api.cc
@@ -59,7 +59,7 @@
 std::string ParamToString(const T& info) {
   scoped_ptr<base::DictionaryValue> dict = info.ToValue();
   std::string out;
-  base::JSONWriter::Write(dict.get(), &out);
+  base::JSONWriter::Write(*dict, &out);
   return out;
 }
 
diff --git a/extensions/browser/api/cast_channel/keep_alive_delegate.cc b/extensions/browser/api/cast_channel/keep_alive_delegate.cc
index 73c356f4..df23519 100644
--- a/extensions/browser/api/cast_channel/keep_alive_delegate.cc
+++ b/extensions/browser/api/cast_channel/keep_alive_delegate.cc
@@ -68,7 +68,7 @@
   output.set_namespace_(kHeartbeatNamespace);
   base::DictionaryValue type_dict;
   type_dict.SetString(kTypeNodeId, message_type);
-  if (!base::JSONWriter::Write(&type_dict, output.mutable_payload_utf8())) {
+  if (!base::JSONWriter::Write(type_dict, output.mutable_payload_utf8())) {
     LOG(ERROR) << "Failed to serialize dictionary.";
     return output;
   }
diff --git a/extensions/browser/api/storage/settings_quota_unittest.cc b/extensions/browser/api/storage/settings_quota_unittest.cc
index 391043e0..02e8735e 100644
--- a/extensions/browser/api/storage/settings_quota_unittest.cc
+++ b/extensions/browser/api/storage/settings_quota_unittest.cc
@@ -24,23 +24,22 @@
 class ExtensionSettingsQuotaTest : public testing::Test {
  public:
   ExtensionSettingsQuotaTest()
-      : byte_value_1_(new base::FundamentalValue(1)),
-        byte_value_16_(new base::StringValue("sixteen bytes.")),
-        byte_value_256_(new base::ListValue()),
+      : byte_value_1_(1),
+        byte_value_16_("sixteen bytes."),
         delegate_(new TestingValueStore()) {
     for (int i = 1; i < 89; ++i) {
-      byte_value_256_->Append(new base::FundamentalValue(i));
+      byte_value_256_.AppendInteger(i);
     }
     ValidateByteValues();
   }
 
   void ValidateByteValues() {
     std::string validate_sizes;
-    base::JSONWriter::Write(byte_value_1_.get(), &validate_sizes);
+    base::JSONWriter::Write(byte_value_1_, &validate_sizes);
     ASSERT_EQ(1u, validate_sizes.size());
-    base::JSONWriter::Write(byte_value_16_.get(), &validate_sizes);
+    base::JSONWriter::Write(byte_value_16_, &validate_sizes);
     ASSERT_EQ(16u, validate_sizes.size());
-    base::JSONWriter::Write(byte_value_256_.get(), &validate_sizes);
+    base::JSONWriter::Write(byte_value_256_, &validate_sizes);
     ASSERT_EQ(256u, validate_sizes.size());
   }
 
@@ -64,9 +63,9 @@
   }
 
   // Values with different serialized sizes.
-  scoped_ptr<base::Value> byte_value_1_;
-  scoped_ptr<base::Value> byte_value_16_;
-  scoped_ptr<base::ListValue> byte_value_256_;
+  base::FundamentalValue byte_value_1_;
+  base::StringValue byte_value_16_;
+  base::ListValue byte_value_256_;
 
   // Quota enforcing storage area being tested.
   scoped_ptr<SettingsStorageQuotaEnforcer> storage_;
@@ -79,7 +78,7 @@
   base::DictionaryValue empty;
   CreateStorage(0, UINT_MAX, UINT_MAX);
 
-  EXPECT_TRUE(storage_->Set(DEFAULTS, "a", *byte_value_1_)->HasError());
+  EXPECT_TRUE(storage_->Set(DEFAULTS, "a", byte_value_1_)->HasError());
   EXPECT_FALSE(storage_->Remove("a")->HasError());
   EXPECT_FALSE(storage_->Remove("b")->HasError());
   EXPECT_TRUE(SettingsEqual(empty));
@@ -89,7 +88,7 @@
   base::DictionaryValue empty;
   CreateStorage(8u, UINT_MAX, UINT_MAX);
   EXPECT_TRUE(
-      storage_->Set(DEFAULTS, "Really long key", *byte_value_1_)->HasError());
+      storage_->Set(DEFAULTS, "Really long key", byte_value_1_)->HasError());
   EXPECT_TRUE(SettingsEqual(empty));
 }
 
@@ -97,12 +96,12 @@
   base::DictionaryValue settings;
   CreateStorage(8u, UINT_MAX, UINT_MAX);
 
-  EXPECT_FALSE(storage_->Set(DEFAULTS, "a", *byte_value_1_)->HasError());
-  settings.Set("a", byte_value_1_->DeepCopy());
+  EXPECT_FALSE(storage_->Set(DEFAULTS, "a", byte_value_1_)->HasError());
+  settings.Set("a", byte_value_1_.CreateDeepCopy());
   EXPECT_TRUE(SettingsEqual(settings));
 
-  EXPECT_TRUE(storage_->Set(DEFAULTS, "b", *byte_value_16_)->HasError());
-  EXPECT_TRUE(storage_->Set(DEFAULTS, "c", *byte_value_256_)->HasError());
+  EXPECT_TRUE(storage_->Set(DEFAULTS, "b", byte_value_16_)->HasError());
+  EXPECT_TRUE(storage_->Set(DEFAULTS, "c", byte_value_256_)->HasError());
   EXPECT_TRUE(SettingsEqual(settings));
 }
 
@@ -111,20 +110,20 @@
   CreateStorage(40, UINT_MAX, UINT_MAX);
 
   base::DictionaryValue to_set;
-  to_set.Set("a", byte_value_1_->DeepCopy());
-  to_set.Set("b", byte_value_16_->DeepCopy());
+  to_set.Set("a", byte_value_1_.CreateDeepCopy());
+  to_set.Set("b", byte_value_16_.CreateDeepCopy());
   EXPECT_FALSE(storage_->Set(DEFAULTS, to_set)->HasError());
-  settings.Set("a", byte_value_1_->DeepCopy());
-  settings.Set("b", byte_value_16_->DeepCopy());
+  settings.Set("a", byte_value_1_.CreateDeepCopy());
+  settings.Set("b", byte_value_16_.CreateDeepCopy());
   EXPECT_TRUE(SettingsEqual(settings));
 
   // Should be able to set value to other under-quota value.
-  to_set.Set("a", byte_value_16_->DeepCopy());
+  to_set.Set("a", byte_value_16_.CreateDeepCopy());
   EXPECT_FALSE(storage_->Set(DEFAULTS, to_set)->HasError());
-  settings.Set("a", byte_value_16_->DeepCopy());
+  settings.Set("a", byte_value_16_.CreateDeepCopy());
   EXPECT_TRUE(SettingsEqual(settings));
 
-  EXPECT_TRUE(storage_->Set(DEFAULTS, "c", *byte_value_256_)->HasError());
+  EXPECT_TRUE(storage_->Set(DEFAULTS, "c", byte_value_256_)->HasError());
   EXPECT_TRUE(SettingsEqual(settings));
 }
 
@@ -132,7 +131,7 @@
   base::DictionaryValue empty;
   CreateStorage(UINT_MAX, UINT_MAX, 0);
 
-  EXPECT_TRUE(storage_->Set(DEFAULTS, "a", *byte_value_1_)->HasError());
+  EXPECT_TRUE(storage_->Set(DEFAULTS, "a", byte_value_1_)->HasError());
   EXPECT_FALSE(storage_->Remove("a")->HasError());
   EXPECT_FALSE(storage_->Remove("b")->HasError());
   EXPECT_TRUE(SettingsEqual(empty));
@@ -142,17 +141,17 @@
   base::DictionaryValue settings;
   CreateStorage(UINT_MAX, UINT_MAX, 1);
 
-  EXPECT_FALSE(storage_->Set(DEFAULTS, "a", *byte_value_1_)->HasError());
-  settings.Set("a", byte_value_1_->DeepCopy());
+  EXPECT_FALSE(storage_->Set(DEFAULTS, "a", byte_value_1_)->HasError());
+  settings.Set("a", byte_value_1_.CreateDeepCopy());
   EXPECT_TRUE(SettingsEqual(settings));
 
   // Should be able to set existing key to other value without going over quota.
-  EXPECT_FALSE(storage_->Set(DEFAULTS, "a", *byte_value_16_)->HasError());
-  settings.Set("a", byte_value_16_->DeepCopy());
+  EXPECT_FALSE(storage_->Set(DEFAULTS, "a", byte_value_16_)->HasError());
+  settings.Set("a", byte_value_16_.CreateDeepCopy());
   EXPECT_TRUE(SettingsEqual(settings));
 
-  EXPECT_TRUE(storage_->Set(DEFAULTS, "b", *byte_value_16_)->HasError());
-  EXPECT_TRUE(storage_->Set(DEFAULTS, "c", *byte_value_256_)->HasError());
+  EXPECT_TRUE(storage_->Set(DEFAULTS, "b", byte_value_16_)->HasError());
+  EXPECT_TRUE(storage_->Set(DEFAULTS, "c", byte_value_256_)->HasError());
   EXPECT_TRUE(SettingsEqual(settings));
 }
 
@@ -161,21 +160,21 @@
   CreateStorage(UINT_MAX, UINT_MAX, 2);
 
   base::DictionaryValue to_set;
-  to_set.Set("a", byte_value_1_->DeepCopy());
-  to_set.Set("b", byte_value_16_->DeepCopy());
+  to_set.Set("a", byte_value_1_.CreateDeepCopy());
+  to_set.Set("b", byte_value_16_.CreateDeepCopy());
   EXPECT_FALSE(storage_->Set(DEFAULTS, to_set)->HasError());
-  settings.Set("a", byte_value_1_->DeepCopy());
-  settings.Set("b", byte_value_16_->DeepCopy());
+  settings.Set("a", byte_value_1_.CreateDeepCopy());
+  settings.Set("b", byte_value_16_.CreateDeepCopy());
   EXPECT_TRUE(SettingsEqual(settings));
 
   // Should be able to set existing keys to other values without going over
   // quota.
-  to_set.Set("a", byte_value_16_->DeepCopy());
+  to_set.Set("a", byte_value_16_.CreateDeepCopy());
   EXPECT_FALSE(storage_->Set(DEFAULTS, to_set)->HasError());
-  settings.Set("a", byte_value_16_->DeepCopy());
+  settings.Set("a", byte_value_16_.CreateDeepCopy());
   EXPECT_TRUE(SettingsEqual(settings));
 
-  EXPECT_TRUE(storage_->Set(DEFAULTS, "c", *byte_value_256_)->HasError());
+  EXPECT_TRUE(storage_->Set(DEFAULTS, "c", byte_value_256_)->HasError());
   EXPECT_TRUE(SettingsEqual(settings));
 }
 
@@ -183,32 +182,32 @@
   base::DictionaryValue settings;
   CreateStorage(266, UINT_MAX, 2);
 
-  storage_->Set(DEFAULTS, "b", *byte_value_16_);
-  settings.Set("b", byte_value_16_->DeepCopy());
+  storage_->Set(DEFAULTS, "b", byte_value_16_);
+  settings.Set("b", byte_value_16_.CreateDeepCopy());
   // Not enough quota.
-  storage_->Set(DEFAULTS, "c", *byte_value_256_);
+  storage_->Set(DEFAULTS, "c", byte_value_256_);
   EXPECT_TRUE(SettingsEqual(settings));
 
   // Try again with "b" removed, enough quota.
   EXPECT_FALSE(storage_->Remove("b")->HasError());
   settings.Remove("b", NULL);
-  EXPECT_FALSE(storage_->Set(DEFAULTS, "c", *byte_value_256_)->HasError());
-  settings.Set("c", byte_value_256_->DeepCopy());
+  EXPECT_FALSE(storage_->Set(DEFAULTS, "c", byte_value_256_)->HasError());
+  settings.Set("c", byte_value_256_.CreateDeepCopy());
   EXPECT_TRUE(SettingsEqual(settings));
 
   // Enough byte quota but max keys not high enough.
-  EXPECT_FALSE(storage_->Set(DEFAULTS, "a", *byte_value_1_)->HasError());
-  settings.Set("a", byte_value_1_->DeepCopy());
+  EXPECT_FALSE(storage_->Set(DEFAULTS, "a", byte_value_1_)->HasError());
+  settings.Set("a", byte_value_1_.CreateDeepCopy());
   EXPECT_TRUE(SettingsEqual(settings));
 
-  EXPECT_TRUE(storage_->Set(DEFAULTS, "b", *byte_value_1_)->HasError());
+  EXPECT_TRUE(storage_->Set(DEFAULTS, "b", byte_value_1_)->HasError());
   EXPECT_TRUE(SettingsEqual(settings));
 
   // Back under max keys.
   EXPECT_FALSE(storage_->Remove("a")->HasError());
   settings.Remove("a", NULL);
-  EXPECT_FALSE(storage_->Set(DEFAULTS, "b", *byte_value_1_)->HasError());
-  settings.Set("b", byte_value_1_->DeepCopy());
+  EXPECT_FALSE(storage_->Set(DEFAULTS, "b", byte_value_1_)->HasError());
+  settings.Set("b", byte_value_1_.CreateDeepCopy());
   EXPECT_TRUE(SettingsEqual(settings));
 }
 
@@ -218,12 +217,12 @@
 
   // Max out bytes.
   base::DictionaryValue to_set;
-  to_set.Set("b1", byte_value_16_->DeepCopy());
-  to_set.Set("b2", byte_value_16_->DeepCopy());
+  to_set.Set("b1", byte_value_16_.CreateDeepCopy());
+  to_set.Set("b2", byte_value_16_.CreateDeepCopy());
   storage_->Set(DEFAULTS, to_set);
-  settings.Set("b1", byte_value_16_->DeepCopy());
-  settings.Set("b2", byte_value_16_->DeepCopy());
-  EXPECT_TRUE(storage_->Set(DEFAULTS, "a", *byte_value_1_)->HasError());
+  settings.Set("b1", byte_value_16_.CreateDeepCopy());
+  settings.Set("b2", byte_value_16_.CreateDeepCopy());
+  EXPECT_TRUE(storage_->Set(DEFAULTS, "a", byte_value_1_)->HasError());
   EXPECT_TRUE(SettingsEqual(settings));
 
   // Remove some settings that don't exist.
@@ -235,18 +234,18 @@
   EXPECT_TRUE(SettingsEqual(settings));
 
   // Still no quota.
-  EXPECT_TRUE(storage_->Set(DEFAULTS, "a", *byte_value_1_)->HasError());
+  EXPECT_TRUE(storage_->Set(DEFAULTS, "a", byte_value_1_)->HasError());
   EXPECT_TRUE(SettingsEqual(settings));
 
   // Max out key count.
   to_set.Clear();
-  to_set.Set("b1", byte_value_1_->DeepCopy());
-  to_set.Set("b2", byte_value_1_->DeepCopy());
+  to_set.Set("b1", byte_value_1_.CreateDeepCopy());
+  to_set.Set("b2", byte_value_1_.CreateDeepCopy());
   storage_->Set(DEFAULTS, to_set);
-  settings.Set("b1", byte_value_1_->DeepCopy());
-  settings.Set("b2", byte_value_1_->DeepCopy());
-  storage_->Set(DEFAULTS, "b3", *byte_value_1_);
-  settings.Set("b3", byte_value_1_->DeepCopy());
+  settings.Set("b1", byte_value_1_.CreateDeepCopy());
+  settings.Set("b2", byte_value_1_.CreateDeepCopy());
+  storage_->Set(DEFAULTS, "b3", byte_value_1_);
+  settings.Set("b3", byte_value_1_.CreateDeepCopy());
   EXPECT_TRUE(SettingsEqual(settings));
 
   // Remove some settings that don't exist.
@@ -258,7 +257,7 @@
   EXPECT_TRUE(SettingsEqual(settings));
 
   // Still no quota.
-  EXPECT_TRUE(storage_->Set(DEFAULTS, "a", *byte_value_1_)->HasError());
+  EXPECT_TRUE(storage_->Set(DEFAULTS, "a", byte_value_1_)->HasError());
   EXPECT_TRUE(SettingsEqual(settings));
 }
 
@@ -269,35 +268,35 @@
   // Test running out of byte quota.
   {
     base::DictionaryValue to_set;
-    to_set.Set("a", byte_value_16_->DeepCopy());
-    to_set.Set("b", byte_value_16_->DeepCopy());
+    to_set.Set("a", byte_value_16_.CreateDeepCopy());
+    to_set.Set("b", byte_value_16_.CreateDeepCopy());
     EXPECT_FALSE(storage_->Set(DEFAULTS, to_set)->HasError());
-    EXPECT_TRUE(storage_->Set(DEFAULTS, "c", *byte_value_16_)->HasError());
+    EXPECT_TRUE(storage_->Set(DEFAULTS, "c", byte_value_16_)->HasError());
 
     EXPECT_FALSE(storage_->Clear()->HasError());
 
     // (repeat)
     EXPECT_FALSE(storage_->Set(DEFAULTS, to_set)->HasError());
-    EXPECT_TRUE(storage_->Set(DEFAULTS, "c", *byte_value_16_)->HasError());
+    EXPECT_TRUE(storage_->Set(DEFAULTS, "c", byte_value_16_)->HasError());
   }
 
   // Test reaching max keys.
   storage_->Clear();
   {
     base::DictionaryValue to_set;
-    to_set.Set("a", byte_value_1_->DeepCopy());
-    to_set.Set("b", byte_value_1_->DeepCopy());
-    to_set.Set("c", byte_value_1_->DeepCopy());
-    to_set.Set("d", byte_value_1_->DeepCopy());
-    to_set.Set("e", byte_value_1_->DeepCopy());
+    to_set.Set("a", byte_value_1_.CreateDeepCopy());
+    to_set.Set("b", byte_value_1_.CreateDeepCopy());
+    to_set.Set("c", byte_value_1_.CreateDeepCopy());
+    to_set.Set("d", byte_value_1_.CreateDeepCopy());
+    to_set.Set("e", byte_value_1_.CreateDeepCopy());
     EXPECT_FALSE(storage_->Set(DEFAULTS, to_set)->HasError());
-    EXPECT_TRUE(storage_->Set(DEFAULTS, "f", *byte_value_1_)->HasError());
+    EXPECT_TRUE(storage_->Set(DEFAULTS, "f", byte_value_1_)->HasError());
 
     storage_->Clear();
 
     // (repeat)
     EXPECT_FALSE(storage_->Set(DEFAULTS, to_set)->HasError());
-    EXPECT_TRUE(storage_->Set(DEFAULTS, "f", *byte_value_1_)->HasError());
+    EXPECT_TRUE(storage_->Set(DEFAULTS, "f", byte_value_1_)->HasError());
   }
 }
 
@@ -306,20 +305,20 @@
   CreateStorage(20, UINT_MAX, UINT_MAX);
 
   // Change a setting to make it go over quota.
-  storage_->Set(DEFAULTS, "a", *byte_value_16_);
-  settings.Set("a", byte_value_16_->DeepCopy());
+  storage_->Set(DEFAULTS, "a", byte_value_16_);
+  settings.Set("a", byte_value_16_.CreateDeepCopy());
   EXPECT_TRUE(SettingsEqual(settings));
 
-  EXPECT_TRUE(storage_->Set(DEFAULTS, "a", *byte_value_256_)->HasError());
+  EXPECT_TRUE(storage_->Set(DEFAULTS, "a", byte_value_256_)->HasError());
   EXPECT_TRUE(SettingsEqual(settings));
 
   // Change a setting to reduce usage and room for another setting.
-  EXPECT_TRUE(storage_->Set(DEFAULTS, "foobar", *byte_value_1_)->HasError());
-  storage_->Set(DEFAULTS, "a", *byte_value_1_);
-  settings.Set("a", byte_value_1_->DeepCopy());
+  EXPECT_TRUE(storage_->Set(DEFAULTS, "foobar", byte_value_1_)->HasError());
+  storage_->Set(DEFAULTS, "a", byte_value_1_);
+  settings.Set("a", byte_value_1_.CreateDeepCopy());
 
-  EXPECT_FALSE(storage_->Set(DEFAULTS, "foobar", *byte_value_1_)->HasError());
-  settings.Set("foobar", byte_value_1_->DeepCopy());
+  EXPECT_FALSE(storage_->Set(DEFAULTS, "foobar", byte_value_1_)->HasError());
+  settings.Set("foobar", byte_value_1_.CreateDeepCopy());
   EXPECT_TRUE(SettingsEqual(settings));
 }
 
@@ -327,22 +326,22 @@
   base::DictionaryValue settings;
   CreateStorage(40, UINT_MAX, UINT_MAX);
 
-  storage_->Set(DEFAULTS, "a", *byte_value_16_);
-  settings.Set("a", byte_value_16_->DeepCopy());
+  storage_->Set(DEFAULTS, "a", byte_value_16_);
+  settings.Set("a", byte_value_16_.CreateDeepCopy());
 
   // The entire change is over quota.
   base::DictionaryValue to_set;
-  to_set.Set("b", byte_value_16_->DeepCopy());
-  to_set.Set("c", byte_value_16_->DeepCopy());
+  to_set.Set("b", byte_value_16_.CreateDeepCopy());
+  to_set.Set("c", byte_value_16_.CreateDeepCopy());
   EXPECT_TRUE(storage_->Set(DEFAULTS, to_set)->HasError());
   EXPECT_TRUE(SettingsEqual(settings));
 
   // The entire change is over quota, but quota reduced in existing key.
-  to_set.Set("a", byte_value_1_->DeepCopy());
+  to_set.Set("a", byte_value_1_.CreateDeepCopy());
   EXPECT_FALSE(storage_->Set(DEFAULTS, to_set)->HasError());
-  settings.Set("a", byte_value_1_->DeepCopy());
-  settings.Set("b", byte_value_16_->DeepCopy());
-  settings.Set("c", byte_value_16_->DeepCopy());
+  settings.Set("a", byte_value_1_.CreateDeepCopy());
+  settings.Set("b", byte_value_16_.CreateDeepCopy());
+  settings.Set("c", byte_value_16_.CreateDeepCopy());
   EXPECT_TRUE(SettingsEqual(settings));
 }
 
@@ -350,44 +349,44 @@
   base::DictionaryValue settings;
   CreateStorage(UINT_MAX, UINT_MAX, 2);
 
-  storage_->Set(DEFAULTS, "a", *byte_value_1_);
-  settings.Set("a", byte_value_1_->DeepCopy());
+  storage_->Set(DEFAULTS, "a", byte_value_1_);
+  settings.Set("a", byte_value_1_.CreateDeepCopy());
 
   base::DictionaryValue to_set;
-  to_set.Set("b", byte_value_16_->DeepCopy());
-  to_set.Set("c", byte_value_16_->DeepCopy());
+  to_set.Set("b", byte_value_16_.CreateDeepCopy());
+  to_set.Set("c", byte_value_16_.CreateDeepCopy());
   EXPECT_TRUE(storage_->Set(DEFAULTS, to_set)->HasError());
   EXPECT_TRUE(SettingsEqual(settings));
 }
 
 TEST_F(ExtensionSettingsQuotaTest, WithInitialDataAndByteQuota) {
   base::DictionaryValue settings;
-  delegate_->Set(DEFAULTS, "a", *byte_value_256_);
-  settings.Set("a", byte_value_256_->DeepCopy());
+  delegate_->Set(DEFAULTS, "a", byte_value_256_);
+  settings.Set("a", byte_value_256_.CreateDeepCopy());
 
   CreateStorage(280, UINT_MAX, UINT_MAX);
   EXPECT_TRUE(SettingsEqual(settings));
 
   // Add some data.
-  EXPECT_FALSE(storage_->Set(DEFAULTS, "b", *byte_value_16_)->HasError());
-  settings.Set("b", byte_value_16_->DeepCopy());
+  EXPECT_FALSE(storage_->Set(DEFAULTS, "b", byte_value_16_)->HasError());
+  settings.Set("b", byte_value_16_.CreateDeepCopy());
   EXPECT_TRUE(SettingsEqual(settings));
 
   // Not enough quota.
-  EXPECT_TRUE(storage_->Set(DEFAULTS, "c", *byte_value_16_)->HasError());
+  EXPECT_TRUE(storage_->Set(DEFAULTS, "c", byte_value_16_)->HasError());
   EXPECT_TRUE(SettingsEqual(settings));
 
   // Reduce usage of original setting so that "c" can fit.
-  EXPECT_FALSE(storage_->Set(DEFAULTS, "a", *byte_value_16_)->HasError());
-  settings.Set("a", byte_value_16_->DeepCopy());
+  EXPECT_FALSE(storage_->Set(DEFAULTS, "a", byte_value_16_)->HasError());
+  settings.Set("a", byte_value_16_.CreateDeepCopy());
   EXPECT_TRUE(SettingsEqual(settings));
 
-  EXPECT_FALSE(storage_->Set(DEFAULTS, "c", *byte_value_16_)->HasError());
-  settings.Set("c", byte_value_16_->DeepCopy());
+  EXPECT_FALSE(storage_->Set(DEFAULTS, "c", byte_value_16_)->HasError());
+  settings.Set("c", byte_value_16_.CreateDeepCopy());
   EXPECT_TRUE(SettingsEqual(settings));
 
   // Remove to free up some more data.
-  EXPECT_TRUE(storage_->Set(DEFAULTS, "d", *byte_value_256_)->HasError());
+  EXPECT_TRUE(storage_->Set(DEFAULTS, "d", byte_value_256_)->HasError());
 
   std::vector<std::string> to_remove;
   to_remove.push_back("a");
@@ -397,61 +396,61 @@
   settings.Remove("b", NULL);
   EXPECT_TRUE(SettingsEqual(settings));
 
-  EXPECT_FALSE(storage_->Set(DEFAULTS, "d", *byte_value_256_)->HasError());
-  settings.Set("d", byte_value_256_->DeepCopy());
+  EXPECT_FALSE(storage_->Set(DEFAULTS, "d", byte_value_256_)->HasError());
+  settings.Set("d", byte_value_256_.CreateDeepCopy());
   EXPECT_TRUE(SettingsEqual(settings));
 }
 
 TEST_F(ExtensionSettingsQuotaTest, WithInitialDataAndMaxKeys) {
   base::DictionaryValue settings;
-  delegate_->Set(DEFAULTS, "a", *byte_value_1_);
-  settings.Set("a", byte_value_1_->DeepCopy());
+  delegate_->Set(DEFAULTS, "a", byte_value_1_);
+  settings.Set("a", byte_value_1_.CreateDeepCopy());
   CreateStorage(UINT_MAX, UINT_MAX, 2);
 
-  EXPECT_FALSE(storage_->Set(DEFAULTS, "b", *byte_value_1_)->HasError());
-  settings.Set("b", byte_value_1_->DeepCopy());
+  EXPECT_FALSE(storage_->Set(DEFAULTS, "b", byte_value_1_)->HasError());
+  settings.Set("b", byte_value_1_.CreateDeepCopy());
 
-  EXPECT_TRUE(storage_->Set(DEFAULTS, "c", *byte_value_1_)->HasError());
+  EXPECT_TRUE(storage_->Set(DEFAULTS, "c", byte_value_1_)->HasError());
 
   EXPECT_TRUE(SettingsEqual(settings));
 }
 
 TEST_F(ExtensionSettingsQuotaTest, InitiallyOverByteQuota) {
   base::DictionaryValue settings;
-  settings.Set("a", byte_value_16_->DeepCopy());
-  settings.Set("b", byte_value_16_->DeepCopy());
-  settings.Set("c", byte_value_16_->DeepCopy());
+  settings.Set("a", byte_value_16_.CreateDeepCopy());
+  settings.Set("b", byte_value_16_.CreateDeepCopy());
+  settings.Set("c", byte_value_16_.CreateDeepCopy());
   delegate_->Set(DEFAULTS, settings);
 
   CreateStorage(40, UINT_MAX, UINT_MAX);
   EXPECT_TRUE(SettingsEqual(settings));
 
-  EXPECT_TRUE(storage_->Set(DEFAULTS, "d", *byte_value_16_)->HasError());
+  EXPECT_TRUE(storage_->Set(DEFAULTS, "d", byte_value_16_)->HasError());
 
   // Take under quota by reducing size of an existing setting
-  EXPECT_FALSE(storage_->Set(DEFAULTS, "a", *byte_value_1_)->HasError());
-  settings.Set("a", byte_value_1_->DeepCopy());
+  EXPECT_FALSE(storage_->Set(DEFAULTS, "a", byte_value_1_)->HasError());
+  settings.Set("a", byte_value_1_.CreateDeepCopy());
   EXPECT_TRUE(SettingsEqual(settings));
 
   // Should be able set another small setting.
-  EXPECT_FALSE(storage_->Set(DEFAULTS, "d", *byte_value_1_)->HasError());
-  settings.Set("d", byte_value_1_->DeepCopy());
+  EXPECT_FALSE(storage_->Set(DEFAULTS, "d", byte_value_1_)->HasError());
+  settings.Set("d", byte_value_1_.CreateDeepCopy());
   EXPECT_TRUE(SettingsEqual(settings));
 }
 
 TEST_F(ExtensionSettingsQuotaTest, InitiallyOverMaxKeys) {
   base::DictionaryValue settings;
-  settings.Set("a", byte_value_16_->DeepCopy());
-  settings.Set("b", byte_value_16_->DeepCopy());
-  settings.Set("c", byte_value_16_->DeepCopy());
+  settings.Set("a", byte_value_16_.CreateDeepCopy());
+  settings.Set("b", byte_value_16_.CreateDeepCopy());
+  settings.Set("c", byte_value_16_.CreateDeepCopy());
   delegate_->Set(DEFAULTS, settings);
 
   CreateStorage(UINT_MAX, UINT_MAX, 2);
   EXPECT_TRUE(SettingsEqual(settings));
 
   // Can't set either an existing or new setting.
-  EXPECT_TRUE(storage_->Set(DEFAULTS, "d", *byte_value_16_)->HasError());
-  EXPECT_TRUE(storage_->Set(DEFAULTS, "a", *byte_value_1_)->HasError());
+  EXPECT_TRUE(storage_->Set(DEFAULTS, "d", byte_value_16_)->HasError());
+  EXPECT_TRUE(storage_->Set(DEFAULTS, "a", byte_value_1_)->HasError());
   EXPECT_TRUE(SettingsEqual(settings));
 
   // Should be able after removing 2.
@@ -461,13 +460,13 @@
   settings.Remove("b", NULL);
   EXPECT_TRUE(SettingsEqual(settings));
 
-  EXPECT_FALSE(storage_->Set(DEFAULTS, "e", *byte_value_1_)->HasError());
-  settings.Set("e", byte_value_1_->DeepCopy());
+  EXPECT_FALSE(storage_->Set(DEFAULTS, "e", byte_value_1_)->HasError());
+  settings.Set("e", byte_value_1_.CreateDeepCopy());
   EXPECT_TRUE(SettingsEqual(settings));
 
   // Still can't set any.
-  EXPECT_TRUE(storage_->Set(DEFAULTS, "d", *byte_value_16_)->HasError());
-  EXPECT_TRUE(storage_->Set(DEFAULTS, "a", *byte_value_1_)->HasError());
+  EXPECT_TRUE(storage_->Set(DEFAULTS, "d", byte_value_16_)->HasError());
+  EXPECT_TRUE(storage_->Set(DEFAULTS, "a", byte_value_1_)->HasError());
   EXPECT_TRUE(SettingsEqual(settings));
 }
 
@@ -475,7 +474,7 @@
   base::DictionaryValue empty;
   CreateStorage(UINT_MAX, 0, UINT_MAX);
 
-  EXPECT_TRUE(storage_->Set(DEFAULTS, "a", *byte_value_1_)->HasError());
+  EXPECT_TRUE(storage_->Set(DEFAULTS, "a", byte_value_1_)->HasError());
   EXPECT_FALSE(storage_->Remove("a")->HasError());
   EXPECT_FALSE(storage_->Remove("b")->HasError());
   EXPECT_TRUE(SettingsEqual(empty));
@@ -486,15 +485,15 @@
 
   CreateStorage(UINT_MAX, 20, UINT_MAX);
 
-  EXPECT_FALSE(storage_->Set(DEFAULTS, "a", *byte_value_1_)->HasError());
-  EXPECT_FALSE(storage_->Set(DEFAULTS, "a", *byte_value_16_)->HasError());
-  settings.Set("a", byte_value_16_->DeepCopy());
-  EXPECT_TRUE(storage_->Set(DEFAULTS, "a", *byte_value_256_)->HasError());
+  EXPECT_FALSE(storage_->Set(DEFAULTS, "a", byte_value_1_)->HasError());
+  EXPECT_FALSE(storage_->Set(DEFAULTS, "a", byte_value_16_)->HasError());
+  settings.Set("a", byte_value_16_.CreateDeepCopy());
+  EXPECT_TRUE(storage_->Set(DEFAULTS, "a", byte_value_256_)->HasError());
 
-  EXPECT_FALSE(storage_->Set(DEFAULTS, "b", *byte_value_1_)->HasError());
-  EXPECT_FALSE(storage_->Set(DEFAULTS, "b", *byte_value_16_)->HasError());
-  settings.Set("b", byte_value_16_->DeepCopy());
-  EXPECT_TRUE(storage_->Set(DEFAULTS, "b", *byte_value_256_)->HasError());
+  EXPECT_FALSE(storage_->Set(DEFAULTS, "b", byte_value_1_)->HasError());
+  EXPECT_FALSE(storage_->Set(DEFAULTS, "b", byte_value_16_)->HasError());
+  settings.Set("b", byte_value_16_.CreateDeepCopy());
+  EXPECT_TRUE(storage_->Set(DEFAULTS, "b", byte_value_256_)->HasError());
 
   EXPECT_TRUE(SettingsEqual(settings));
 }
@@ -502,25 +501,25 @@
 TEST_F(ExtensionSettingsQuotaTest, QuotaBytesPerSettingWithInitialSettings) {
   base::DictionaryValue settings;
 
-  delegate_->Set(DEFAULTS, "a", *byte_value_1_);
-  delegate_->Set(DEFAULTS, "b", *byte_value_16_);
-  delegate_->Set(DEFAULTS, "c", *byte_value_256_);
+  delegate_->Set(DEFAULTS, "a", byte_value_1_);
+  delegate_->Set(DEFAULTS, "b", byte_value_16_);
+  delegate_->Set(DEFAULTS, "c", byte_value_256_);
   CreateStorage(UINT_MAX, 20, UINT_MAX);
 
-  EXPECT_FALSE(storage_->Set(DEFAULTS, "a", *byte_value_1_)->HasError());
-  EXPECT_FALSE(storage_->Set(DEFAULTS, "a", *byte_value_16_)->HasError());
-  settings.Set("a", byte_value_16_->DeepCopy());
-  EXPECT_TRUE(storage_->Set(DEFAULTS, "a", *byte_value_256_)->HasError());
+  EXPECT_FALSE(storage_->Set(DEFAULTS, "a", byte_value_1_)->HasError());
+  EXPECT_FALSE(storage_->Set(DEFAULTS, "a", byte_value_16_)->HasError());
+  settings.Set("a", byte_value_16_.CreateDeepCopy());
+  EXPECT_TRUE(storage_->Set(DEFAULTS, "a", byte_value_256_)->HasError());
 
-  EXPECT_FALSE(storage_->Set(DEFAULTS, "b", *byte_value_1_)->HasError());
-  EXPECT_FALSE(storage_->Set(DEFAULTS, "b", *byte_value_16_)->HasError());
-  settings.Set("b", byte_value_16_->DeepCopy());
-  EXPECT_TRUE(storage_->Set(DEFAULTS, "b", *byte_value_256_)->HasError());
+  EXPECT_FALSE(storage_->Set(DEFAULTS, "b", byte_value_1_)->HasError());
+  EXPECT_FALSE(storage_->Set(DEFAULTS, "b", byte_value_16_)->HasError());
+  settings.Set("b", byte_value_16_.CreateDeepCopy());
+  EXPECT_TRUE(storage_->Set(DEFAULTS, "b", byte_value_256_)->HasError());
 
-  EXPECT_FALSE(storage_->Set(DEFAULTS, "c", *byte_value_1_)->HasError());
-  EXPECT_FALSE(storage_->Set(DEFAULTS, "c", *byte_value_16_)->HasError());
-  settings.Set("c", byte_value_16_->DeepCopy());
-  EXPECT_TRUE(storage_->Set(DEFAULTS, "c", *byte_value_256_)->HasError());
+  EXPECT_FALSE(storage_->Set(DEFAULTS, "c", byte_value_1_)->HasError());
+  EXPECT_FALSE(storage_->Set(DEFAULTS, "c", byte_value_16_)->HasError());
+  settings.Set("c", byte_value_16_.CreateDeepCopy());
+  EXPECT_TRUE(storage_->Set(DEFAULTS, "c", byte_value_256_)->HasError());
 
   EXPECT_TRUE(SettingsEqual(settings));
 }
@@ -532,27 +531,27 @@
   // rejected...
   base::DictionaryValue settings;
 
-  delegate_->Set(DEFAULTS, "a", *byte_value_1_);
-  delegate_->Set(DEFAULTS, "b", *byte_value_16_);
-  delegate_->Set(DEFAULTS, "c", *byte_value_256_);
+  delegate_->Set(DEFAULTS, "a", byte_value_1_);
+  delegate_->Set(DEFAULTS, "b", byte_value_16_);
+  delegate_->Set(DEFAULTS, "c", byte_value_256_);
   CreateStorage(UINT_MAX, 20, UINT_MAX);
 
-  EXPECT_FALSE(storage_->Set(IGNORE_QUOTA, "a", *byte_value_1_)->HasError());
-  EXPECT_FALSE(storage_->Set(IGNORE_QUOTA, "a", *byte_value_16_)->HasError());
-  EXPECT_FALSE(storage_->Set(IGNORE_QUOTA, "a", *byte_value_256_)->HasError());
-  settings.Set("a", byte_value_256_->DeepCopy());
+  EXPECT_FALSE(storage_->Set(IGNORE_QUOTA, "a", byte_value_1_)->HasError());
+  EXPECT_FALSE(storage_->Set(IGNORE_QUOTA, "a", byte_value_16_)->HasError());
+  EXPECT_FALSE(storage_->Set(IGNORE_QUOTA, "a", byte_value_256_)->HasError());
+  settings.Set("a", byte_value_256_.CreateDeepCopy());
 
-  EXPECT_FALSE(storage_->Set(IGNORE_QUOTA, "b", *byte_value_1_)->HasError());
-  EXPECT_FALSE(storage_->Set(IGNORE_QUOTA, "b", *byte_value_16_)->HasError());
-  EXPECT_FALSE(storage_->Set(IGNORE_QUOTA, "b", *byte_value_256_)->HasError());
-  settings.Set("b", byte_value_256_->DeepCopy());
+  EXPECT_FALSE(storage_->Set(IGNORE_QUOTA, "b", byte_value_1_)->HasError());
+  EXPECT_FALSE(storage_->Set(IGNORE_QUOTA, "b", byte_value_16_)->HasError());
+  EXPECT_FALSE(storage_->Set(IGNORE_QUOTA, "b", byte_value_256_)->HasError());
+  settings.Set("b", byte_value_256_.CreateDeepCopy());
 
-  EXPECT_FALSE(storage_->Set(IGNORE_QUOTA, "c", *byte_value_1_)->HasError());
-  EXPECT_FALSE(storage_->Set(IGNORE_QUOTA, "c", *byte_value_16_)->HasError());
-  settings.Set("c", byte_value_16_->DeepCopy());
+  EXPECT_FALSE(storage_->Set(IGNORE_QUOTA, "c", byte_value_1_)->HasError());
+  EXPECT_FALSE(storage_->Set(IGNORE_QUOTA, "c", byte_value_16_)->HasError());
+  settings.Set("c", byte_value_16_.CreateDeepCopy());
 
   // ... except the last.  Make sure it can still fail.
-  EXPECT_TRUE(storage_->Set(DEFAULTS, "c", *byte_value_256_)->HasError());
+  EXPECT_TRUE(storage_->Set(DEFAULTS, "c", byte_value_256_)->HasError());
 
   EXPECT_TRUE(SettingsEqual(settings));
 }
@@ -570,21 +569,21 @@
   EXPECT_EQ(0u, storage_->GetBytesInUse("b"));
   EXPECT_EQ(0u, storage_->GetBytesInUse(ab));
 
-  storage_->Set(DEFAULTS, "a", *byte_value_1_);
+  storage_->Set(DEFAULTS, "a", byte_value_1_);
 
   EXPECT_EQ(2u, storage_->GetBytesInUse());
   EXPECT_EQ(2u, storage_->GetBytesInUse("a"));
   EXPECT_EQ(0u, storage_->GetBytesInUse("b"));
   EXPECT_EQ(2u, storage_->GetBytesInUse(ab));
 
-  storage_->Set(DEFAULTS, "b", *byte_value_1_);
+  storage_->Set(DEFAULTS, "b", byte_value_1_);
 
   EXPECT_EQ(4u, storage_->GetBytesInUse());
   EXPECT_EQ(2u, storage_->GetBytesInUse("a"));
   EXPECT_EQ(2u, storage_->GetBytesInUse("b"));
   EXPECT_EQ(4u, storage_->GetBytesInUse(ab));
 
-  storage_->Set(DEFAULTS, "c", *byte_value_1_);
+  storage_->Set(DEFAULTS, "c", byte_value_1_);
 
   EXPECT_EQ(6u, storage_->GetBytesInUse());
   EXPECT_EQ(2u, storage_->GetBytesInUse("a"));
diff --git a/extensions/browser/api/storage/settings_storage_quota_enforcer.cc b/extensions/browser/api/storage/settings_storage_quota_enforcer.cc
index e448a5d..1fbcbbd 100644
--- a/extensions/browser/api/storage/settings_storage_quota_enforcer.cc
+++ b/extensions/browser/api/storage/settings_storage_quota_enforcer.cc
@@ -38,7 +38,7 @@
   // TODO(kalman): This is duplicating work that the leveldb delegate
   // implementation is about to do, and it would be nice to avoid this.
   std::string value_as_json;
-  base::JSONWriter::Write(&value, &value_as_json);
+  base::JSONWriter::Write(value, &value_as_json);
   size_t new_size = key.size() + value_as_json.size();
   size_t existing_size = (*used_per_setting)[key];
 
diff --git a/extensions/browser/api/web_request/web_request_api.cc b/extensions/browser/api/web_request/web_request_api.cc
index 7de492e..f6c7527 100644
--- a/extensions/browser/api/web_request/web_request_api.cc
+++ b/extensions/browser/api/web_request/web_request_api.cc
@@ -2374,7 +2374,7 @@
             headers_value->GetDictionary(i, &header_value));
         if (!FromHeaderDictionary(header_value, &name, &value)) {
           std::string serialized_header;
-          base::JSONWriter::Write(header_value, &serialized_header);
+          base::JSONWriter::Write(*header_value, &serialized_header);
           RespondWithError(event_name,
                            sub_event_name,
                            request_id,
diff --git a/extensions/browser/browser_context_keyed_api_factory.h b/extensions/browser/browser_context_keyed_api_factory.h
index dfd2887..fc0add24 100644
--- a/extensions/browser/browser_context_keyed_api_factory.h
+++ b/extensions/browser/browser_context_keyed_api_factory.h
@@ -43,9 +43,9 @@
   static const bool kServiceIsNULLWhileTesting = false;
 
   // Users of this factory template must define a GetFactoryInstance()
-  // and manage their own instances (typically using LazyInstance or
-  // Singleton), because those cannot be included in more than one
-  // translation unit (and thus cannot be initialized in a header file).
+  // and manage their own instances (using LazyInstance), because those cannot
+  // be included in more than one translation unit (and thus cannot be
+  // initialized in a header file).
   //
   // In the header file, declare GetFactoryInstance(), e.g.:
   //   class HistoryAPI {
diff --git a/extensions/browser/computed_hashes.cc b/extensions/browser/computed_hashes.cc
index 473ee3c..35ea5255 100644
--- a/extensions/browser/computed_hashes.cc
+++ b/extensions/browser/computed_hashes.cc
@@ -156,7 +156,7 @@
   top_dictionary.SetInteger(kVersionKey, kVersion);
   top_dictionary.Set(kFileHashesKey, file_list_.release());
 
-  if (!base::JSONWriter::Write(&top_dictionary, &json))
+  if (!base::JSONWriter::Write(top_dictionary, &json))
     return false;
   int written = base::WriteFile(path, json.data(), json.size());
   if (static_cast<unsigned>(written) != json.size()) {
diff --git a/extensions/browser/event_router.cc b/extensions/browser/event_router.cc
index 365cd2f..afd92d03 100644
--- a/extensions/browser/event_router.cc
+++ b/extensions/browser/event_router.cc
@@ -155,14 +155,21 @@
                                 const EventFilteringInfo& info) {
   int event_id = g_extension_event_id.GetNext();
 
+  if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
+    // This is called from WebRequest API.
+    // TODO(lazyboy): Skip this entirely: http://crbug.com/488747.
+    BrowserThread::PostTask(
+        BrowserThread::UI, FROM_HERE,
+        base::Bind(&EventRouter::IncrementInFlightEventsOnUI,
+                   browser_context_id, extension_id, event_id, event_name));
+  } else {
+    IncrementInFlightEventsOnUI(browser_context_id, extension_id, event_id,
+                                event_name);
+  }
+
   DispatchExtensionMessage(ipc_sender, browser_context_id, extension_id,
                            event_id, event_name, event_args.get(), user_gesture,
                            info);
-
-  BrowserThread::PostTask(
-      BrowserThread::UI, FROM_HERE,
-      base::Bind(&EventRouter::IncrementInFlightEventsOnUI, browser_context_id,
-                 extension_id, event_id, event_name));
 }
 
 EventRouter::EventRouter(BrowserContext* browser_context,
diff --git a/extensions/browser/extension_function_histogram_value.h b/extensions/browser/extension_function_histogram_value.h
index 9839de0..8a7081c0 100644
--- a/extensions/browser/extension_function_histogram_value.h
+++ b/extensions/browser/extension_function_histogram_value.h
@@ -1068,7 +1068,7 @@
   DEVELOPERPRIVATE_SHOWOPTIONS,
   DEVELOPERPRIVATE_SHOWPATH,
   FILEMANAGERPRIVATE_ADDPROVIDEDFILESYSTEM,
-  FILEMANAGERPRIVATE_CONFIGUREPROVIDEDFILESYSTEM,
+  FILEMANAGERPRIVATE_CONFIGUREVOLUME,
   SEARCHENGINESPRIVATE_GETSEARCHENGINES,
   SEARCHENGINESPRIVATE_SETSELECTEDSEARCHENGINE,
   AUTOFILLPRIVATE_SAVEADDRESS,
@@ -1098,6 +1098,7 @@
   PASSWORDSPRIVATE_REMOVESAVEDPASSWORD,
   PASSWORDSPRIVATE_REMOVEPASSWORDEXCEPTION,
   PASSWORDSPRIVATE_GETPLAINTEXTPASSWORD,
+  LAUNCHERPAGE_HIDE,
   // Last entry: Add new entries above and ensure to update
   // tools/metrics/histograms/histograms.xml.
   ENUM_BOUNDARY
diff --git a/extensions/browser/guest_view/web_view/web_view_guest.cc b/extensions/browser/guest_view/web_view/web_view_guest.cc
index 11aad86..43f68b9 100644
--- a/extensions/browser/guest_view/web_view/web_view_guest.cc
+++ b/extensions/browser/guest_view/web_view/web_view_guest.cc
@@ -330,8 +330,6 @@
                               content::NOTIFICATION_RESOURCE_RECEIVED_REDIRECT,
                               content::Source<WebContents>(web_contents()));
 
-  if (web_view_guest_delegate_)
-    web_view_guest_delegate_->OnDidInitialize();
   AttachWebViewHelpers(web_contents());
 
   rules_registry_id_ = GetOrGenerateRulesRegistryID(
@@ -786,11 +784,6 @@
       new GuestViewEvent(webview::kEventLoadCommit, args.Pass()));
 
   find_helper_.CancelAllFindSessions();
-
-  if (web_view_guest_delegate_) {
-    web_view_guest_delegate_->OnDidCommitProvisionalLoadForFrame(
-        !render_frame_host->GetParent());
-  }
 }
 
 void WebViewGuest::DidFailProvisionalLoad(
@@ -814,12 +807,6 @@
       new GuestViewEvent(webview::kEventLoadStart, args.Pass()));
 }
 
-void WebViewGuest::DocumentLoadedInFrame(
-    content::RenderFrameHost* render_frame_host) {
-  if (web_view_guest_delegate_)
-    web_view_guest_delegate_->OnDocumentLoadedInFrame(render_frame_host);
-}
-
 void WebViewGuest::RenderProcessGone(base::TerminationStatus status) {
   // Cancel all find sessions in progress.
   find_helper_.CancelAllFindSessions();
diff --git a/extensions/browser/guest_view/web_view/web_view_guest.h b/extensions/browser/guest_view/web_view/web_view_guest.h
index dcfd378a79..9260b74 100644
--- a/extensions/browser/guest_view/web_view/web_view_guest.h
+++ b/extensions/browser/guest_view/web_view/web_view_guest.h
@@ -295,8 +295,6 @@
       const GURL& validated_url,
       bool is_error_page,
       bool is_iframe_srcdoc) override;
-  void DocumentLoadedInFrame(
-      content::RenderFrameHost* render_frame_host) override;
   void RenderProcessGone(base::TerminationStatus status) override;
   void UserAgentOverrideSet(const std::string& user_agent) override;
   void FrameNameChanged(content::RenderFrameHost* render_frame_host,
diff --git a/extensions/browser/guest_view/web_view/web_view_guest_delegate.h b/extensions/browser/guest_view/web_view/web_view_guest_delegate.h
index b6e0f1a9..0ab06150 100644
--- a/extensions/browser/guest_view/web_view/web_view_guest_delegate.h
+++ b/extensions/browser/guest_view/web_view/web_view_guest_delegate.h
@@ -38,15 +38,6 @@
   // Called to attach helpers just after additional initialization is performed.
   virtual void OnAttachWebViewHelpers(content::WebContents* contents) = 0;
 
-  // Called when the guest WebContents commits a provisional load in any frame.
-  virtual void OnDidCommitProvisionalLoadForFrame(bool is_main_frame) = 0;
-
-  // Called just after additional initialization is performed.
-  virtual void OnDidInitialize() = 0;
-
-  virtual void OnDocumentLoadedInFrame(
-      content::RenderFrameHost* render_frame_host) = 0;
-
   // Called immediately after the guest WebContents has been destroyed.
   virtual void OnGuestDestroyed() = 0;
 
diff --git a/extensions/browser/user_script_loader.cc b/extensions/browser/user_script_loader.cc
index 7daf95d2..44070930 100644
--- a/extensions/browser/user_script_loader.cc
+++ b/extensions/browser/user_script_loader.cc
@@ -378,9 +378,9 @@
 void UserScriptLoader::SendUpdate(content::RenderProcessHost* process,
                                   base::SharedMemory* shared_memory,
                                   const std::set<HostID>& changed_hosts) {
-  // Don't allow injection of extensions' content scripts into <webview>.
-  if (process->IsIsolatedGuest() && host_id().id().empty())
-    return;
+  // Don't allow injection of non-whitelisted extensions' content scripts
+  // into <webview>.
+  bool whitelisted_only = process->IsIsolatedGuest() && host_id().id().empty();
 
   // Make sure we only send user scripts to processes in our browser_context.
   if (!ExtensionsBrowserClient::Get()->IsSameContext(
@@ -398,8 +398,8 @@
     return;  // This can legitimately fail if the renderer asserts at startup.
 
   if (base::SharedMemory::IsHandleValid(handle_for_process)) {
-    process->Send(new ExtensionMsg_UpdateUserScripts(handle_for_process,
-                                                     host_id(), changed_hosts));
+    process->Send(new ExtensionMsg_UpdateUserScripts(
+        handle_for_process, host_id(), changed_hosts, whitelisted_only));
   }
 }
 
diff --git a/extensions/browser/value_store/leveldb_value_store.cc b/extensions/browser/value_store/leveldb_value_store.cc
index ad8076d..4b7d274e 100644
--- a/extensions/browser/value_store/leveldb_value_store.cc
+++ b/extensions/browser/value_store/leveldb_value_store.cc
@@ -389,7 +389,7 @@
 
   if (write_new_value) {
     std::string value_as_json;
-    if (!base::JSONWriter::Write(&value, &value_as_json))
+    if (!base::JSONWriter::Write(value, &value_as_json))
       return Error::Create(OTHER_ERROR, kCannotSerialize, util::NewKey(key));
     batch->Put(key, value_as_json);
   }
diff --git a/extensions/browser/value_store/value_store_change.cc b/extensions/browser/value_store/value_store_change.cc
index 822c9b9..904ec82 100644
--- a/extensions/browser/value_store/value_store_change.cc
+++ b/extensions/browser/value_store/value_store_change.cc
@@ -23,7 +23,7 @@
     changes_value.SetWithoutPathExpansion(it->key(), change_value);
   }
   std::string json;
-  base::JSONWriter::Write(&changes_value, &json);
+  base::JSONWriter::Write(changes_value, &json);
   return json;
 }
 
diff --git a/extensions/browser/value_store/value_store_unittest.cc b/extensions/browser/value_store/value_store_unittest.cc
index 4293459a..c2ecbab5 100644
--- a/extensions/browser/value_store/value_store_unittest.cc
+++ b/extensions/browser/value_store/value_store_unittest.cc
@@ -18,9 +18,8 @@
 // Gets the pretty-printed JSON for a value.
 std::string GetJSON(const base::Value& value) {
   std::string json;
-  base::JSONWriter::WriteWithOptions(&value,
-                                     base::JSONWriter::OPTIONS_PRETTY_PRINT,
-                                     &json);
+  base::JSONWriter::WriteWithOptions(
+      value, base::JSONWriter::OPTIONS_PRETTY_PRINT, &json);
   return json;
 }
 
diff --git a/extensions/common/api/_behavior_features.json b/extensions/common/api/_behavior_features.json
index 7d5e923..9c81f727 100644
--- a/extensions/common/api/_behavior_features.json
+++ b/extensions/common/api/_behavior_features.json
@@ -24,7 +24,8 @@
     "platforms": ["chromeos"],
     "whitelist": [
       "307E96539209F95A1A8740C713E6998A73657D96",  // http://crbug.com/485292
-      "81986D4F846CEDDDB962643FA501D1780DD441BB"   // http://crbug.com/485292
+      "81986D4F846CEDDDB962643FA501D1780DD441BB",  // http://crbug.com/485292
+      "9E287A8257E58EFB13E89C86A4B75A3AC4B058D8"   // http://crbug.com/485292
     ]
   },
   "whitelisted_for_incognito": {
diff --git a/extensions/common/api/_permission_features.json b/extensions/common/api/_permission_features.json
index 03116b8..2897a81 100644
--- a/extensions/common/api/_permission_features.json
+++ b/extensions/common/api/_permission_features.json
@@ -260,7 +260,7 @@
     "extension_types": [ "extension", "legacy_packaged_app", "platform_app" ]
   },
   "printerProvider": {
-    "channel": "dev",
+    "channel": "stable",
     "extension_types": ["extension", "platform_app" ]
   },
   // Note: runtime is not actually a permission, but some systems check these
diff --git a/extensions/common/api/virtual_keyboard_private.json b/extensions/common/api/virtual_keyboard_private.json
index 71bdd0e..f8dd8268e2 100644
--- a/extensions/common/api/virtual_keyboard_private.json
+++ b/extensions/common/api/virtual_keyboard_private.json
@@ -39,7 +39,17 @@
         "type": "string",
         "description": "The value of type attribute of the focused text input box.",
         "enum": ["text", "number", "password", "date", "url", "tel", "email"]
-       }
+      },
+      {
+        "id": "Bounds",
+        "type": "object",
+        "properties": {
+          "left": {"type": "integer", "description": "The position of the virtual keyboard window's left edge."},
+          "top": {"type": "integer", "description": "The position of the virtual keyboard window's top edge."},
+          "width": {"type": "integer", "description": "The width of the virtual keyboard window."},
+          "height": {"type": "integer", "description": "The height of the virtual keyboard window."}
+        }
+      }
     ],
     "functions": [
       {
@@ -208,6 +218,18 @@
             }
           }
         ]
+      },
+      {
+        "name": "onBoundsChanged",
+        "type": "function",
+        "description": "This event is sent when virtual keyboard bounds changed and overscroll/resize is enabled.",
+        "parameters": [
+          {
+            "name": "bounds",
+            "description": "The virtual keyboard bounds",
+            "$ref": "Bounds"
+          }
+        ]
       }
     ]
   }
diff --git a/extensions/common/extension_messages.h b/extensions/common/extension_messages.h
index 73adbcd20..5dc4981 100644
--- a/extensions/common/extension_messages.h
+++ b/extensions/common/extension_messages.h
@@ -457,10 +457,13 @@
 // region will be updated. Note that the empty set => all hosts case is not
 // supported for per-extension programmatically-defined script regions; in such
 // regions, the owner is expected to list itself as the only changed host.
-IPC_MESSAGE_CONTROL3(ExtensionMsg_UpdateUserScripts,
+// If |whitelisted_only| is true, this process should only run whitelisted
+// scripts and not all user scripts.
+IPC_MESSAGE_CONTROL4(ExtensionMsg_UpdateUserScripts,
                      base::SharedMemoryHandle,
                      HostID /* owner */,
-                     std::set<HostID> /* changed hosts */)
+                     std::set<HostID> /* changed hosts */,
+                     bool /* whitelisted_only */)
 
 // Trigger to execute declarative content script under browser control.
 IPC_MESSAGE_ROUTED4(ExtensionMsg_ExecuteDeclarativeScript,
diff --git a/extensions/common/permissions/manifest_permission.cc b/extensions/common/permissions/manifest_permission.cc
index a3a3a09..6be6b18 100644
--- a/extensions/common/permissions/manifest_permission.cc
+++ b/extensions/common/permissions/manifest_permission.cc
@@ -48,7 +48,7 @@
 
 void ManifestPermission::Log(std::string* log) const {
   base::JSONWriter::WriteWithOptions(
-      ToValue().get(), base::JSONWriter::OPTIONS_PRETTY_PRINT, log);
+      *ToValue(), base::JSONWriter::OPTIONS_PRETTY_PRINT, log);
 }
 
 }  // namespace extensions
diff --git a/extensions/common/permissions/set_disjunction_permission.h b/extensions/common/permissions/set_disjunction_permission.h
index 87d1858..28b6867 100644
--- a/extensions/common/permissions/set_disjunction_permission.h
+++ b/extensions/common/permissions/set_disjunction_permission.h
@@ -122,7 +122,7 @@
         data_set_.insert(data);
       } else {
         std::string unknown_permission;
-        base::JSONWriter::Write(item_value, &unknown_permission);
+        base::JSONWriter::Write(*item_value, &unknown_permission);
         if (unhandled_permissions) {
           unhandled_permissions->push_back(unknown_permission);
         } else {
diff --git a/extensions/common/value_builder.cc b/extensions/common/value_builder.cc
index 3d8c2890..4011e70 100644
--- a/extensions/common/value_builder.cc
+++ b/extensions/common/value_builder.cc
@@ -20,7 +20,7 @@
 std::string DictionaryBuilder::ToJSON() const {
   std::string json;
   base::JSONWriter::WriteWithOptions(
-      dict_.get(), base::JSONWriter::OPTIONS_PRETTY_PRINT, &json);
+      *dict_, base::JSONWriter::OPTIONS_PRETTY_PRINT, &json);
   return json;
 }
 
diff --git a/extensions/extensions.gypi b/extensions/extensions.gypi
index 7985f28..f90e9a2 100644
--- a/extensions/extensions.gypi
+++ b/extensions/extensions.gypi
@@ -264,6 +264,8 @@
       'browser/api/bluetooth/bluetooth_extension_function.h',
       'browser/api/bluetooth/bluetooth_private_api.cc',
       'browser/api/bluetooth/bluetooth_private_api.h',
+      'browser/api/bluetooth_low_energy/bluetooth_api_advertisement.cc',
+      'browser/api/bluetooth_low_energy/bluetooth_api_advertisement.h',
       'browser/api/bluetooth_low_energy/bluetooth_low_energy_api.cc',
       'browser/api/bluetooth_low_energy/bluetooth_low_energy_api.h',
       'browser/api/bluetooth_low_energy/bluetooth_low_energy_connection.cc',
diff --git a/extensions/renderer/messaging_bindings.cc b/extensions/renderer/messaging_bindings.cc
index b4b315b..595bee1 100644
--- a/extensions/renderer/messaging_bindings.cc
+++ b/extensions/renderer/messaging_bindings.cc
@@ -10,7 +10,9 @@
 #include "base/basictypes.h"
 #include "base/bind.h"
 #include "base/bind_helpers.h"
+#include "base/callback.h"
 #include "base/lazy_instance.h"
+#include "base/memory/weak_ptr.h"
 #include "base/message_loop/message_loop.h"
 #include "base/values.h"
 #include "components/guest_view/common/guest_view_constants.h"
@@ -51,6 +53,72 @@
 
 namespace {
 
+// Binds |callback| to run when |object| is garbage collected. So as to not
+// re-entrantly call into v8, we execute this function asynchronously, at
+// which point |context| may have been invalidated. If so, |callback| is not
+// run, and |fallback| will be called instead.
+//
+// Deletes itself when the object args[0] is garbage collected or when the
+// context is invalidated.
+class GCCallback : public base::SupportsWeakPtr<GCCallback> {
+ public:
+  GCCallback(ScriptContext* context,
+             const v8::Local<v8::Object>& object,
+             const v8::Local<v8::Function>& callback,
+             const base::Closure& fallback)
+      : context_(context),
+        object_(context->isolate(), object),
+        callback_(context->isolate(), callback),
+        fallback_(fallback) {
+    object_.SetWeak(this, FirstWeakCallback, v8::WeakCallbackType::kParameter);
+    context->AddInvalidationObserver(
+        base::Bind(&GCCallback::OnContextInvalidated, AsWeakPtr()));
+  }
+
+ private:
+  static void FirstWeakCallback(const v8::WeakCallbackInfo<GCCallback>& data) {
+    // v8 says we need to explicitly reset weak handles from their callbacks.
+    // It's not implicit as one might expect.
+    data.GetParameter()->object_.Reset();
+    data.SetSecondPassCallback(SecondWeakCallback);
+  }
+
+  static void SecondWeakCallback(const v8::WeakCallbackInfo<GCCallback>& data) {
+    base::MessageLoop::current()->PostTask(
+        FROM_HERE,
+        base::Bind(&GCCallback::RunCallback, data.GetParameter()->AsWeakPtr()));
+  }
+
+  void RunCallback() {
+    CHECK(context_);
+    v8::Isolate* isolate = context_->isolate();
+    v8::HandleScope handle_scope(isolate);
+    context_->CallFunction(v8::Local<v8::Function>::New(isolate, callback_));
+    delete this;
+  }
+
+  void OnContextInvalidated() {
+    fallback_.Run();
+    context_ = NULL;
+    delete this;
+  }
+
+  // ScriptContext which owns this GCCallback.
+  ScriptContext* context_;
+
+  // Holds a global handle to the object this GCCallback is bound to.
+  v8::Global<v8::Object> object_;
+
+  // Function to run when |object_| bound to this GCCallback is GC'd.
+  v8::Global<v8::Function> callback_;
+
+  // Function to run if context is invalidated before we have a chance
+  // to execute |callback_|.
+  base::Closure fallback_;
+
+  DISALLOW_COPY_AND_ASSIGN(GCCallback);
+};
+
 struct ExtensionData {
   struct PortData {
     int ref_count;  // how many contexts have a handle to this port
@@ -81,7 +149,9 @@
 class ExtensionImpl : public ObjectBackedNativeHandler {
  public:
   ExtensionImpl(Dispatcher* dispatcher, ScriptContext* context)
-      : ObjectBackedNativeHandler(context), dispatcher_(dispatcher) {
+      : ObjectBackedNativeHandler(context),
+        dispatcher_(dispatcher),
+        weak_ptr_factory_(this) {
     RouteFunction(
         "CloseChannel",
         base::Bind(&ExtensionImpl::CloseChannel, base::Unretained(this)));
@@ -166,10 +236,13 @@
   // the other end of the channel.
   void PortRelease(const v8::FunctionCallbackInfo<v8::Value>& args) {
     // Arguments are (int32 port_id).
-    CHECK_EQ(1, args.Length());
-    CHECK(args[0]->IsInt32());
+    CHECK(args.Length() == 1 && args[0]->IsInt32());
+    ReleasePort(args[0]->Int32Value());
+  }
 
-    int port_id = args[0]->Int32Value();
+  // Implementation of both the PortRelease native handler call, and callback
+  // when contexts are invalidated to release their ports.
+  void ReleasePort(int port_id) {
     if (HasPortData(port_id) && --GetPortData(port_id).ref_count == 0) {
       // Send via the RenderThread because the RenderFrame might be closing.
       content::RenderThread::Get()->Send(
@@ -178,75 +251,33 @@
     }
   }
 
-  // Holds a |callback| to run sometime after |object| is GC'ed. |callback| will
-  // not be executed re-entrantly to avoid running JS in an unexpected state.
-  class GCCallback {
-   public:
-    static void Bind(v8::Local<v8::Object> object,
-                     v8::Local<v8::Function> callback,
-                     v8::Isolate* isolate) {
-      GCCallback* cb = new GCCallback(object, callback, isolate);
-      cb->object_.SetWeak(cb, FirstWeakCallback,
-                          v8::WeakCallbackType::kParameter);
-    }
-
-   private:
-    static void FirstWeakCallback(
-        const v8::WeakCallbackInfo<GCCallback>& data) {
-      // v8 says we need to explicitly reset weak handles from their callbacks.
-      // It's not implicit as one might expect.
-      data.GetParameter()->object_.Reset();
-      data.SetSecondPassCallback(SecondWeakCallback);
-    }
-
-    static void SecondWeakCallback(
-        const v8::WeakCallbackInfo<GCCallback>& data) {
-      base::MessageLoop::current()->PostTask(
-          FROM_HERE,
-          base::Bind(&GCCallback::RunCallback,
-                     base::Owned(data.GetParameter())));
-    }
-
-    GCCallback(v8::Local<v8::Object> object,
-               v8::Local<v8::Function> callback,
-               v8::Isolate* isolate)
-        : object_(isolate, object),
-          callback_(isolate, callback),
-          isolate_(isolate) {}
-
-    void RunCallback() {
-      v8::HandleScope handle_scope(isolate_);
-      v8::Local<v8::Function> callback =
-          v8::Local<v8::Function>::New(isolate_, callback_);
-      v8::Local<v8::Context> context = callback->CreationContext();
-      if (context.IsEmpty())
-        return;
-      v8::Context::Scope context_scope(context);
-      blink::WebScopedMicrotaskSuppression suppression;
-      callback->Call(context->Global(), 0, NULL);
-    }
-
-    v8::Global<v8::Object> object_;
-    v8::Global<v8::Function> callback_;
-    v8::Isolate* isolate_;
-
-    DISALLOW_COPY_AND_ASSIGN(GCCallback);
-  };
-
-  // void BindToGC(object, callback)
+  // void BindToGC(object, callback, port_id)
   //
   // Binds |callback| to be invoked *sometime after* |object| is garbage
   // collected. We don't call the method re-entrantly so as to avoid executing
-  // JS in some bizarro undefined mid-GC state.
+  // JS in some bizarro undefined mid-GC state, nor do we then call into the
+  // script context if it's been invalidated.
+  //
+  // If the script context *is* invalidated in the meantime, as a slight hack,
+  // release the port with ID |port_id| if it's >= 0.
   void BindToGC(const v8::FunctionCallbackInfo<v8::Value>& args) {
-    CHECK(args.Length() == 2 && args[0]->IsObject() && args[1]->IsFunction());
-    GCCallback::Bind(args[0].As<v8::Object>(),
-                     args[1].As<v8::Function>(),
-                     args.GetIsolate());
+    CHECK(args.Length() == 3 && args[0]->IsObject() && args[1]->IsFunction() &&
+          args[2]->IsInt32());
+    int port_id = args[2]->Int32Value();
+    base::Closure fallback = base::Bind(&base::DoNothing);
+    if (port_id >= 0) {
+      fallback = base::Bind(&ExtensionImpl::ReleasePort,
+                            weak_ptr_factory_.GetWeakPtr(), port_id);
+    }
+    // Destroys itself when the object is GC'd or context is invalidated.
+    new GCCallback(context(), args[0].As<v8::Object>(),
+                   args[1].As<v8::Function>(), fallback);
   }
 
   // Dispatcher handle. Not owned.
   Dispatcher* dispatcher_;
+
+  base::WeakPtrFactory<ExtensionImpl> weak_ptr_factory_;
 };
 
 void DispatchOnConnectToScriptContext(
diff --git a/extensions/renderer/resources/guest_view/web_view/web_view_action_requests.js b/extensions/renderer/resources/guest_view/web_view/web_view_action_requests.js
index e58e620d..f5be50a 100644
--- a/extensions/renderer/resources/guest_view/web_view/web_view_action_requests.js
+++ b/extensions/renderer/resources/guest_view/web_view/web_view_action_requests.js
@@ -66,7 +66,8 @@
 
   if (defaultPrevented) {
     // Track the lifetime of |request| with the garbage collector.
-    MessagingNatives.BindToGC(request, this.defaultAction.bind(this));
+    var portId = -1;  // (hack) there is no Extension Port to release
+    MessagingNatives.BindToGC(request, this.defaultAction.bind(this), portId);
   } else {
     this.defaultAction();
   }
diff --git a/extensions/renderer/resources/messaging.js b/extensions/renderer/resources/messaging.js
index 7a5c9104..e39795b 100644
--- a/extensions/renderer/resources/messaging.js
+++ b/extensions/renderer/resources/messaging.js
@@ -179,12 +179,18 @@
       // doesn't keep a reference to it, we need to clean up the port. Do
       // so by attaching to the garbage collection of the responseCallback
       // using some native hackery.
+      //
+      // If the context is destroyed before this has a chance to execute,
+      // BindToGC knows to release |portId| (important for updating C++ state
+      // both in this renderer and on the other end). We don't need to clear
+      // any JavaScript state, as calling destroy_() would usually do - but
+      // the context has been destroyed, so there isn't any JS state to clear.
       messagingNatives.BindToGC(responseCallback, function() {
         if (port) {
           privates(port).impl.destroy_();
           port = null;
         }
-      });
+      }, portId);
       var rv = requestEvent.dispatch(request, sender, responseCallback);
       if (isSendMessage) {
         responseCallbackPreserved =
diff --git a/extensions/renderer/script_context.cc b/extensions/renderer/script_context.cc
index f384f0c..ac87f70 100644
--- a/extensions/renderer/script_context.cc
+++ b/extensions/renderer/script_context.cc
@@ -176,7 +176,7 @@
 }
 
 v8::Local<v8::Value> ScriptContext::CallFunction(
-    v8::Local<v8::Function> function,
+    const v8::Local<v8::Function>& function,
     int argc,
     v8::Local<v8::Value> argv[]) const {
   v8::EscapableHandleScope handle_scope(isolate());
@@ -196,6 +196,11 @@
           function, global, argc, argv)));
 }
 
+v8::Local<v8::Value> ScriptContext::CallFunction(
+    const v8::Local<v8::Function>& function) const {
+  return CallFunction(function, 0, nullptr);
+}
+
 Feature::Availability ScriptContext::GetAvailability(
     const std::string& api_name) {
   // Hack: Hosted apps should have the availability of messaging APIs based on
diff --git a/extensions/renderer/script_context.h b/extensions/renderer/script_context.h
index 73579b9..012f11f7 100644
--- a/extensions/renderer/script_context.h
+++ b/extensions/renderer/script_context.h
@@ -108,9 +108,11 @@
   // must do that if they want.
   //
   // USE THIS METHOD RATHER THAN v8::Function::Call WHEREVER POSSIBLE.
-  v8::Local<v8::Value> CallFunction(v8::Local<v8::Function> function,
+  v8::Local<v8::Value> CallFunction(const v8::Local<v8::Function>& function,
                                     int argc,
                                     v8::Local<v8::Value> argv[]) const;
+  v8::Local<v8::Value> CallFunction(
+      const v8::Local<v8::Function>& function) const;
 
   void DispatchEvent(const char* event_name, v8::Local<v8::Array> args) const;
 
diff --git a/extensions/renderer/user_script_set.cc b/extensions/renderer/user_script_set.cc
index 58e9de1..929c017 100644
--- a/extensions/renderer/user_script_set.cc
+++ b/extensions/renderer/user_script_set.cc
@@ -9,6 +9,7 @@
 #include "content/public/renderer/render_thread.h"
 #include "extensions/common/extension.h"
 #include "extensions/common/extension_set.h"
+#include "extensions/common/extensions_client.h"
 #include "extensions/common/permissions/permissions_data.h"
 #include "extensions/renderer/extension_injection_host.h"
 #include "extensions/renderer/extensions_renderer_client.h"
@@ -86,7 +87,8 @@
 }
 
 bool UserScriptSet::UpdateUserScripts(base::SharedMemoryHandle shared_memory,
-                                      const std::set<HostID>& changed_hosts) {
+                                      const std::set<HostID>& changed_hosts,
+                                      bool whitelisted_only) {
   bool only_inject_incognito =
       ExtensionsRendererClient::Get()->IsIncognitoProcess();
 
@@ -140,6 +142,13 @@
     if (only_inject_incognito && !script->is_incognito_enabled())
       continue;  // This script shouldn't run in an incognito tab.
 
+    const Extension* extension = extensions_->GetByID(script->extension_id());
+    if (whitelisted_only &&
+        (!extension ||
+         !PermissionsData::CanExecuteScriptEverywhere(extension))) {
+      continue;
+    }
+
     scripts_.push_back(script.release());
   }
 
diff --git a/extensions/renderer/user_script_set.h b/extensions/renderer/user_script_set.h
index a371a94d..5ce5152 100644
--- a/extensions/renderer/user_script_set.h
+++ b/extensions/renderer/user_script_set.h
@@ -68,7 +68,8 @@
   // Updates scripts given the shared memory region containing user scripts.
   // Returns true if the scripts were successfully updated.
   bool UpdateUserScripts(base::SharedMemoryHandle shared_memory,
-                         const std::set<HostID>& changed_hosts);
+                         const std::set<HostID>& changed_hosts,
+                         bool whitelisted_only);
 
   const std::vector<UserScript*>& scripts() const { return scripts_.get(); }
 
diff --git a/extensions/renderer/user_script_set_manager.cc b/extensions/renderer/user_script_set_manager.cc
index 5a317a14..1c8f72d 100644
--- a/extensions/renderer/user_script_set_manager.cc
+++ b/extensions/renderer/user_script_set_manager.cc
@@ -96,7 +96,8 @@
 void UserScriptSetManager::OnUpdateUserScripts(
     base::SharedMemoryHandle shared_memory,
     const HostID& host_id,
-    const std::set<HostID>& changed_hosts) {
+    const std::set<HostID>& changed_hosts,
+    bool whitelisted_only) {
   if (!base::SharedMemory::IsHandleValid(shared_memory)) {
     NOTREACHED() << "Bad scripts handle";
     return;
@@ -147,7 +148,9 @@
     effective_hosts = &all_hosts;
   }
 
-  if (scripts->UpdateUserScripts(shared_memory, *effective_hosts)) {
+  if (scripts->UpdateUserScripts(shared_memory,
+                                 *effective_hosts,
+                                 whitelisted_only)) {
     FOR_EACH_OBSERVER(
         Observer,
         observers_,
diff --git a/extensions/renderer/user_script_set_manager.h b/extensions/renderer/user_script_set_manager.h
index 49e547a3..02d22efc 100644
--- a/extensions/renderer/user_script_set_manager.h
+++ b/extensions/renderer/user_script_set_manager.h
@@ -91,7 +91,8 @@
   // Handle the UpdateUserScripts extension message.
   void OnUpdateUserScripts(base::SharedMemoryHandle shared_memory,
                            const HostID& host_id,
-                           const std::set<HostID>& changed_hosts);
+                           const std::set<HostID>& changed_hosts,
+                           bool whitelisted_only);
 
   // Scripts statically defined in extension manifests.
   UserScriptSet static_scripts_;
diff --git a/google_apis/drive/drive_api_requests.cc b/google_apis/drive/drive_api_requests.cc
index 5cd289a..57a3ec1 100644
--- a/google_apis/drive/drive_api_requests.cc
+++ b/google_apis/drive/drive_api_requests.cc
@@ -130,7 +130,7 @@
 
   AttachProperties(properties, &root);
   std::string json_string;
-  base::JSONWriter::Write(&root, &json_string);
+  base::JSONWriter::Write(root, &json_string);
   return json_string;
 }
 
@@ -417,7 +417,7 @@
     root.SetString("title", title_);
 
   AttachProperties(properties_, &root);
-  base::JSONWriter::Write(&root, upload_content);
+  base::JSONWriter::Write(root, upload_content);
 
   DVLOG(1) << "FilesInsert data: " << *upload_content_type << ", ["
            << *upload_content << "]";
@@ -491,7 +491,7 @@
   }
 
   AttachProperties(properties_, &root);
-  base::JSONWriter::Write(&root, upload_content);
+  base::JSONWriter::Write(root, upload_content);
 
   DVLOG(1) << "FilesPatch data: " << *upload_content_type << ", ["
            << *upload_content << "]";
@@ -545,7 +545,7 @@
   if (!title_.empty())
     root.SetString("title", title_);
 
-  base::JSONWriter::Write(&root, upload_content);
+  base::JSONWriter::Write(root, upload_content);
   DVLOG(1) << "FilesCopy data: " << *upload_content_type << ", ["
            << *upload_content << "]";
   return true;
@@ -755,7 +755,7 @@
   base::DictionaryValue root;
   root.SetString("id", id_);
 
-  base::JSONWriter::Write(&root, upload_content);
+  base::JSONWriter::Write(root, upload_content);
   DVLOG(1) << "InsertResource data: " << *upload_content_type << ", ["
            << *upload_content << "]";
   return true;
@@ -834,7 +834,7 @@
   }
 
   AttachProperties(properties_, &root);
-  base::JSONWriter::Write(&root, upload_content);
+  base::JSONWriter::Write(root, upload_content);
 
   DVLOG(1) << "InitiateUploadNewFile data: " << *upload_content_type << ", ["
            << *upload_content << "]";
@@ -906,7 +906,7 @@
     return false;
 
   *upload_content_type = util::kContentTypeApplicationJson;
-  base::JSONWriter::Write(&root, upload_content);
+  base::JSONWriter::Write(root, upload_content);
   DVLOG(1) << "InitiateUploadExistingFile data: " << *upload_content_type
            << ", [" << *upload_content << "]";
   return true;
@@ -1158,7 +1158,7 @@
       break;
   }
   root.SetString("value", value_);
-  base::JSONWriter::Write(&root, upload_content);
+  base::JSONWriter::Write(root, upload_content);
   return true;
 }
 
diff --git a/google_apis/gaia/fake_gaia.cc b/google_apis/gaia/fake_gaia.cc
index bf2331d9..1bf87ca7 100644
--- a/google_apis/gaia/fake_gaia.cc
+++ b/google_apis/gaia/fake_gaia.cc
@@ -390,7 +390,7 @@
 void FakeGaia::FormatJSONResponse(const base::DictionaryValue& response_dict,
                                   BasicHttpResponse* http_response) {
   std::string response_json;
-  base::JSONWriter::Write(&response_dict, &response_json);
+  base::JSONWriter::Write(response_dict, &response_json);
   http_response->set_content(response_json);
   http_response->set_code(net::HTTP_OK);
 }
diff --git a/google_apis/gaia/gaia_auth_fetcher.cc b/google_apis/gaia/gaia_auth_fetcher.cc
index 83d6522..b19e5f4 100644
--- a/google_apis/gaia/gaia_auth_fetcher.cc
+++ b/google_apis/gaia/gaia_auth_fetcher.cc
@@ -115,6 +115,9 @@
     "client_secret=%s&"
     "code=%s";
 // static
+const char GaiaAuthFetcher::kOAuth2CodeToTokenPairDeviceIdParam[] =
+    "device_id=%s&device_type=chrome";
+// static
 const char GaiaAuthFetcher::kOAuth2RevokeTokenBodyFormat[] =
     "token=%s";
 // static
@@ -341,7 +344,8 @@
 
 // static
 std::string GaiaAuthFetcher::MakeGetTokenPairBody(
-    const std::string& auth_code) {
+    const std::string& auth_code,
+    const std::string& device_id) {
   std::string encoded_scope = net::EscapeUrlEncodedData(
       GaiaConstants::kOAuth1LoginScope, true);
   std::string encoded_client_id = net::EscapeUrlEncodedData(
@@ -349,11 +353,15 @@
   std::string encoded_client_secret = net::EscapeUrlEncodedData(
       GaiaUrls::GetInstance()->oauth2_chrome_client_secret(), true);
   std::string encoded_auth_code = net::EscapeUrlEncodedData(auth_code, true);
-  return base::StringPrintf(kOAuth2CodeToTokenPairBodyFormat,
-                            encoded_scope.c_str(),
-                            encoded_client_id.c_str(),
-                            encoded_client_secret.c_str(),
-                            encoded_auth_code.c_str());
+  std::string body = base::StringPrintf(
+      kOAuth2CodeToTokenPairBodyFormat, encoded_scope.c_str(),
+      encoded_client_id.c_str(), encoded_client_secret.c_str(),
+      encoded_auth_code.c_str());
+  if (!device_id.empty()) {
+    body += "&" + base::StringPrintf(kOAuth2CodeToTokenPairDeviceIdParam,
+                                     device_id.c_str());
+  }
+  return body;
 }
 
 // static
@@ -678,10 +686,16 @@
 
 void GaiaAuthFetcher::StartAuthCodeForOAuth2TokenExchange(
     const std::string& auth_code) {
+  StartAuthCodeForOAuth2TokenExchangeWithDeviceId(auth_code, std::string());
+}
+
+void GaiaAuthFetcher::StartAuthCodeForOAuth2TokenExchangeWithDeviceId(
+    const std::string& auth_code,
+    const std::string& device_id) {
   DCHECK(!fetch_pending_) << "Tried to fetch two things at once!";
 
   DVLOG(1) << "Starting OAuth token pair fetch";
-  request_body_ = MakeGetTokenPairBody(auth_code);
+  request_body_ = MakeGetTokenPairBody(auth_code, device_id);
   fetcher_ =
       CreateGaiaFetcher(getter_, request_body_, std::string(),
                         oauth2_token_gurl_, kLoadFlagsIgnoreCookies, this);
diff --git a/google_apis/gaia/gaia_auth_fetcher.h b/google_apis/gaia/gaia_auth_fetcher.h
index c2c8f64..31ea47d 100644
--- a/google_apis/gaia/gaia_auth_fetcher.h
+++ b/google_apis/gaia/gaia_auth_fetcher.h
@@ -139,6 +139,17 @@
   // called on the consumer on the original thread.
   void StartAuthCodeForOAuth2TokenExchange(const std::string& auth_code);
 
+  // Start a request to exchange the authorization code for an OAuthLogin-scoped
+  // oauth2 token.
+  // Resulting refresh token is annotated on the server with |device_id|. Format
+  // of device_id on the server is at most 64 unicode characters.
+  //
+  // Either OnClientOAuthSuccess or OnClientOAuthFailure will be
+  // called on the consumer on the original thread.
+  void StartAuthCodeForOAuth2TokenExchangeWithDeviceId(
+      const std::string& auth_code,
+      const std::string& device_id);
+
   // Start a request to get user info for the account identified by |lsid|.
   //
   // Either OnGetUserInfoSuccess or OnGetUserInfoFailure will be
@@ -238,6 +249,8 @@
   static const char kClientLoginToOAuth2WithDeviceTypeBodyFormat[];
   // The format of the POST body to get OAuth2 token pair from auth code.
   static const char kOAuth2CodeToTokenPairBodyFormat[];
+  // Additional param for the POST body to get OAuth2 token pair from auth code.
+  static const char kOAuth2CodeToTokenPairDeviceIdParam[];
   // The format of the POST body to revoke an OAuth2 token.
   static const char kOAuth2RevokeTokenBodyFormat[];
   // The format of the POST body for GetUserInfo.
@@ -379,8 +392,10 @@
                                             const char* const service);
   // Create body to get OAuth2 auth code.
   static std::string MakeGetAuthCodeBody(bool include_device_type);
-  // Given auth code, create body to get OAuth2 token pair.
-  static std::string MakeGetTokenPairBody(const std::string& auth_code);
+  // Given auth code and device ID (optional), create body to get OAuth2 token
+  // pair.
+  static std::string MakeGetTokenPairBody(const std::string& auth_code,
+                                          const std::string& device_id);
   // Given an OAuth2 token, create body to revoke the token.
   std::string MakeRevokeTokenBody(const std::string& auth_token);
   // Supply the lsid returned from ClientLogin in order to fetch
diff --git a/gpu/BUILD.gn b/gpu/BUILD.gn
index 4df2569..f9b7300 100644
--- a/gpu/BUILD.gn
+++ b/gpu/BUILD.gn
@@ -241,9 +241,10 @@
     "//testing/gtest",
     "//third_party/angle:translator",
     "//ui/gfx",
-    "//ui/gfx:test_support",
     "//ui/gfx/geometry",
+    "//ui/gfx:test_support",
     "//ui/gl",
+    "//ui/gl:gl_unittest_utils",
     "//gpu/command_buffer/common:gles2_utils",
     "//gpu/command_buffer/client:gles2_c_lib",
     "//gpu/command_buffer/client:gles2_implementation",
diff --git a/gpu/tools/compositor_model_bench/render_tree.cc b/gpu/tools/compositor_model_bench/render_tree.cc
index 8712a97..ff60961 100644
--- a/gpu/tools/compositor_model_bench/render_tree.cc
+++ b/gpu/tools/compositor_model_bench/render_tree.cc
@@ -442,7 +442,7 @@
 
 
   string outjson;
-  JSONWriter::WriteWithOptions(node, base::JSONWriter::OPTIONS_PRETTY_PRINT,
+  JSONWriter::WriteWithOptions(*node, base::JSONWriter::OPTIONS_PRETTY_PRINT,
                                &outjson);
   LOG(ERROR) << "Unrecognized node type! JSON:\n\n"
       "-----------------------\n" <<
diff --git a/ios/web/web_state/ui/crw_web_controller_observer_unittest.mm b/ios/web/web_state/ui/crw_web_controller_observer_unittest.mm
index 9fd9358..9b99c9a 100644
--- a/ios/web/web_state/ui/crw_web_controller_observer_unittest.mm
+++ b/ios/web/web_state/ui/crw_web_controller_observer_unittest.mm
@@ -68,7 +68,7 @@
   base::DictionaryValue command;
   command.SetString("command", "test.testMessage");
   std::string message;
-  base::JSONWriter::Write(&command, &message);
+  base::JSONWriter::Write(command, &message);
   this->RunJavaScript([NSString
       stringWithFormat:@"__gCrWeb.message.invokeOnHost(%s)", message.c_str()]);
   this->WaitForBackgroundTasks();
@@ -91,7 +91,7 @@
   command.SetString("target", "target");
   command.SetString("referrerPolicy", "referrerPolicy");
   std::string message;
-  base::JSONWriter::Write(&command, &message);
+  base::JSONWriter::Write(command, &message);
   this->RunJavaScript(
       [NSString stringWithFormat:@"__gCrWeb.message.invokeOnHostImmediate(%s)",
                                  message.c_str()]);
@@ -112,7 +112,7 @@
   for (int count = 0; count <= kNumberMessages; count++) {
     std::string message;
     command.SetInteger("number", count);
-    base::JSONWriter::Write(&command, &message);
+    base::JSONWriter::Write(command, &message);
     ASSERT_EQ(0U,
               [this->fake_web_controller_observer_ commandsReceived].size());
     this->RunJavaScript(
diff --git a/ios/web/webui/web_ui_ios_impl.mm b/ios/web/webui/web_ui_ios_impl.mm
index 810f3a7..8913f79d7 100644
--- a/ios/web/webui/web_ui_ios_impl.mm
+++ b/ios/web/webui/web_ui_ios_impl.mm
@@ -27,7 +27,7 @@
     if (i > 0)
       parameters += base::char16(',');
 
-    base::JSONWriter::Write(arg_list[i], &json);
+    base::JSONWriter::Write(*arg_list[i], &json);
     parameters += base::UTF8ToUTF16(json);
   }
   return base::ASCIIToUTF16(function_name) + base::char16('(') + parameters +
diff --git a/ipc/ipc_message_utils.cc b/ipc/ipc_message_utils.cc
index adb14d1..a00e857e 100644
--- a/ipc/ipc_message_utils.cc
+++ b/ipc/ipc_message_utils.cc
@@ -451,7 +451,7 @@
 void ParamTraits<base::DictionaryValue>::Log(const param_type& p,
                                              std::string* l) {
   std::string json;
-  base::JSONWriter::Write(&p, &json);
+  base::JSONWriter::Write(p, &json);
   l->append(json);
 }
 
@@ -533,7 +533,7 @@
 
 void ParamTraits<base::ListValue>::Log(const param_type& p, std::string* l) {
   std::string json;
-  base::JSONWriter::Write(&p, &json);
+  base::JSONWriter::Write(p, &json);
   l->append(json);
 }
 
diff --git a/jingle/glue/chrome_async_socket_unittest.cc b/jingle/glue/chrome_async_socket_unittest.cc
index 78b07a6c..a785553 100644
--- a/jingle/glue/chrome_async_socket_unittest.cc
+++ b/jingle/glue/chrome_async_socket_unittest.cc
@@ -93,6 +93,14 @@
     writes_.push_back(mock_write);
   }
 
+  bool AllReadDataConsumed() const override {
+    return reads_.empty();
+  }
+
+  bool AllWriteDataConsumed() const override {
+    return writes_.empty();
+  }
+
  private:
   std::deque<net::MockRead> reads_;
   bool has_pending_read_;
diff --git a/jingle/glue/utils.cc b/jingle/glue/utils.cc
index 4d35650..4c9f4b6 100644
--- a/jingle/glue/utils.cc
+++ b/jingle/glue/utils.cc
@@ -46,7 +46,7 @@
   value.SetInteger("generation", candidate.generation());
 
   std::string result;
-  base::JSONWriter::Write(&value, &result);
+  base::JSONWriter::Write(value, &result);
   return result;
 }
 
diff --git a/mandoline/app/android/apk/AndroidManifest.xml b/mandoline/app/android/apk/AndroidManifest.xml
index 07318e39..b59b8c9 100644
--- a/mandoline/app/android/apk/AndroidManifest.xml
+++ b/mandoline/app/android/apk/AndroidManifest.xml
@@ -26,6 +26,9 @@
                   android:hardwareAccelerated="true">
             <intent-filter>
                 <action android:name="android.intent.action.VIEW"/>
+                <category android:name="android.intent.category.DEFAULT"/>
+                <data android:scheme="http"/>
+                <data android:scheme="https"/>
             </intent-filter>
         </activity>
     </application>
diff --git a/mandoline/app/core_services_initialization.cc b/mandoline/app/core_services_initialization.cc
index 5eeb30ce..612dd2b 100644
--- a/mandoline/app/core_services_initialization.cc
+++ b/mandoline/app/core_services_initialization.cc
@@ -14,6 +14,11 @@
   mojo::shell::ApplicationManager* manager = context->application_manager();
   manager->RegisterApplicationPackageAlias(GURL("mojo:clipboard"),
                                            GURL("mojo:core_services"), "Core");
+#if !defined(OS_ANDROID)
+  manager->RegisterApplicationPackageAlias(GURL("mojo:native_viewport_service"),
+                                           GURL("mojo:core_services"),
+                                           "Surfaces");
+#endif
   manager->RegisterApplicationPackageAlias(
       GURL("mojo:network_service"), GURL("mojo:core_services"), "Network");
 #if !defined(OS_ANDROID)
diff --git a/mandoline/services/core_services/BUILD.gn b/mandoline/services/core_services/BUILD.gn
index 4bc6c9e..19ec9af 100644
--- a/mandoline/services/core_services/BUILD.gn
+++ b/mandoline/services/core_services/BUILD.gn
@@ -77,8 +77,9 @@
 
   if (!is_android) {
     deps += [
+      "//components/native_viewport:lib",
+      "//components/native_viewport/public/cpp:args",
       "//mandoline/ui/omnibox:lib",
-      "//mojo/services/network:lib",
     ]
   }
 }
diff --git a/mandoline/services/core_services/DEPS b/mandoline/services/core_services/DEPS
index 5234781d..2035162d 100644
--- a/mandoline/services/core_services/DEPS
+++ b/mandoline/services/core_services/DEPS
@@ -1,6 +1,7 @@
 include_rules = [
   "+components/clipboard",
   "+components/kiosk_wm",
+  "+components/native_viewport",
   "+components/resource_provider",
   "+components/surfaces",
   "+components/view_manager",
diff --git a/mandoline/services/core_services/core_services_application_delegate.cc b/mandoline/services/core_services/core_services_application_delegate.cc
index 90e9314..5eeb52c 100644
--- a/mandoline/services/core_services/core_services_application_delegate.cc
+++ b/mandoline/services/core_services/core_services_application_delegate.cc
@@ -6,6 +6,7 @@
 
 #include "base/bind.h"
 #include "components/clipboard/clipboard_application_delegate.h"
+#include "components/native_viewport/native_viewport_application_delegate.h"
 #include "components/resource_provider/resource_provider_app.h"
 #include "components/surfaces/surfaces_service_application.h"
 #include "components/view_manager/view_manager_app.h"
@@ -13,12 +14,12 @@
 #include "mojo/application/public/cpp/application_connection.h"
 #include "mojo/application/public/cpp/application_impl.h"
 #include "mojo/common/message_pump_mojo.h"
+#include "mojo/services/network/network_service_delegate.h"
 #include "mojo/services/tracing/tracing_app.h"
 #include "url/gurl.h"
 
 #if !defined(OS_ANDROID)
 #include "mandoline/ui/omnibox/omnibox_impl.h"
-#include "mojo/services/network/network_service_delegate.h"
 #endif
 
 namespace core_services {
@@ -129,8 +130,12 @@
   if (url == "mojo://clipboard/")
     delegate.reset(new clipboard::ClipboardApplicationDelegate);
 #if !defined(OS_ANDROID)
+  else if (url == "mojo://native_viewport_service/")
+    delegate.reset(new native_viewport::NativeViewportApplicationDelegate);
+#endif
   else if (url == "mojo://network_service/")
     delegate.reset(new NetworkServiceDelegate);
+#if !defined(OS_ANDROID)
   else if (url == "mojo://omnibox/")
     delegate.reset(new mandoline::OmniboxImpl);
 #endif
@@ -152,6 +157,8 @@
   // In the case of mojo:network_service, we must use an IO message loop.
   if (url == "mojo://network_service/") {
     thread_options.message_loop_type = base::MessageLoop::TYPE_IO;
+  } else if (url == "mojo://native_viewport_service/") {
+    thread_options.message_loop_type = base::MessageLoop::TYPE_UI;
   } else {
     // We must use a MessagePumpMojo to awake on mojo messages.
     thread_options.message_pump_factory =
diff --git a/mandoline/ui/browser/BUILD.gn b/mandoline/ui/browser/BUILD.gn
index 48149ee..bebb90d 100644
--- a/mandoline/ui/browser/BUILD.gn
+++ b/mandoline/ui/browser/BUILD.gn
@@ -71,5 +71,6 @@
 mojom("interfaces") {
   sources = [
     "omnibox.mojom",
+    "view_embedder.mojom",
   ]
 }
diff --git a/mandoline/ui/browser/browser.cc b/mandoline/ui/browser/browser.cc
index 741346a81..19d0d130 100644
--- a/mandoline/ui/browser/browser.cc
+++ b/mandoline/ui/browser/browser.cc
@@ -36,7 +36,7 @@
       omnibox_(nullptr),
       navigator_host_(this),
       ui_(nullptr) {
-  exposed_services_impl_.AddService(this);
+  exposed_services_impl_.AddService<mojo::NavigatorHost>(this);
 }
 
 Browser::~Browser() {
@@ -72,6 +72,7 @@
 
 bool Browser::ConfigureOutgoingConnection(
     mojo::ApplicationConnection* connection) {
+  connection->AddService<ViewEmbedder>(this);
   return true;
 }
 
@@ -122,24 +123,6 @@
   ReplaceContentWithURL(url);
 }
 
-void Browser::Create(mojo::ApplicationConnection* connection,
-                     mojo::InterfaceRequest<mojo::NavigatorHost> request) {
-  navigator_host_.Bind(request.Pass());
-}
-
-void Browser::ShowOmnibox(
-    const mojo::String& url,
-    mojo::InterfaceRequest<mojo::ServiceProvider> services,
-    mojo::ServiceProviderPtr exposed_services) {
-  if (!omnibox_) {
-    omnibox_ = root_->view_manager()->CreateView();
-    root_->AddChild(omnibox_);
-    omnibox_->SetVisible(true);
-    omnibox_->SetBounds(root_->bounds());
-  }
-  omnibox_->Embed(url, services.Pass(), exposed_services.Pass());
-}
-
 void Browser::Embed(const mojo::String& url,
                     mojo::InterfaceRequest<mojo::ServiceProvider> services,
                     mojo::ServiceProviderPtr exposed_services) {
@@ -170,4 +153,27 @@
   navigator_host_.RecordNavigation(url);
 }
 
+void Browser::Create(mojo::ApplicationConnection* connection,
+                     mojo::InterfaceRequest<mojo::NavigatorHost> request) {
+  navigator_host_.Bind(request.Pass());
+}
+
+void Browser::Create(mojo::ApplicationConnection* connection,
+                     mojo::InterfaceRequest<ViewEmbedder> request) {
+  view_embedder_bindings_.AddBinding(this, request.Pass());
+}
+
+void Browser::ShowOmnibox(
+    const mojo::String& url,
+    mojo::InterfaceRequest<mojo::ServiceProvider> services,
+    mojo::ServiceProviderPtr exposed_services) {
+  if (!omnibox_) {
+    omnibox_ = root_->view_manager()->CreateView();
+    root_->AddChild(omnibox_);
+    omnibox_->SetVisible(true);
+    omnibox_->SetBounds(root_->bounds());
+  }
+  omnibox_->Embed(url, services.Pass(), exposed_services.Pass());
+}
+
 }  // namespace mandoline
diff --git a/mandoline/ui/browser/browser.h b/mandoline/ui/browser/browser.h
index a972509..0cb7612 100644
--- a/mandoline/ui/browser/browser.h
+++ b/mandoline/ui/browser/browser.h
@@ -11,10 +11,12 @@
 #include "mandoline/services/navigation/public/interfaces/navigation.mojom.h"
 #include "mandoline/ui/browser/navigator_host_impl.h"
 #include "mandoline/ui/browser/omnibox.mojom.h"
+#include "mandoline/ui/browser/view_embedder.mojom.h"
 #include "mojo/application/public/cpp/application_delegate.h"
 #include "mojo/application/public/cpp/application_impl.h"
 #include "mojo/application/public/cpp/connect.h"
 #include "mojo/application/public/cpp/service_provider_impl.h"
+#include "mojo/common/weak_binding_set.h"
 #include "ui/mojo/events/input_events.mojom.h"
 #include "url/gurl.h"
 
@@ -31,7 +33,9 @@
                 public mojo::ViewManagerDelegate,
                 public mojo::ViewManagerRootClient,
                 public OmniboxClient,
-                public mojo::InterfaceFactory<mojo::NavigatorHost> {
+                public ViewEmbedder,
+                public mojo::InterfaceFactory<mojo::NavigatorHost>,
+                public mojo::InterfaceFactory<ViewEmbedder> {
  public:
   Browser();
   ~Browser() override;
@@ -63,13 +67,18 @@
   // Overridden from OmniboxClient:
   void OpenURL(const mojo::String& url) override;
 
+  // Overridden from ViewEmbedder:
+  void Embed(const mojo::String& url,
+             mojo::InterfaceRequest<mojo::ServiceProvider> services,
+             mojo::ServiceProviderPtr exposed_services) override;
+
   // Overridden from mojo::InterfaceFactory<mojo::NavigatorHost>:
   void Create(mojo::ApplicationConnection* connection,
               mojo::InterfaceRequest<mojo::NavigatorHost> request) override;
 
-  void Embed(const mojo::String& url,
-             mojo::InterfaceRequest<mojo::ServiceProvider> services,
-             mojo::ServiceProviderPtr exposed_services);
+  // Overridden from mojo::InterfaceFactory<ViewEmbedder>:
+  void Create(mojo::ApplicationConnection* connection,
+              mojo::InterfaceRequest<ViewEmbedder> request) override;
 
   void ShowOmnibox(const mojo::String& url,
                    mojo::InterfaceRequest<mojo::ServiceProvider> services,
@@ -88,6 +97,8 @@
   mojo::ServiceProviderImpl exposed_services_impl_;
   scoped_ptr<MergedServiceProvider> merged_service_provider_;
 
+  mojo::WeakBindingSet<ViewEmbedder> view_embedder_bindings_;
+
   NavigatorHostImpl navigator_host_;
 
   GURL current_url_;
diff --git a/mandoline/ui/browser/view_embedder.mojom b/mandoline/ui/browser/view_embedder.mojom
new file mode 100644
index 0000000..238da6fe
--- /dev/null
+++ b/mandoline/ui/browser/view_embedder.mojom
@@ -0,0 +1,13 @@
+// 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.
+
+module mandoline;
+
+import "mojo/application/public/interfaces/service_provider.mojom";
+
+interface ViewEmbedder {
+  Embed(string url,
+        mojo.ServiceProvider&? services,
+        mojo.ServiceProvider? exposed_services);
+};
diff --git a/mandoline/ui/omnibox/omnibox_impl.cc b/mandoline/ui/omnibox/omnibox_impl.cc
index e41149d..b310c032 100644
--- a/mandoline/ui/omnibox/omnibox_impl.cc
+++ b/mandoline/ui/omnibox/omnibox_impl.cc
@@ -39,6 +39,7 @@
     mojo::ApplicationConnection* connection) {
   connection->AddService<Omnibox>(this);
   connection->AddService(view_manager_client_factory_.get());
+  connection->ConnectToService(&view_embedder_);
   return true;
 }
 
@@ -59,9 +60,11 @@
     edit_->set_controller(this);
   }
 
+  const int kOpacity = 0xC0;
   views::WidgetDelegateView* widget_delegate = new views::WidgetDelegateView;
   widget_delegate->GetContentsView()->set_background(
-    views::Background::CreateSolidBackground(0xFFDDDDDD));
+      views::Background::CreateSolidBackground(
+          SkColorSetA(0xDDDDDD, kOpacity)));
   widget_delegate->GetContentsView()->AddChildView(edit_);
   widget_delegate->GetContentsView()->SetLayoutManager(this);
 
@@ -74,8 +77,11 @@
       new NativeWidgetViewManager(widget, app_impl_->shell(), root);
   params.delegate = widget_delegate;
   params.bounds = root->bounds().To<gfx::Rect>();
+  params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
   widget->Init(params);
   widget->Show();
+  widget->GetCompositor()->SetBackgroundColor(
+      SkColorSetA(SK_ColorBLACK, kOpacity));
   root->SetFocus();
   edit_->SetText(url_.To<base::string16>());
   edit_->SelectAll(false);
@@ -129,7 +135,8 @@
 
 void OmniboxImpl::ShowForURL(const mojo::String& url) {
   url_ = url;
-  // TODO: get embedding working.
+
+  view_embedder_->Embed("mojo:omnibox", nullptr, nullptr);
 }
 
 }  // namespace mandoline
diff --git a/mandoline/ui/omnibox/omnibox_impl.h b/mandoline/ui/omnibox/omnibox_impl.h
index 0d59c76..2c3e97ab 100644
--- a/mandoline/ui/omnibox/omnibox_impl.h
+++ b/mandoline/ui/omnibox/omnibox_impl.h
@@ -7,6 +7,7 @@
 
 #include "components/view_manager/public/cpp/view_manager_delegate.h"
 #include "mandoline/ui/browser/omnibox.mojom.h"
+#include "mandoline/ui/browser/view_embedder.mojom.h"
 #include "mojo/application/public/cpp/application_delegate.h"
 #include "mojo/application/public/cpp/interface_factory.h"
 #include "mojo/common/weak_binding_set.h"
@@ -68,6 +69,7 @@
   views::Textfield* edit_;
   mojo::WeakBindingSet<Omnibox> bindings_;
   scoped_ptr<mojo::ViewManagerClientFactory> view_manager_client_factory_;
+  ViewEmbedderPtr view_embedder_;
 
   DISALLOW_COPY_AND_ASSIGN(OmniboxImpl);
 };
diff --git a/media/audio/audio_manager_base.cc b/media/audio/audio_manager_base.cc
index dbe1b68..fe7c12e 100644
--- a/media/audio/audio_manager_base.cc
+++ b/media/audio/audio_manager_base.cc
@@ -200,6 +200,9 @@
     return NULL;
   }
 
+  DVLOG(2) << "Creating a new AudioInputStream with buffer size = "
+           << params.frames_per_buffer();
+
   AudioInputStream* stream;
   switch (params.format()) {
     case AudioParameters::AUDIO_PCM_LINEAR:
diff --git a/media/base/BUILD.gn b/media/base/BUILD.gn
index 2474ff9..d81171e 100644
--- a/media/base/BUILD.gn
+++ b/media/base/BUILD.gn
@@ -63,6 +63,7 @@
     "byte_queue.h",
     "cdm_callback_promise.cc",
     "cdm_callback_promise.h",
+    "cdm_config.h",
     "cdm_context.cc",
     "cdm_context.h",
     "cdm_factory.cc",
@@ -119,6 +120,8 @@
     "media_permission.h",
     "media_switches.cc",
     "media_switches.h",
+    "mime_util.cc",
+    "mime_util.h",
     "moving_average.cc",
     "moving_average.h",
     "multi_channel_resampler.cc",
@@ -380,6 +383,7 @@
     "fake_demuxer_stream_unittest.cc",
     "gmock_callback_support_unittest.cc",
     "key_systems_unittest.cc",
+    "mime_util_unittest.cc",
     "moving_average_unittest.cc",
     "multi_channel_resampler_unittest.cc",
     "null_video_sink_unittest.cc",
diff --git a/media/base/android/java/src/org/chromium/media/MediaCodecBridge.java b/media/base/android/java/src/org/chromium/media/MediaCodecBridge.java
index 018c475..04066e0e 100644
--- a/media/base/android/java/src/org/chromium/media/MediaCodecBridge.java
+++ b/media/base/android/java/src/org/chromium/media/MediaCodecBridge.java
@@ -15,11 +15,11 @@
 import android.media.MediaFormat;
 import android.os.Build;
 import android.os.Bundle;
-import android.util.Log;
 import android.view.Surface;
 
 import org.chromium.base.CalledByNative;
 import org.chromium.base.JNINamespace;
+import org.chromium.base.Log;
 
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
diff --git a/media/base/cdm_config.h b/media/base/cdm_config.h
index 4b57ebb..6f72348 100644
--- a/media/base/cdm_config.h
+++ b/media/base/cdm_config.h
@@ -12,7 +12,7 @@
 // The runtime configuration for new CDM instances as computed by
 // |requestMediaKeySystemAccess|. This is in some sense the Chromium-side
 // counterpart of Blink's WebMediaKeySystemConfiguration.
-struct MEDIA_EXPORT CdmConfig {
+struct CdmConfig {
   // Allow access to a distinctive identifier.
   bool allow_distinctive_identifier = false;
 
diff --git a/media/base/media_log.cc b/media/base/media_log.cc
index c89c415..462299b 100644
--- a/media/base/media_log.cc
+++ b/media/base/media_log.cc
@@ -139,7 +139,7 @@
         media::MediaLog::PipelineStatusToString(status);
   }
   std::string params_json;
-  base::JSONWriter::Write(&event.params, &params_json);
+  base::JSONWriter::Write(event.params, &params_json);
   return EventTypeToString(event.type) + " " + params_json;
 }
 
diff --git a/media/base/mime_util.cc b/media/base/mime_util.cc
new file mode 100644
index 0000000..bc12773
--- /dev/null
+++ b/media/base/mime_util.cc
@@ -0,0 +1,668 @@
+// Copyright 2012 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 <map>
+
+#include "base/containers/hash_tables.h"
+#include "base/lazy_instance.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+#include "build/build_config.h"
+#include "media/base/mime_util.h"
+
+#if defined(OS_ANDROID)
+#include "base/android/build_info.h"
+#endif
+
+namespace media {
+
+// Singleton utility class for mime types.
+class MimeUtil {
+ public:
+  enum Codec {
+    INVALID_CODEC,
+    PCM,
+    MP3,
+    MPEG2_AAC_LC,
+    MPEG2_AAC_MAIN,
+    MPEG2_AAC_SSR,
+    MPEG4_AAC_LC,
+    MPEG4_AAC_SBR_v1,
+    MPEG4_AAC_SBR_PS_v2,
+    VORBIS,
+    OPUS,
+    H264_BASELINE,
+    H264_MAIN,
+    H264_HIGH,
+    VP8,
+    VP9,
+    THEORA
+  };
+
+  bool IsSupportedMediaMimeType(const std::string& mime_type) const;
+
+  bool AreSupportedMediaCodecs(const std::vector<std::string>& codecs) const;
+
+  void ParseCodecString(const std::string& codecs,
+                        std::vector<std::string>* codecs_out,
+                        bool strip);
+
+  bool IsStrictMediaMimeType(const std::string& mime_type) const;
+  SupportsType IsSupportedStrictMediaMimeType(
+      const std::string& mime_type,
+      const std::vector<std::string>& codecs) const;
+
+  void RemoveProprietaryMediaTypesAndCodecsForTests();
+
+ private:
+  friend struct base::DefaultLazyInstanceTraits<MimeUtil>;
+
+  typedef base::hash_set<int> CodecSet;
+  typedef std::map<std::string, CodecSet> StrictMappings;
+  struct CodecEntry {
+    CodecEntry() : codec(INVALID_CODEC), is_ambiguous(true) {}
+    CodecEntry(Codec c, bool ambiguous) : codec(c), is_ambiguous(ambiguous) {}
+    Codec codec;
+    bool is_ambiguous;
+  };
+  typedef std::map<std::string, CodecEntry> StringToCodecMappings;
+
+  MimeUtil();
+
+  // For faster lookup, keep hash sets.
+  void InitializeMimeTypeMaps();
+
+  // Returns IsSupported if all codec IDs in |codecs| are unambiguous
+  // and are supported by the platform. MayBeSupported is returned if
+  // at least one codec ID in |codecs| is ambiguous but all the codecs
+  // are supported by the platform. IsNotSupported is returned if at
+  // least one codec ID  is not supported by the platform.
+  SupportsType AreSupportedCodecs(
+      const CodecSet& supported_codecs,
+      const std::vector<std::string>& codecs) const;
+
+  // Converts a codec ID into an Codec enum value and indicates
+  // whether the conversion was ambiguous.
+  // Returns true if this method was able to map |codec_id| to a specific
+  // Codec enum value. |codec| and |is_ambiguous| are only valid if true
+  // is returned. Otherwise their value is undefined after the call.
+  // |is_ambiguous| is true if |codec_id| did not have enough information to
+  // unambiguously determine the proper Codec enum value. If |is_ambiguous|
+  // is true |codec| contains the best guess for the intended Codec enum value.
+  bool StringToCodec(const std::string& codec_id,
+                     Codec* codec,
+                     bool* is_ambiguous) const;
+
+  // Returns true if |codec| is supported by the platform.
+  // Note: This method will return false if the platform supports proprietary
+  // codecs but |allow_proprietary_codecs_| is set to false.
+  bool IsCodecSupported(Codec codec) const;
+
+  // Returns true if |codec| refers to a proprietary codec.
+  bool IsCodecProprietary(Codec codec) const;
+
+  // Returns true and sets |*default_codec| if |mime_type| has a  default codec
+  // associated with it. Returns false otherwise and the value of
+  // |*default_codec| is undefined.
+  bool GetDefaultCodecLowerCase(const std::string& mime_type_lower_case,
+                                Codec* default_codec) const;
+
+  // Returns true if |mime_type_lower_case| has a default codec associated with
+  // it and IsCodecSupported() returns true for that particular codec.
+  bool IsDefaultCodecSupportedLowerCase(
+      const std::string& mime_type_lower_case) const;
+
+  using MimeTypes = base::hash_set<std::string>;
+  MimeTypes media_map_;
+
+  // A map of mime_types and hash map of the supported codecs for the mime_type.
+  StrictMappings strict_format_map_;
+
+  // Keeps track of whether proprietary codec support should be
+  // advertised to callers.
+  bool allow_proprietary_codecs_;
+
+  // Lookup table for string compare based string -> Codec mappings.
+  StringToCodecMappings string_to_codec_map_;
+
+  DISALLOW_COPY_AND_ASSIGN(MimeUtil);
+};  // class MimeUtil
+
+// This variable is Leaky because it is accessed from WorkerPool threads.
+static base::LazyInstance<MimeUtil>::Leaky g_media_mime_util =
+    LAZY_INSTANCE_INITIALIZER;
+
+
+// A list of media types: http://en.wikipedia.org/wiki/Internet_media_type
+// A comprehensive mime type list: http://plugindoc.mozdev.org/winmime.php
+// This set of codecs is supported by all variations of Chromium.
+static const char* const common_media_types[] = {
+  // Ogg.
+  "audio/ogg",
+  "application/ogg",
+#if !defined(OS_ANDROID)  // Android doesn't support Ogg Theora.
+  "video/ogg",
+#endif
+
+  // WebM.
+  "video/webm",
+  "audio/webm",
+
+  // Wav.
+  "audio/wav",
+  "audio/x-wav",
+
+#if defined(OS_ANDROID)
+  // HLS.
+  "application/vnd.apple.mpegurl",
+  "application/x-mpegurl",
+#endif
+};
+
+// List of proprietary types only supported by Google Chrome.
+static const char* const proprietary_media_types[] = {
+  // MPEG-4.
+  "video/mp4",
+  "video/x-m4v",
+  "audio/mp4",
+  "audio/x-m4a",
+
+  // MP3.
+  "audio/mp3",
+  "audio/x-mp3",
+  "audio/mpeg",
+  "audio/aac",
+
+#if defined(ENABLE_MPEG2TS_STREAM_PARSER)
+  // MPEG-2 TS.
+  "video/mp2t",
+#endif
+};
+
+#if defined(OS_ANDROID)
+static bool IsCodecSupportedOnAndroid(MimeUtil::Codec codec) {
+  switch (codec) {
+    case MimeUtil::INVALID_CODEC:
+      return false;
+
+    case MimeUtil::PCM:
+    case MimeUtil::MP3:
+    case MimeUtil::MPEG4_AAC_LC:
+    case MimeUtil::MPEG4_AAC_SBR_v1:
+    case MimeUtil::MPEG4_AAC_SBR_PS_v2:
+    case MimeUtil::H264_BASELINE:
+    case MimeUtil::H264_MAIN:
+    case MimeUtil::H264_HIGH:
+    case MimeUtil::VP8:
+    case MimeUtil::VORBIS:
+      return true;
+
+    case MimeUtil::MPEG2_AAC_LC:
+    case MimeUtil::MPEG2_AAC_MAIN:
+    case MimeUtil::MPEG2_AAC_SSR:
+      // MPEG-2 variants of AAC are not supported on Android.
+      return false;
+
+    case MimeUtil::VP9:
+      // VP9 is supported only in KitKat+ (API Level 19).
+      return base::android::BuildInfo::GetInstance()->sdk_int() >= 19;
+
+    case MimeUtil::OPUS:
+      // Opus is supported only in Lollipop+ (API Level 21).
+      return base::android::BuildInfo::GetInstance()->sdk_int() >= 21;
+
+    case MimeUtil::THEORA:
+      return false;
+  }
+
+  return false;
+}
+#endif
+
+struct MediaFormatStrict {
+  const char* const mime_type;
+  const char* const codecs_list;
+};
+
+// Following is the list of RFC 6381 compliant codecs:
+//   mp4a.66     - MPEG-2 AAC MAIN
+//   mp4a.67     - MPEG-2 AAC LC
+//   mp4a.68     - MPEG-2 AAC SSR
+//   mp4a.69     - MPEG-2 extension to MPEG-1
+//   mp4a.6B     - MPEG-1 audio
+//   mp4a.40.2   - MPEG-4 AAC LC
+//   mp4a.40.02  - MPEG-4 AAC LC (leading 0 in aud-oti for compatibility)
+//   mp4a.40.5   - MPEG-4 HE-AAC v1 (AAC LC + SBR)
+//   mp4a.40.05  - MPEG-4 HE-AAC v1 (AAC LC + SBR) (leading 0 in aud-oti for
+//                 compatibility)
+//   mp4a.40.29  - MPEG-4 HE-AAC v2 (AAC LC + SBR + PS)
+//
+//   avc1.42E0xx - H.264 Baseline
+//   avc1.4D40xx - H.264 Main
+//   avc1.6400xx - H.264 High
+static const char kMP4AudioCodecsExpression[] =
+    "mp4a.66,mp4a.67,mp4a.68,mp4a.69,mp4a.6B,mp4a.40.2,mp4a.40.02,mp4a.40.5,"
+    "mp4a.40.05,mp4a.40.29";
+static const char kMP4VideoCodecsExpression[] =
+    // This is not a complete list of supported avc1 codecs. It is simply used
+    // to register support for the corresponding Codec enum. Instead of using
+    // strings in these three arrays, we should use the Codec enum values.
+    // This will avoid confusion and unnecessary parsing at runtime.
+    // kUnambiguousCodecStringMap/kAmbiguousCodecStringMap should be the only
+    // mapping from strings to codecs. See crbug.com/461009.
+    "avc1.42E00A,avc1.4D400A,avc1.64000A,"
+    "mp4a.66,mp4a.67,mp4a.68,mp4a.69,mp4a.6B,mp4a.40.2,mp4a.40.02,mp4a.40.5,"
+    "mp4a.40.05,mp4a.40.29";
+
+// These containers are also included in
+// common_media_types/proprietary_media_types. See crbug.com/461012.
+static const MediaFormatStrict format_codec_mappings[] = {
+    {"video/webm", "opus,vorbis,vp8,vp8.0,vp9,vp9.0"},
+    {"audio/webm", "opus,vorbis"},
+    {"audio/wav", "1"},
+    {"audio/x-wav", "1"},
+// Android does not support Opus in Ogg container.
+#if defined(OS_ANDROID)
+    {"video/ogg", "theora,vorbis"},
+    {"audio/ogg", "vorbis"},
+    {"application/ogg", "theora,vorbis"},
+#else
+    {"video/ogg", "opus,theora,vorbis"},
+    {"audio/ogg", "opus,vorbis"},
+    {"application/ogg", "opus,theora,vorbis"},
+#endif
+    {"audio/mpeg", "mp3"},
+    {"audio/mp3", ""},
+    {"audio/x-mp3", ""},
+    {"audio/mp4", kMP4AudioCodecsExpression},
+    {"audio/x-m4a", kMP4AudioCodecsExpression},
+    {"video/mp4", kMP4VideoCodecsExpression},
+    {"video/x-m4v", kMP4VideoCodecsExpression},
+    {"application/x-mpegurl", kMP4VideoCodecsExpression},
+    {"application/vnd.apple.mpegurl", kMP4VideoCodecsExpression}};
+
+struct CodecIDMappings {
+  const char* const codec_id;
+  MimeUtil::Codec codec;
+};
+
+// List of codec IDs that provide enough information to determine the
+// codec and profile being requested.
+//
+// The "mp4a" strings come from RFC 6381.
+static const CodecIDMappings kUnambiguousCodecStringMap[] = {
+    {"1", MimeUtil::PCM},  // We only allow this for WAV so it isn't ambiguous.
+    // avc1/avc3.XXXXXX may be unambiguous; handled by ParseH264CodecID().
+    {"mp3", MimeUtil::MP3},
+    {"mp4a.66", MimeUtil::MPEG2_AAC_MAIN},
+    {"mp4a.67", MimeUtil::MPEG2_AAC_LC},
+    {"mp4a.68", MimeUtil::MPEG2_AAC_SSR},
+    {"mp4a.69", MimeUtil::MP3},
+    {"mp4a.6B", MimeUtil::MP3},
+    {"mp4a.40.2", MimeUtil::MPEG4_AAC_LC},
+    {"mp4a.40.02", MimeUtil::MPEG4_AAC_LC},
+    {"mp4a.40.5", MimeUtil::MPEG4_AAC_SBR_v1},
+    {"mp4a.40.05", MimeUtil::MPEG4_AAC_SBR_v1},
+    {"mp4a.40.29", MimeUtil::MPEG4_AAC_SBR_PS_v2},
+    {"vorbis", MimeUtil::VORBIS},
+    {"opus", MimeUtil::OPUS},
+    {"vp8", MimeUtil::VP8},
+    {"vp8.0", MimeUtil::VP8},
+    {"vp9", MimeUtil::VP9},
+    {"vp9.0", MimeUtil::VP9},
+    {"theora", MimeUtil::THEORA}};
+
+// List of codec IDs that are ambiguous and don't provide
+// enough information to determine the codec and profile.
+// The codec in these entries indicate the codec and profile
+// we assume the user is trying to indicate.
+static const CodecIDMappings kAmbiguousCodecStringMap[] = {
+    {"mp4a.40", MimeUtil::MPEG4_AAC_LC},
+    {"avc1", MimeUtil::H264_BASELINE},
+    {"avc3", MimeUtil::H264_BASELINE},
+    // avc1/avc3.XXXXXX may be ambiguous; handled by ParseH264CodecID().
+};
+
+MimeUtil::MimeUtil() : allow_proprietary_codecs_(false) {
+  InitializeMimeTypeMaps();
+}
+
+SupportsType MimeUtil::AreSupportedCodecs(
+    const CodecSet& supported_codecs,
+    const std::vector<std::string>& codecs) const {
+  DCHECK(!supported_codecs.empty());
+  DCHECK(!codecs.empty());
+
+  SupportsType result = IsSupported;
+  for (size_t i = 0; i < codecs.size(); ++i) {
+    bool is_ambiguous = true;
+    Codec codec = INVALID_CODEC;
+    if (!StringToCodec(codecs[i], &codec, &is_ambiguous))
+      return IsNotSupported;
+
+    if (!IsCodecSupported(codec) ||
+        supported_codecs.find(codec) == supported_codecs.end()) {
+      return IsNotSupported;
+    }
+
+    if (is_ambiguous)
+      result = MayBeSupported;
+  }
+
+  return result;
+}
+
+void MimeUtil::InitializeMimeTypeMaps() {
+  // Initialize the supported media types.
+  for (size_t i = 0; i < arraysize(common_media_types); ++i)
+    media_map_.insert(common_media_types[i]);
+#if defined(USE_PROPRIETARY_CODECS)
+  allow_proprietary_codecs_ = true;
+
+  for (size_t i = 0; i < arraysize(proprietary_media_types); ++i)
+    media_map_.insert(proprietary_media_types[i]);
+#endif
+
+  for (size_t i = 0; i < arraysize(kUnambiguousCodecStringMap); ++i) {
+    string_to_codec_map_[kUnambiguousCodecStringMap[i].codec_id] =
+        CodecEntry(kUnambiguousCodecStringMap[i].codec, false);
+  }
+
+  for (size_t i = 0; i < arraysize(kAmbiguousCodecStringMap); ++i) {
+    string_to_codec_map_[kAmbiguousCodecStringMap[i].codec_id] =
+        CodecEntry(kAmbiguousCodecStringMap[i].codec, true);
+  }
+
+  // Initialize the strict supported media types.
+  for (size_t i = 0; i < arraysize(format_codec_mappings); ++i) {
+    std::vector<std::string> mime_type_codecs;
+    ParseCodecString(format_codec_mappings[i].codecs_list,
+                     &mime_type_codecs,
+                     false);
+
+    CodecSet codecs;
+    for (size_t j = 0; j < mime_type_codecs.size(); ++j) {
+      Codec codec = INVALID_CODEC;
+      bool is_ambiguous = true;
+      CHECK(StringToCodec(mime_type_codecs[j], &codec, &is_ambiguous));
+      DCHECK(!is_ambiguous);
+      codecs.insert(codec);
+    }
+
+    strict_format_map_[format_codec_mappings[i].mime_type] = codecs;
+  }
+}
+
+bool MimeUtil::IsSupportedMediaMimeType(const std::string& mime_type) const {
+  return media_map_.find(base::StringToLowerASCII(mime_type)) !=
+         media_map_.end();
+}
+
+
+bool MimeUtil::AreSupportedMediaCodecs(
+    const std::vector<std::string>& codecs) const {
+  for (size_t i = 0; i < codecs.size(); ++i) {
+    Codec codec = INVALID_CODEC;
+    bool is_ambiguous = true;
+    if (!StringToCodec(codecs[i], &codec, &is_ambiguous) ||
+        !IsCodecSupported(codec)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+void MimeUtil::ParseCodecString(const std::string& codecs,
+                                std::vector<std::string>* codecs_out,
+                                bool strip) {
+  std::string no_quote_codecs;
+  base::TrimString(codecs, "\"", &no_quote_codecs);
+  base::SplitString(no_quote_codecs, ',', codecs_out);
+
+  if (!strip)
+    return;
+
+  // Strip everything past the first '.'
+  for (std::vector<std::string>::iterator it = codecs_out->begin();
+       it != codecs_out->end();
+       ++it) {
+    size_t found = it->find_first_of('.');
+    if (found != std::string::npos)
+      it->resize(found);
+  }
+}
+
+bool MimeUtil::IsStrictMediaMimeType(const std::string& mime_type) const {
+  return strict_format_map_.find(base::StringToLowerASCII(mime_type)) !=
+         strict_format_map_.end();
+}
+
+SupportsType MimeUtil::IsSupportedStrictMediaMimeType(
+    const std::string& mime_type,
+    const std::vector<std::string>& codecs) const {
+  const std::string mime_type_lower_case = base::StringToLowerASCII(mime_type);
+  StrictMappings::const_iterator it_strict_map =
+      strict_format_map_.find(mime_type_lower_case);
+  if (it_strict_map == strict_format_map_.end())
+    return codecs.empty() ? MayBeSupported : IsNotSupported;
+
+  if (it_strict_map->second.empty()) {
+    // We get here if the mimetype does not expect a codecs parameter.
+    return (codecs.empty() &&
+            IsDefaultCodecSupportedLowerCase(mime_type_lower_case))
+               ? IsSupported
+               : IsNotSupported;
+  }
+
+  if (codecs.empty()) {
+    // We get here if the mimetype expects to get a codecs parameter,
+    // but didn't get one. If |mime_type_lower_case| does not have a default
+    // codec the best we can do is say "maybe" because we don't have enough
+    // information.
+    Codec default_codec = INVALID_CODEC;
+    if (!GetDefaultCodecLowerCase(mime_type_lower_case, &default_codec))
+      return MayBeSupported;
+
+    return IsCodecSupported(default_codec) ? IsSupported : IsNotSupported;
+  }
+
+  return AreSupportedCodecs(it_strict_map->second, codecs);
+}
+
+void MimeUtil::RemoveProprietaryMediaTypesAndCodecsForTests() {
+  for (size_t i = 0; i < arraysize(proprietary_media_types); ++i)
+    media_map_.erase(proprietary_media_types[i]);
+  allow_proprietary_codecs_ = false;
+}
+
+// Returns true iff |profile_str| conforms to hex string "42y0", where y is one
+// of [8..F]. Requiring constraint_set0_flag be set and profile_idc be 0x42 is
+// taken from ISO-14496-10 7.3.2.1, 7.4.2.1, and Annex A.2.1.
+//
+// |profile_str| is the first four characters of the H.264 suffix string
+// (ignoring the last 2 characters of the full 6 character suffix that are
+// level_idc). From ISO-14496-10 7.3.2.1, it consists of:
+// 8 bits: profile_idc: required to be 0x42 here.
+// 1 bit: constraint_set0_flag : required to be true here.
+// 1 bit: constraint_set1_flag : ignored here.
+// 1 bit: constraint_set2_flag : ignored here.
+// 1 bit: constraint_set3_flag : ignored here.
+// 4 bits: reserved : required to be 0 here.
+//
+// The spec indicates other ways, not implemented here, that a |profile_str|
+// can indicate a baseline conforming decoder is sufficient for decode in Annex
+// A.2.1: "[profile_idc not necessarily 0x42] with constraint_set0_flag set and
+// in which level_idc and constraint_set3_flag represent a level less than or
+// equal to the specified level."
+static bool IsValidH264BaselineProfile(const std::string& profile_str) {
+  uint32 constraint_set_bits;
+  if (profile_str.size() != 4 ||
+      profile_str[0] != '4' ||
+      profile_str[1] != '2' ||
+      profile_str[3] != '0' ||
+      !base::HexStringToUInt(base::StringPiece(profile_str.c_str() + 2, 1),
+                             &constraint_set_bits)) {
+    return false;
+  }
+
+  return constraint_set_bits >= 8;
+}
+
+static bool IsValidH264Level(const std::string& level_str) {
+  uint32 level;
+  if (level_str.size() != 2 || !base::HexStringToUInt(level_str, &level))
+    return false;
+
+  // Valid levels taken from Table A-1 in ISO-14496-10.
+  // Essentially |level_str| is toHex(10 * level).
+  return ((level >= 10 && level <= 13) ||
+          (level >= 20 && level <= 22) ||
+          (level >= 30 && level <= 32) ||
+          (level >= 40 && level <= 42) ||
+          (level >= 50 && level <= 51));
+}
+
+// Handle parsing H.264 codec IDs as outlined in RFC 6381 and ISO-14496-10.
+//   avc1.42y0xx, y >= 8 - H.264 Baseline
+//   avc1.4D40xx         - H.264 Main
+//   avc1.6400xx         - H.264 High
+//
+//   avc1.xxxxxx & avc3.xxxxxx are considered ambiguous forms that are trying to
+//   signal H.264 Baseline. For example, the idc_level, profile_idc and
+//   constraint_set3_flag pieces may explicitly require decoder to conform to
+//   baseline profile at the specified level (see Annex A and constraint_set0 in
+//   ISO-14496-10).
+static bool ParseH264CodecID(const std::string& codec_id,
+                             MimeUtil::Codec* codec,
+                             bool* is_ambiguous) {
+  // Make sure we have avc1.xxxxxx or avc3.xxxxxx
+  if (codec_id.size() != 11 ||
+      (!StartsWithASCII(codec_id, "avc1.", true) &&
+       !StartsWithASCII(codec_id, "avc3.", true))) {
+    return false;
+  }
+
+  std::string profile = StringToUpperASCII(codec_id.substr(5, 4));
+  if (IsValidH264BaselineProfile(profile)) {
+    *codec = MimeUtil::H264_BASELINE;
+  } else if (profile == "4D40") {
+    *codec = MimeUtil::H264_MAIN;
+  } else if (profile == "6400") {
+    *codec = MimeUtil::H264_HIGH;
+  } else {
+    *codec = MimeUtil::H264_BASELINE;
+    *is_ambiguous = true;
+    return true;
+  }
+
+  *is_ambiguous = !IsValidH264Level(StringToUpperASCII(codec_id.substr(9)));
+  return true;
+}
+
+bool MimeUtil::StringToCodec(const std::string& codec_id,
+                             Codec* codec,
+                             bool* is_ambiguous) const {
+  StringToCodecMappings::const_iterator itr =
+      string_to_codec_map_.find(codec_id);
+  if (itr != string_to_codec_map_.end()) {
+    *codec = itr->second.codec;
+    *is_ambiguous = itr->second.is_ambiguous;
+    return true;
+  }
+
+  // If |codec_id| is not in |string_to_codec_map_|, then we assume that it is
+  // an H.264 codec ID because currently those are the only ones that can't be
+  // stored in the |string_to_codec_map_| and require parsing.
+  return ParseH264CodecID(codec_id, codec, is_ambiguous);
+}
+
+bool MimeUtil::IsCodecSupported(Codec codec) const {
+  DCHECK_NE(codec, INVALID_CODEC);
+
+#if defined(OS_ANDROID)
+  if (!IsCodecSupportedOnAndroid(codec))
+    return false;
+#endif
+
+  return allow_proprietary_codecs_ || !IsCodecProprietary(codec);
+}
+
+bool MimeUtil::IsCodecProprietary(Codec codec) const {
+  switch (codec) {
+    case INVALID_CODEC:
+    case MP3:
+    case MPEG2_AAC_LC:
+    case MPEG2_AAC_MAIN:
+    case MPEG2_AAC_SSR:
+    case MPEG4_AAC_LC:
+    case MPEG4_AAC_SBR_v1:
+    case MPEG4_AAC_SBR_PS_v2:
+    case H264_BASELINE:
+    case H264_MAIN:
+    case H264_HIGH:
+      return true;
+
+    case PCM:
+    case VORBIS:
+    case OPUS:
+    case VP8:
+    case VP9:
+    case THEORA:
+      return false;
+  }
+
+  return true;
+}
+
+bool MimeUtil::GetDefaultCodecLowerCase(const std::string& mime_type_lower_case,
+                                        Codec* default_codec) const {
+  if (mime_type_lower_case == "audio/mpeg" ||
+      mime_type_lower_case == "audio/mp3" ||
+      mime_type_lower_case == "audio/x-mp3") {
+    *default_codec = MimeUtil::MP3;
+    return true;
+  }
+
+  return false;
+}
+
+bool MimeUtil::IsDefaultCodecSupportedLowerCase(
+    const std::string& mime_type_lower_case) const {
+  Codec default_codec = Codec::INVALID_CODEC;
+  if (!GetDefaultCodecLowerCase(mime_type_lower_case, &default_codec))
+    return false;
+  return IsCodecSupported(default_codec);
+}
+
+bool IsSupportedMediaMimeType(const std::string& mime_type) {
+  return g_media_mime_util.Get().IsSupportedMediaMimeType(mime_type);
+}
+
+bool AreSupportedMediaCodecs(const std::vector<std::string>& codecs) {
+  return g_media_mime_util.Get().AreSupportedMediaCodecs(codecs);
+}
+
+bool IsStrictMediaMimeType(const std::string& mime_type) {
+  return g_media_mime_util.Get().IsStrictMediaMimeType(mime_type);
+}
+
+SupportsType IsSupportedStrictMediaMimeType(
+    const std::string& mime_type,
+    const std::vector<std::string>& codecs) {
+  return g_media_mime_util.Get().IsSupportedStrictMediaMimeType(
+      mime_type, codecs);
+}
+
+void ParseCodecString(const std::string& codecs,
+                      std::vector<std::string>* codecs_out,
+                      const bool strip) {
+  g_media_mime_util.Get().ParseCodecString(codecs, codecs_out, strip);
+}
+
+void RemoveProprietaryMediaTypesAndCodecsForTests() {
+  g_media_mime_util.Get().RemoveProprietaryMediaTypesAndCodecsForTests();
+}
+
+}  // namespace media
diff --git a/media/base/mime_util.h b/media/base/mime_util.h
new file mode 100644
index 0000000..a5c80d5
--- /dev/null
+++ b/media/base/mime_util.h
@@ -0,0 +1,76 @@
+// Copyright 2012 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 MEDIA_BASE_MIME_UTIL_H__
+#define MEDIA_BASE_MIME_UTIL_H__
+
+#include <string>
+#include <vector>
+
+#include "media/base/media_export.h"
+
+namespace media {
+
+// Check to see if a particular MIME type is in the list of
+// supported/recognized MIME types.
+MEDIA_EXPORT bool IsSupportedMediaMimeType(const std::string& mime_type);
+
+// Returns true if and only if all codecs are supported, false otherwise.
+MEDIA_EXPORT bool AreSupportedMediaCodecs(
+    const std::vector<std::string>& codecs);
+
+// Parses a codec string, populating |codecs_out| with the prefix of each codec
+// in the string |codecs_in|. For example, passed "aaa.b.c,dd.eee", if
+// |strip| == true |codecs_out| will contain {"aaa", "dd"}, if |strip| == false
+// |codecs_out| will contain {"aaa.b.c", "dd.eee"}.
+// See http://www.ietf.org/rfc/rfc4281.txt.
+MEDIA_EXPORT void ParseCodecString(const std::string& codecs,
+                                   std::vector<std::string>* codecs_out,
+                                   bool strip);
+
+// Check to see if a particular MIME type is in our list which only supports a
+// certain subset of codecs.
+MEDIA_EXPORT bool IsStrictMediaMimeType(const std::string& mime_type);
+
+// Indicates that the MIME type and (possible codec string) are supported by the
+// underlying platform.
+enum SupportsType {
+  // The underlying platform is known not to support the given MIME type and
+  // codec combination.
+  IsNotSupported,
+
+  // The underlying platform is known to support the given MIME type and codec
+  // combination.
+  IsSupported,
+
+  // The underlying platform is unsure whether the given MIME type and codec
+  // combination can be rendered or not before actually trying to play it.
+  MayBeSupported
+};
+
+// Checks the |mime_type| and |codecs| against the MIME types known to support
+// only a particular subset of codecs.
+// * Returns IsSupported if the |mime_type| is supported and all the codecs
+//   within the |codecs| are supported for the |mime_type|.
+// * Returns MayBeSupported if the |mime_type| is supported and is known to
+//   support only a subset of codecs, but |codecs| was empty. Also returned if
+//   all the codecs in |codecs| are supported, but additional codec parameters
+//   were supplied (such as profile) for which the support cannot be decided.
+// * Returns IsNotSupported if either the |mime_type| is not supported or the
+//   |mime_type| is supported but at least one of the codecs within |codecs| is
+//   not supported for the |mime_type|.
+MEDIA_EXPORT SupportsType IsSupportedStrictMediaMimeType(
+    const std::string& mime_type,
+    const std::vector<std::string>& codecs);
+
+// Test only method that removes proprietary media types and codecs from the
+// list of supported MIME types and codecs. These types and codecs must be
+// removed to ensure consistent layout test results across all Chromium
+// variations.
+MEDIA_EXPORT void RemoveProprietaryMediaTypesAndCodecsForTests();
+
+}  // namespace media
+
+#endif  // MEDIA_BASE_MIME_UTIL_H__
+
diff --git a/media/base/mime_util_unittest.cc b/media/base/mime_util_unittest.cc
new file mode 100644
index 0000000..d1d6722
--- /dev/null
+++ b/media/base/mime_util_unittest.cc
@@ -0,0 +1,142 @@
+// 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 "base/basictypes.h"
+#include "base/strings/string_split.h"
+#include "build/build_config.h"
+#include "media/base/mime_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace media {
+
+TEST(MimeUtilTest, StrictMediaMimeType) {
+  EXPECT_TRUE(IsStrictMediaMimeType("video/webm"));
+  EXPECT_TRUE(IsStrictMediaMimeType("Video/WEBM"));
+  EXPECT_TRUE(IsStrictMediaMimeType("audio/webm"));
+
+  EXPECT_TRUE(IsStrictMediaMimeType("audio/wav"));
+  EXPECT_TRUE(IsStrictMediaMimeType("audio/x-wav"));
+
+  EXPECT_TRUE(IsStrictMediaMimeType("video/ogg"));
+  EXPECT_TRUE(IsStrictMediaMimeType("audio/ogg"));
+  EXPECT_TRUE(IsStrictMediaMimeType("application/ogg"));
+
+  EXPECT_TRUE(IsStrictMediaMimeType("audio/mpeg"));
+  EXPECT_TRUE(IsStrictMediaMimeType("audio/mp3"));
+  EXPECT_TRUE(IsStrictMediaMimeType("audio/x-mp3"));
+
+  EXPECT_TRUE(IsStrictMediaMimeType("video/mp4"));
+  EXPECT_TRUE(IsStrictMediaMimeType("video/x-m4v"));
+  EXPECT_TRUE(IsStrictMediaMimeType("audio/mp4"));
+  EXPECT_TRUE(IsStrictMediaMimeType("audio/x-m4a"));
+
+  EXPECT_TRUE(IsStrictMediaMimeType("application/x-mpegurl"));
+  EXPECT_TRUE(IsStrictMediaMimeType("application/vnd.apple.mpegurl"));
+
+  EXPECT_FALSE(IsStrictMediaMimeType("video/unknown"));
+  EXPECT_FALSE(IsStrictMediaMimeType("Video/UNKNOWN"));
+  EXPECT_FALSE(IsStrictMediaMimeType("audio/unknown"));
+  EXPECT_FALSE(IsStrictMediaMimeType("application/unknown"));
+  EXPECT_FALSE(IsStrictMediaMimeType("unknown/unknown"));
+}
+
+TEST(MimeUtilTest, CommonMediaMimeType) {
+  EXPECT_TRUE(IsSupportedMediaMimeType("audio/webm"));
+  EXPECT_TRUE(IsSupportedMediaMimeType("video/webm"));
+
+  EXPECT_TRUE(IsSupportedMediaMimeType("audio/wav"));
+  EXPECT_TRUE(IsSupportedMediaMimeType("audio/x-wav"));
+
+  EXPECT_TRUE(IsSupportedMediaMimeType("audio/ogg"));
+  EXPECT_TRUE(IsSupportedMediaMimeType("application/ogg"));
+#if defined(OS_ANDROID)
+  EXPECT_FALSE(IsSupportedMediaMimeType("video/ogg"));
+#else
+  EXPECT_TRUE(IsSupportedMediaMimeType("video/ogg"));
+#endif  // OS_ANDROID
+
+#if defined(OS_ANDROID)
+  // HLS is supported on Android API level 14 and higher and Chrome supports
+  // API levels 15 and higher, so these are expected to be supported.
+  bool kHlsSupported = true;
+#else
+  bool kHlsSupported = false;
+#endif
+
+  EXPECT_EQ(kHlsSupported, IsSupportedMediaMimeType("application/x-mpegurl"));
+  EXPECT_EQ(kHlsSupported, IsSupportedMediaMimeType("Application/X-MPEGURL"));
+  EXPECT_EQ(kHlsSupported, IsSupportedMediaMimeType(
+      "application/vnd.apple.mpegurl"));
+
+#if defined(USE_PROPRIETARY_CODECS)
+  EXPECT_TRUE(IsSupportedMediaMimeType("audio/mp4"));
+  EXPECT_TRUE(IsSupportedMediaMimeType("audio/x-m4a"));
+  EXPECT_TRUE(IsSupportedMediaMimeType("video/mp4"));
+  EXPECT_TRUE(IsSupportedMediaMimeType("video/x-m4v"));
+
+  EXPECT_TRUE(IsSupportedMediaMimeType("audio/mp3"));
+  EXPECT_TRUE(IsSupportedMediaMimeType("audio/x-mp3"));
+  EXPECT_TRUE(IsSupportedMediaMimeType("audio/mpeg"));
+  EXPECT_TRUE(IsSupportedMediaMimeType("audio/aac"));
+
+#if defined(ENABLE_MPEG2TS_STREAM_PARSER)
+  EXPECT_TRUE(IsSupportedMediaMimeType("video/mp2t"));
+#else
+  EXPECT_FALSE(IsSupportedMediaMimeType("video/mp2t"));
+#endif
+#else
+  EXPECT_FALSE(IsSupportedMediaMimeType("audio/mp4"));
+  EXPECT_FALSE(IsSupportedMediaMimeType("audio/x-m4a"));
+  EXPECT_FALSE(IsSupportedMediaMimeType("video/mp4"));
+  EXPECT_FALSE(IsSupportedMediaMimeType("video/x-m4v"));
+
+  EXPECT_FALSE(IsSupportedMediaMimeType("audio/mp3"));
+  EXPECT_FALSE(IsSupportedMediaMimeType("audio/x-mp3"));
+  EXPECT_FALSE(IsSupportedMediaMimeType("audio/mpeg"));
+  EXPECT_FALSE(IsSupportedMediaMimeType("audio/aac"));
+#endif  // USE_PROPRIETARY_CODECS
+  EXPECT_FALSE(IsSupportedMediaMimeType("video/mp3"));
+
+  EXPECT_FALSE(IsSupportedMediaMimeType("video/unknown"));
+  EXPECT_FALSE(IsSupportedMediaMimeType("audio/unknown"));
+  EXPECT_FALSE(IsSupportedMediaMimeType("unknown/unknown"));
+}
+
+// Note: codecs should only be a list of 2 or fewer; hence the restriction of
+// results' length to 2.
+TEST(MimeUtilTest, ParseCodecString) {
+  const struct {
+    const char* const original;
+    size_t expected_size;
+    const char* const results[2];
+  } tests[] = {
+    { "\"bogus\"",                  1, { "bogus" }            },
+    { "0",                          1, { "0" }                },
+    { "avc1.42E01E, mp4a.40.2",     2, { "avc1",   "mp4a" }   },
+    { "\"mp4v.20.240, mp4a.40.2\"", 2, { "mp4v",   "mp4a" }   },
+    { "mp4v.20.8, samr",            2, { "mp4v",   "samr" }   },
+    { "\"theora, vorbis\"",         2, { "theora", "vorbis" } },
+    { "",                           0, { }                    },
+    { "\"\"",                       0, { }                    },
+    { "\"   \"",                    0, { }                    },
+    { ",",                          2, { "", "" }             },
+  };
+
+  for (size_t i = 0; i < arraysize(tests); ++i) {
+    std::vector<std::string> codecs_out;
+    ParseCodecString(tests[i].original, &codecs_out, true);
+    ASSERT_EQ(tests[i].expected_size, codecs_out.size());
+    for (size_t j = 0; j < tests[i].expected_size; ++j)
+      EXPECT_EQ(tests[i].results[j], codecs_out[j]);
+  }
+
+  // Test without stripping the codec type.
+  std::vector<std::string> codecs_out;
+  ParseCodecString("avc1.42E01E, mp4a.40.2", &codecs_out, false);
+  ASSERT_EQ(2u, codecs_out.size());
+  EXPECT_EQ("avc1.42E01E", codecs_out[0]);
+  EXPECT_EQ("mp4a.40.2", codecs_out[1]);
+}
+
+}  // namespace media
diff --git a/media/base/video_util.cc b/media/base/video_util.cc
index d794674..e04a5a3c 100644
--- a/media/base/video_util.cc
+++ b/media/base/video_util.cc
@@ -270,6 +270,23 @@
   }
 }
 
+// Common logic for the letterboxing and scale-within/scale-encompassing
+// functions.  Scales |size| to either fit within or encompass |target|,
+// depending on whether |fit_within_target| is true.
+static gfx::Size ScaleSizeToTarget(const gfx::Size& size,
+                                   const gfx::Size& target,
+                                   bool fit_within_target) {
+  if (size.IsEmpty())
+    return gfx::Size();  // Corner case: Aspect ratio is undefined.
+
+  const int64 x = static_cast<int64>(size.width()) * target.height();
+  const int64 y = static_cast<int64>(size.height()) * target.width();
+  const bool use_target_width = fit_within_target ? (y < x) : (x < y);
+  return use_target_width ?
+      gfx::Size(target.width(), static_cast<int>(y / size.width())) :
+      gfx::Size(static_cast<int>(x / size.height()), target.height());
+}
+
 gfx::Rect ComputeLetterboxRegion(const gfx::Rect& bounds,
                                  const gfx::Size& content) {
   // If |content| has an undefined aspect ratio, let's not try to divide by
@@ -277,19 +294,33 @@
   if (content.IsEmpty())
     return gfx::Rect();
 
-  int64 x = static_cast<int64>(content.width()) * bounds.height();
-  int64 y = static_cast<int64>(content.height()) * bounds.width();
-
-  gfx::Size letterbox(bounds.width(), bounds.height());
-  if (y < x)
-    letterbox.set_height(static_cast<int>(y / content.width()));
-  else
-    letterbox.set_width(static_cast<int>(x / content.height()));
   gfx::Rect result = bounds;
-  result.ClampToCenteredSize(letterbox);
+  result.ClampToCenteredSize(ScaleSizeToTarget(content, bounds.size(), true));
   return result;
 }
 
+gfx::Size ScaleSizeToFitWithinTarget(const gfx::Size& size,
+                                     const gfx::Size& target) {
+  return ScaleSizeToTarget(size, target, true);
+}
+
+gfx::Size ScaleSizeToEncompassTarget(const gfx::Size& size,
+                                     const gfx::Size& target) {
+  return ScaleSizeToTarget(size, target, false);
+}
+
+gfx::Size PadToMatchAspectRatio(const gfx::Size& size,
+                                const gfx::Size& target) {
+  if (target.IsEmpty())
+    return gfx::Size();  // Aspect ratio is undefined.
+
+  const int64 x = static_cast<int64>(size.width()) * target.height();
+  const int64 y = static_cast<int64>(size.height()) * target.width();
+  if (x < y)
+    return gfx::Size(static_cast<int>(y / target.height()), size.height());
+  return gfx::Size(size.width(), static_cast<int>(x / target.width()));
+}
+
 void CopyRGBToVideoFrame(const uint8* source,
                          int stride,
                          const gfx::Rect& region_in_frame,
diff --git a/media/base/video_util.h b/media/base/video_util.h
index 7798ebe0..abbcad4 100644
--- a/media/base/video_util.h
+++ b/media/base/video_util.h
@@ -84,6 +84,29 @@
 MEDIA_EXPORT gfx::Rect ComputeLetterboxRegion(const gfx::Rect& bounds,
                                               const gfx::Size& content);
 
+// Return a scaled |size| whose area is less than or equal to |target|, where
+// one of its dimensions is equal to |target|'s.  The aspect ratio of |size| is
+// preserved as closely as possible.  If |size| is empty, the result will be
+// empty.
+MEDIA_EXPORT gfx::Size ScaleSizeToFitWithinTarget(const gfx::Size& size,
+                                                  const gfx::Size& target);
+
+// Return a scaled |size| whose area is greater than or equal to |target|, where
+// one of its dimensions is equal to |target|'s.  The aspect ratio of |size| is
+// preserved as closely as possible.  If |size| is empty, the result will be
+// empty.
+MEDIA_EXPORT gfx::Size ScaleSizeToEncompassTarget(const gfx::Size& size,
+                                                  const gfx::Size& target);
+
+// Returns |size| with only one of its dimensions increased such that the result
+// matches the aspect ratio of |target|.  This is different from
+// ScaleSizeToEncompassTarget() in two ways: 1) The goal is to match the aspect
+// ratio of |target| rather than that of |size|.  2) Only one of the dimensions
+// of |size| may change, and it may only be increased (padded).  If either
+// |size| or |target| is empty, the result will be empty.
+MEDIA_EXPORT gfx::Size PadToMatchAspectRatio(const gfx::Size& size,
+                                             const gfx::Size& target);
+
 // Copy an RGB bitmap into the specified |region_in_frame| of a YUV video frame.
 // Fills the regions outside |region_in_frame| with black.
 MEDIA_EXPORT void CopyRGBToVideoFrame(const uint8* source,
diff --git a/media/base/video_util_unittest.cc b/media/base/video_util_unittest.cc
index 9ac13c1f..79c5315 100644
--- a/media/base/video_util_unittest.cc
+++ b/media/base/video_util_unittest.cc
@@ -328,6 +328,8 @@
 INSTANTIATE_TEST_CASE_P(, VideoUtilRotationTest,
                         testing::ValuesIn(kVideoRotationTestData));
 
+// Tests the ComputeLetterboxRegion function.  Also, because of shared code
+// internally, this also tests ScaleSizeToFitWithinTarget().
 TEST_F(VideoUtilTest, ComputeLetterboxRegion) {
   EXPECT_EQ(gfx::Rect(167, 0, 666, 500),
             ComputeLetterboxRegion(gfx::Rect(0, 0, 1000, 500),
@@ -348,6 +350,48 @@
                                      gfx::Size(0, 0)).IsEmpty());
 }
 
+TEST_F(VideoUtilTest, ScaleSizeToEncompassTarget) {
+  EXPECT_EQ(gfx::Size(1000, 750),
+            ScaleSizeToEncompassTarget(gfx::Size(640, 480),
+                                       gfx::Size(1000, 500)));
+  EXPECT_EQ(gfx::Size(1333, 1000),
+            ScaleSizeToEncompassTarget(gfx::Size(640, 480),
+                                       gfx::Size(500, 1000)));
+  EXPECT_EQ(gfx::Size(1000, 562),
+            ScaleSizeToEncompassTarget(gfx::Size(1920, 1080),
+                                       gfx::Size(1000, 500)));
+  EXPECT_EQ(gfx::Size(133, 100),
+            ScaleSizeToEncompassTarget(gfx::Size(400, 300),
+                                       gfx::Size(100, 100)));
+  EXPECT_EQ(gfx::Size(2666666666, 2000000000),
+            ScaleSizeToEncompassTarget(gfx::Size(40000, 30000),
+                                       gfx::Size(2000000000, 2000000000)));
+  EXPECT_TRUE(ScaleSizeToEncompassTarget(
+      gfx::Size(0, 0), gfx::Size(2000000000, 2000000000)).IsEmpty());
+}
+
+TEST_F(VideoUtilTest, PadToMatchAspectRatio) {
+  EXPECT_EQ(gfx::Size(640, 480),
+            PadToMatchAspectRatio(gfx::Size(640, 480), gfx::Size(640, 480)));
+  EXPECT_EQ(gfx::Size(640, 480),
+            PadToMatchAspectRatio(gfx::Size(640, 480), gfx::Size(4, 3)));
+  EXPECT_EQ(gfx::Size(960, 480),
+            PadToMatchAspectRatio(gfx::Size(640, 480), gfx::Size(1000, 500)));
+  EXPECT_EQ(gfx::Size(640, 1280),
+            PadToMatchAspectRatio(gfx::Size(640, 480), gfx::Size(500, 1000)));
+  EXPECT_EQ(gfx::Size(2160, 1080),
+            PadToMatchAspectRatio(gfx::Size(1920, 1080), gfx::Size(1000, 500)));
+  EXPECT_EQ(gfx::Size(400, 400),
+            PadToMatchAspectRatio(gfx::Size(400, 300), gfx::Size(100, 100)));
+  EXPECT_EQ(gfx::Size(400, 400),
+            PadToMatchAspectRatio(gfx::Size(300, 400), gfx::Size(100, 100)));
+  EXPECT_EQ(gfx::Size(40000, 40000),
+            PadToMatchAspectRatio(gfx::Size(40000, 30000),
+                                  gfx::Size(2000000000, 2000000000)));
+  EXPECT_TRUE(PadToMatchAspectRatio(
+      gfx::Size(40000, 30000), gfx::Size(0, 0)).IsEmpty());
+}
+
 TEST_F(VideoUtilTest, LetterboxYUV) {
   int width = 40;
   int height = 30;
diff --git a/media/blink/key_system_config_selector.cc b/media/blink/key_system_config_selector.cc
index 24cbf9f3..ff53449d 100644
--- a/media/blink/key_system_config_selector.cc
+++ b/media/blink/key_system_config_selector.cc
@@ -11,8 +11,8 @@
 #include "media/base/cdm_config.h"
 #include "media/base/key_systems.h"
 #include "media/base/media_permission.h"
+#include "media/base/mime_util.h"
 #include "media/blink/webmediaplayer_util.h"
-#include "net/base/mime_util.h"
 #include "third_party/WebKit/public/platform/WebMediaKeySystemConfiguration.h"
 #include "third_party/WebKit/public/platform/WebSecurityOrigin.h"
 #include "third_party/WebKit/public/platform/WebString.h"
@@ -284,7 +284,7 @@
   std::string container_lower = base::StringToLowerASCII(container_mime_type);
 
   // Check that |container_mime_type| is supported by Chrome.
-  if (!net::IsSupportedMediaMimeType(container_lower))
+  if (!media::IsSupportedMediaMimeType(container_lower))
     return false;
 
   // Check that |codecs| are supported by Chrome. This is done primarily to
@@ -292,10 +292,10 @@
   // codecs that Chrome does not (which could complicate the robustness
   // algorithm).
   std::vector<std::string> codec_vector;
-  net::ParseCodecString(codecs, &codec_vector, false);
+  media::ParseCodecString(codecs, &codec_vector, false);
   if (!codec_vector.empty() &&
-      (net::IsSupportedStrictMediaMimeType(container_lower, codec_vector) !=
-       net::IsSupported)) {
+      (media::IsSupportedStrictMediaMimeType(container_lower, codec_vector) !=
+       media::IsSupported)) {
     return false;
   }
 
@@ -303,7 +303,7 @@
   // This check does not handle extended codecs, so extended codec information
   // is stripped (extended codec information was checked above).
   std::vector<std::string> stripped_codec_vector;
-  net::ParseCodecString(codecs, &stripped_codec_vector, true);
+  media::ParseCodecString(codecs, &stripped_codec_vector, true);
   EmeConfigRule codecs_rule = key_systems_->GetContentTypeConfigRule(
       key_system, media_type, container_lower, stripped_codec_vector);
   if (!config_state->IsRuleSupported(codecs_rule))
diff --git a/media/cast/sender/fake_software_video_encoder.cc b/media/cast/sender/fake_software_video_encoder.cc
index 7a2a333..0cd01396 100644
--- a/media/cast/sender/fake_software_video_encoder.cc
+++ b/media/cast/sender/fake_software_video_encoder.cc
@@ -57,7 +57,7 @@
   values.SetInteger("ref", encoded_frame->referenced_frame_id);
   values.SetInteger("id", encoded_frame->frame_id);
   values.SetInteger("size", frame_size_);
-  base::JSONWriter::Write(&values, &encoded_frame->data);
+  base::JSONWriter::Write(values, &encoded_frame->data);
   encoded_frame->data.resize(
       std::max<size_t>(encoded_frame->data.size(), frame_size_), ' ');
 }
diff --git a/media/cast/test/sender.cc b/media/cast/test/sender.cc
index e34ecf12..73986987 100644
--- a/media/cast/test/sender.cc
+++ b/media/cast/test/sender.cc
@@ -187,13 +187,13 @@
   scoped_ptr<base::DictionaryValue> stats = video_event_subscriber->GetStats();
   std::string json;
   base::JSONWriter::WriteWithOptions(
-      stats.get(), base::JSONWriter::OPTIONS_PRETTY_PRINT, &json);
+      *stats, base::JSONWriter::OPTIONS_PRETTY_PRINT, &json);
   VLOG(0) << "Video stats: " << json;
 
   stats = audio_event_subscriber->GetStats();
   json.clear();
   base::JSONWriter::WriteWithOptions(
-      stats.get(), base::JSONWriter::OPTIONS_PRETTY_PRINT, &json);
+      *stats, base::JSONWriter::OPTIONS_PRETTY_PRINT, &json);
   VLOG(0) << "Audio stats: " << json;
 }
 
diff --git a/media/cast/test/simulator.cc b/media/cast/test/simulator.cc
index 6c277d56..a3a560e 100644
--- a/media/cast/test/simulator.cc
+++ b/media/cast/test/simulator.cc
@@ -766,7 +766,7 @@
   values.SetString("sim-id", sim_id);
 
   std::string extra_data;
-  base::JSONWriter::Write(&values, &extra_data);
+  base::JSONWriter::Write(values, &extra_data);
 
   // Run.
   media::cast::RunSimulation(source_path, log_output_path, metrics_output_path,
diff --git a/media/formats/mp4/box_definitions.cc b/media/formats/mp4/box_definitions.cc
index a08cb26d..5a15240 100644
--- a/media/formats/mp4/box_definitions.cc
+++ b/media/formats/mp4/box_definitions.cc
@@ -657,12 +657,15 @@
 FourCC Movie::BoxType() const { return FOURCC_MOOV; }
 
 bool Movie::Parse(BoxReader* reader) {
-  return reader->ScanChildren() &&
-         reader->ReadChild(&header) &&
-         reader->ReadChildren(&tracks) &&
-         // Media Source specific: 'mvex' required
-         reader->ReadChild(&extends) &&
-         reader->MaybeReadChildren(&pssh);
+  RCHECK(reader->ScanChildren() && reader->ReadChild(&header) &&
+         reader->ReadChildren(&tracks));
+
+  RCHECK_MEDIA_LOGGED(reader->ReadChild(&extends), reader->log_cb(),
+                      "Detected unfragmented MP4. Media Source Extensions "
+                      "require ISO BMFF moov to contain mvex to indicate that "
+                      "Movie Fragments are to be expected.");
+
+  return reader->MaybeReadChildren(&pssh);
 }
 
 TrackFragmentDecodeTime::TrackFragmentDecodeTime() : decode_time(0) {}
diff --git a/media/formats/mp4/box_definitions.h b/media/formats/mp4/box_definitions.h
index 1271403..026effe 100644
--- a/media/formats/mp4/box_definitions.h
+++ b/media/formats/mp4/box_definitions.h
@@ -11,6 +11,7 @@
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
 #include "media/base/media_export.h"
+#include "media/base/media_log.h"
 #include "media/formats/mp4/aac.h"
 #include "media/formats/mp4/avc.h"
 #include "media/formats/mp4/box_reader.h"
diff --git a/media/formats/mp4/box_reader.cc b/media/formats/mp4/box_reader.cc
index edebddd..5105726d 100644
--- a/media/formats/mp4/box_reader.cc
+++ b/media/formats/mp4/box_reader.cc
@@ -219,7 +219,8 @@
   CHECK(Read4Into8(&size) && ReadFourCC(&type_));
 
   if (size == 0) {
-    // Media Source specific: we do not support boxes that run to EOS.
+    MEDIA_LOG(DEBUG, log_cb_) << "Media Source Extensions do not support ISO "
+                                 "BMFF boxes that run to EOS";
     *err = true;
     return false;
   } else if (size == 1) {
diff --git a/media/formats/mp4/box_reader.h b/media/formats/mp4/box_reader.h
index 3360204..6b59361 100644
--- a/media/formats/mp4/box_reader.h
+++ b/media/formats/mp4/box_reader.h
@@ -22,7 +22,10 @@
 
 struct MEDIA_EXPORT Box {
   virtual ~Box();
+
+  // Parse errors may be logged using the BoxReader's log callback.
   virtual bool Parse(BoxReader* reader) = 0;
+
   virtual FourCC BoxType() const = 0;
 };
 
diff --git a/media/formats/mp4/rcheck.h b/media/formats/mp4/rcheck.h
index fb0f8f27..d756487 100644
--- a/media/formats/mp4/rcheck.h
+++ b/media/formats/mp4/rcheck.h
@@ -6,13 +6,25 @@
 #define MEDIA_FORMATS_MP4_RCHECK_H_
 
 #include "base/logging.h"
+#include "media/base/media_log.h"
 
-#define RCHECK(x) \
-    do { \
-      if (!(x)) { \
-        DLOG(ERROR) << "Failure while parsing MP4: " << #x; \
-        return false; \
-      } \
-    } while (0)
+#define RCHECK_MEDIA_LOGGED(condition, log_cb, msg)                 \
+  do {                                                              \
+    if (!(condition)) {                                             \
+      DLOG(ERROR) << "Failure while parsing MP4: " #condition;      \
+      MEDIA_LOG(ERROR, log_cb) << "Failure parsing MP4: " << (msg); \
+      return false;                                                 \
+    }                                                               \
+  } while (0)
+
+// TODO(wolenetz,chcunningham): Where appropriate, replace usage of this macro
+// in favor of RCHECK_MEDIA_LOGGED. See https://crbug.com/487410.
+#define RCHECK(condition)                                      \
+  do {                                                         \
+    if (!(condition)) {                                        \
+      DLOG(ERROR) << "Failure while parsing MP4: " #condition; \
+      return false;                                            \
+    }                                                          \
+  } while (0)
 
 #endif  // MEDIA_FORMATS_MP4_RCHECK_H_
diff --git a/media/media.gyp b/media/media.gyp
index ed6aa66..312f426 100644
--- a/media/media.gyp
+++ b/media/media.gyp
@@ -259,6 +259,7 @@
         'base/byte_queue.h',
         'base/cdm_callback_promise.cc',
         'base/cdm_callback_promise.h',
+        'base/cdm_config.h',
         'base/cdm_context.cc',
         'base/cdm_context.h',
         'base/cdm_factory.cc',
@@ -330,6 +331,8 @@
         'base/media_switches.cc',
         'base/media_switches.h',
         'base/media_win.cc',
+        'base/mime_util.cc',
+        'base/mime_util.h',
         'base/moving_average.cc',
         'base/moving_average.h',
         'base/multi_channel_resampler.cc',
@@ -1141,6 +1144,7 @@
         'base/key_systems_unittest.cc',
         'base/mac/video_frame_mac_unittests.cc',
         'base/media_file_checker_unittest.cc',
+        'base/mime_util_unittest.cc',
         'base/moving_average_unittest.cc',
         'base/multi_channel_resampler_unittest.cc',
         'base/null_video_sink_unittest.cc',
diff --git a/mojo/runner/android/apk/src/org/chromium/mojo/shell/MojoShellActivity.java b/mojo/runner/android/apk/src/org/chromium/mojo/shell/MojoShellActivity.java
index a56c43d..901012fb 100644
--- a/mojo/runner/android/apk/src/org/chromium/mojo/shell/MojoShellActivity.java
+++ b/mojo/runner/android/apk/src/org/chromium/mojo/shell/MojoShellActivity.java
@@ -6,9 +6,11 @@
 
 import android.app.Activity;
 import android.content.Intent;
+import android.net.Uri;
 import android.os.Bundle;
 import android.util.JsonReader;
-import android.util.Log;
+
+import org.chromium.base.Log;
 
 import java.io.IOException;
 import java.io.StringReader;
@@ -25,6 +27,22 @@
     protected void onCreate(final Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
+        String[] parameters = getParametersFromIntent(getIntent());
+        if (Intent.ACTION_VIEW.equals(getIntent().getAction())) {
+            Uri uri = getIntent().getData();
+            if (uri != null) {
+                Log.i(TAG, "MojoShellActivity opening " + uri);
+                if (parameters == null) {
+                    parameters = new String[] {uri.toString()};
+                } else {
+                    String[] newParameters = new String[parameters.length + 1];
+                    System.arraycopy(parameters, 0, newParameters, 0, parameters.length);
+                    newParameters[parameters.length] = uri.toString();
+                    parameters = newParameters;
+                }
+            }
+        }
+
         // TODO(ppi): Gotcha - the call below will work only once per process lifetime, but the OS
         // has no obligation to kill the application process between destroying and restarting the
         // activity. If the application process is kept alive, initialization parameters sent with
@@ -32,7 +50,7 @@
         // TODO(qsr): We should be passing application context here as required by
         // InitApplicationContext on the native side. Currently we can't, as PlatformViewportAndroid
         // relies on this being the activity context.
-        ShellMain.ensureInitialized(this, getParametersFromIntent(getIntent()));
+        ShellMain.ensureInitialized(this, parameters);
 
         // TODO(eseidel): ShellMain can fail, but we're ignoring the return.
         ShellMain.start();
diff --git a/mojo/services/network/BUILD.gn b/mojo/services/network/BUILD.gn
index 203bd5e..4cc0839 100644
--- a/mojo/services/network/BUILD.gn
+++ b/mojo/services/network/BUILD.gn
@@ -115,6 +115,7 @@
   testonly = true
 
   sources = [
+    "http_server_apptest.cc",
     "udp_socket_apptest.cc",
     "url_loader_impl_apptest.cc",
   ]
diff --git a/mojo/services/network/http_connection_impl.cc b/mojo/services/network/http_connection_impl.cc
index 47449ecd..be306cd 100644
--- a/mojo/services/network/http_connection_impl.cc
+++ b/mojo/services/network/http_connection_impl.cc
@@ -6,14 +6,114 @@
 
 #include <limits>
 
+#include "base/bind_helpers.h"
+#include "base/callback.h"
+#include "base/logging.h"
+#include "base/stl_util.h"
+#include "base/strings/string_util.h"
+#include "mojo/common/handle_watcher.h"
 #include "mojo/services/network/http_server_impl.h"
 #include "mojo/services/network/net_adapters.h"
 #include "net/base/net_errors.h"
+#include "net/http/http_request_headers.h"
+#include "net/http/http_status_code.h"
 #include "net/server/http_server.h"
 #include "net/server/http_server_request_info.h"
+#include "net/server/http_server_response_info.h"
+#include "third_party/mojo/src/mojo/public/cpp/bindings/type_converter.h"
+#include "third_party/mojo/src/mojo/public/cpp/system/data_pipe.h"
 
 namespace mojo {
 
+// SimpleDataPipeReader reads till end-of-file, stores the data in a string and
+// notifies completion.
+class HttpConnectionImpl::SimpleDataPipeReader {
+ public:
+  using CompletionCallback =
+      base::Callback<void(SimpleDataPipeReader*, scoped_ptr<std::string>)>;
+
+  SimpleDataPipeReader() {}
+  ~SimpleDataPipeReader() {}
+
+  void Start(ScopedDataPipeConsumerHandle consumer,
+             const CompletionCallback& completion_callback) {
+    DCHECK(consumer.is_valid() && !consumer_.is_valid());
+    consumer_ = consumer.Pass();
+    completion_callback_ = completion_callback;
+    buffer_.reset(new std::string);
+    ReadMore();
+  }
+
+ private:
+  void ReadMore() {
+    const void* buf;
+    uint32_t buf_size;
+    MojoResult rv = BeginReadDataRaw(consumer_.get(), &buf, &buf_size,
+                                     MOJO_READ_DATA_FLAG_NONE);
+    if (rv == MOJO_RESULT_OK) {
+      buffer_->append(static_cast<const char*>(buf), buf_size);
+      EndReadDataRaw(consumer_.get(), buf_size);
+      WaitToReadMore();
+    } else if (rv == MOJO_RESULT_SHOULD_WAIT) {
+      WaitToReadMore();
+    } else if (rv == MOJO_RESULT_FAILED_PRECONDITION) {
+      // We reached end-of-file.
+      completion_callback_.Run(this, buffer_.Pass());
+      // Note: This object may have been destroyed in the callback.
+    } else {
+      CHECK(false);
+    }
+  }
+
+  void WaitToReadMore() {
+    watcher_.Start(consumer_.get(), MOJO_HANDLE_SIGNAL_READABLE,
+                   MOJO_DEADLINE_INDEFINITE,
+                   base::Bind(&SimpleDataPipeReader::OnHandleReady,
+                              base::Unretained(this)));
+  }
+
+  void OnHandleReady(MojoResult result) { ReadMore(); }
+
+  ScopedDataPipeConsumerHandle consumer_;
+  common::HandleWatcher watcher_;
+  CompletionCallback completion_callback_;
+  scoped_ptr<std::string> buffer_;
+
+  DISALLOW_COPY_AND_ASSIGN(SimpleDataPipeReader);
+};
+
+template <>
+struct TypeConverter<HttpRequestPtr, net::HttpServerRequestInfo> {
+  static HttpRequestPtr Convert(const net::HttpServerRequestInfo& obj) {
+    HttpRequestPtr request(HttpRequest::New());
+    request->method = obj.method;
+    request->url = obj.path;
+    request->headers.resize(obj.headers.size());
+    size_t index = 0;
+    for (const auto& item : obj.headers) {
+      HttpHeaderPtr header(HttpHeader::New());
+      header->name = item.first;
+      header->value = item.second;
+      request->headers[index++] = header.Pass();
+    }
+    if (!obj.data.empty()) {
+      uint32_t num_bytes = static_cast<uint32_t>(obj.data.size());
+      MojoCreateDataPipeOptions options;
+      options.struct_size = sizeof(MojoCreateDataPipeOptions);
+      options.flags = MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE;
+      options.element_num_bytes = 1;
+      options.capacity_num_bytes = num_bytes;
+      DataPipe data_pipe(options);
+      request->body = data_pipe.consumer_handle.Pass();
+      MojoResult result =
+          WriteDataRaw(data_pipe.producer_handle.get(), obj.data.data(),
+                       &num_bytes, MOJO_WRITE_DATA_FLAG_ALL_OR_NONE);
+      CHECK_EQ(MOJO_RESULT_OK, result);
+    }
+    return request.Pass();
+  }
+};
+
 HttpConnectionImpl::HttpConnectionImpl(int connection_id,
                                        HttpServerImpl* owner,
                                        HttpConnectionDelegatePtr delegate,
@@ -22,15 +122,33 @@
       owner_(owner),
       delegate_(delegate.Pass()),
       binding_(this, connection) {
+  DCHECK(delegate_);
   binding_.set_error_handler(this);
   delegate_.set_error_handler(this);
 }
 
-HttpConnectionImpl::~HttpConnectionImpl() {}
+HttpConnectionImpl::~HttpConnectionImpl() {
+  STLDeleteElements(&response_body_readers_);
+}
 
 void HttpConnectionImpl::OnReceivedHttpRequest(
     const net::HttpServerRequestInfo& info) {
-  // TODO(yzshen): implement it.
+  if (EncounteredConnectionError())
+    return;
+
+  delegate_->OnReceivedRequest(
+      HttpRequest::From(info), [this](HttpResponsePtr response) {
+        if (response->body.is_valid()) {
+          SimpleDataPipeReader* reader = new SimpleDataPipeReader;
+          response_body_readers_.insert(reader);
+          reader->Start(
+              response->body.Pass(),
+              base::Bind(&HttpConnectionImpl::OnFinishedReadingResponseBody,
+                         base::Unretained(this), base::Passed(&response)));
+        } else {
+          OnFinishedReadingResponseBody(response.Pass(), nullptr, nullptr);
+        }
+      });
 }
 
 void HttpConnectionImpl::OnReceivedWebSocketRequest(
@@ -65,9 +183,61 @@
 }
 
 void HttpConnectionImpl::OnConnectionError() {
-  // The proxy side of |binding_| or the impl side of |delegate_| has closed the
-  // pipe. The connection is not needed anymore.
-  owner_->server()->Close(connection_id_);
+  // This method is called when the proxy side of |binding_| or the impl side of
+  // |delegate_| has closed the pipe. Although it is set as error handler for
+  // both |binding_| and |delegate_|, it will only be called at most once
+  // because when called it closes/resets |binding_| and |delegate_|.
+  DCHECK(!EncounteredConnectionError());
+
+  binding_.Close();
+  delegate_.reset();
+
+  // Don't close the connection until all pending responses are sent.
+  if (response_body_readers_.empty())
+    owner_->server()->Close(connection_id_);
+}
+
+void HttpConnectionImpl::OnFinishedReadingResponseBody(
+    HttpResponsePtr response,
+    SimpleDataPipeReader* reader,
+    scoped_ptr<std::string> body) {
+  if (reader) {
+    delete reader;
+    response_body_readers_.erase(reader);
+  }
+
+  net::HttpServerResponseInfo info(
+      static_cast<net::HttpStatusCode>(response->status_code));
+
+  std::string content_type;
+  for (size_t i = 0; i < response->headers.size(); ++i) {
+    const HttpHeader& header = *(response->headers[i]);
+
+    if (body) {
+      // net::HttpServerResponseInfo::SetBody() automatically sets
+      // Content-Length and Content-Types, so skip the two here.
+      //
+      // TODO(yzshen): Consider adding to net::HttpServerResponseInfo a simple
+      // setter for body which doesn't fiddle with headers.
+      if (base::strcasecmp(header.name.data(),
+                           net::HttpRequestHeaders::kContentLength) == 0) {
+        continue;
+      } else if (base::strcasecmp(header.name.data(),
+                                  net::HttpRequestHeaders::kContentType) == 0) {
+        content_type = header.value;
+        continue;
+      }
+    }
+    info.AddHeader(header.name, header.value);
+  }
+
+  if (body)
+    info.SetBody(*body, content_type);
+
+  owner_->server()->SendResponse(connection_id_, info);
+
+  if (response_body_readers_.empty() && EncounteredConnectionError())
+    owner_->server()->Close(connection_id_);
 }
 
 }  // namespace mojo
diff --git a/mojo/services/network/http_connection_impl.h b/mojo/services/network/http_connection_impl.h
index 84d669a7..7f952310 100644
--- a/mojo/services/network/http_connection_impl.h
+++ b/mojo/services/network/http_connection_impl.h
@@ -5,10 +5,13 @@
 #ifndef MOJO_SERVICES_NETWORK_HTTP_CONNECTION_IMPL_H_
 #define MOJO_SERVICES_NETWORK_HTTP_CONNECTION_IMPL_H_
 
+#include <set>
 #include <string>
 
 #include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
 #include "mojo/services/network/public/interfaces/http_connection.mojom.h"
+#include "mojo/services/network/public/interfaces/http_message.mojom.h"
 #include "third_party/mojo/src/mojo/public/cpp/bindings/binding.h"
 #include "third_party/mojo/src/mojo/public/cpp/bindings/error_handler.h"
 
@@ -36,6 +39,8 @@
   void OnReceivedWebSocketMessage(const std::string& data);
 
  private:
+  class SimpleDataPipeReader;
+
   // HttpConnection implementation.
   void SetSendBufferSize(uint32_t size,
                          const SetSendBufferSizeCallback& callback) override;
@@ -46,10 +51,20 @@
   // ErrorHandler implementation.
   void OnConnectionError() override;
 
+  void OnFinishedReadingResponseBody(HttpResponsePtr response_ptr,
+                                     SimpleDataPipeReader* reader,
+                                     scoped_ptr<std::string> body);
+
+  bool EncounteredConnectionError() const {
+    return !binding_.is_bound() || !delegate_;
+  }
+
   const int connection_id_;
   HttpServerImpl* const owner_;
   HttpConnectionDelegatePtr delegate_;
   Binding<HttpConnection> binding_;
+  // Owns its elements.
+  std::set<SimpleDataPipeReader*> response_body_readers_;
 
   DISALLOW_COPY_AND_ASSIGN(HttpConnectionImpl);
 };
diff --git a/mojo/services/network/http_server_apptest.cc b/mojo/services/network/http_server_apptest.cc
new file mode 100644
index 0000000..1fe8e50
--- /dev/null
+++ b/mojo/services/network/http_server_apptest.cc
@@ -0,0 +1,481 @@
+// 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 "base/macros.h"
+#include "base/memory/linked_ptr.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/run_loop.h"
+#include "base/strings/string_util.h"
+#include "mojo/application/application_test_base_chromium.h"
+#include "mojo/application/public/cpp/application_connection.h"
+#include "mojo/application/public/cpp/application_impl.h"
+#include "mojo/common/data_pipe_utils.h"
+#include "mojo/services/network/net_address_type_converters.h"
+#include "mojo/services/network/public/interfaces/http_server.mojom.h"
+#include "mojo/services/network/public/interfaces/network_service.mojom.h"
+#include "net/base/io_buffer.h"
+#include "net/base/net_errors.h"
+#include "net/base/test_completion_callback.h"
+#include "net/http/http_response_headers.h"
+#include "net/http/http_util.h"
+#include "net/socket/tcp_client_socket.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace mojo {
+namespace {
+
+const int kMaxExpectedResponseLength = 2048;
+
+NetAddressPtr GetLocalHostWithAnyPort() {
+  NetAddressPtr addr(NetAddress::New());
+  addr->family = NET_ADDRESS_FAMILY_IPV4;
+  addr->ipv4 = NetAddressIPv4::New();
+  addr->ipv4->port = 0;
+  addr->ipv4->addr.resize(4);
+  addr->ipv4->addr[0] = 127;
+  addr->ipv4->addr[1] = 0;
+  addr->ipv4->addr[2] = 0;
+  addr->ipv4->addr[3] = 1;
+
+  return addr.Pass();
+}
+
+using TestHeaders = std::vector<std::pair<std::string, std::string>>;
+
+struct TestRequest {
+  std::string method;
+  std::string url;
+  TestHeaders headers;
+  scoped_ptr<std::string> body;
+};
+
+struct TestResponse {
+  uint32_t status_code;
+  TestHeaders headers;
+  scoped_ptr<std::string> body;
+};
+
+std::string MakeRequestMessage(const TestRequest& data) {
+  std::string message = data.method + " " + data.url + " HTTP/1.1\r\n";
+  for (const auto& item : data.headers)
+    message += item.first + ": " + item.second + "\r\n";
+  message += "\r\n";
+  if (data.body)
+    message += *data.body;
+
+  return message;
+}
+
+HttpResponsePtr MakeResponseStruct(const TestResponse& data) {
+  HttpResponsePtr response(HttpResponse::New());
+  response->status_code = data.status_code;
+  response->headers.resize(data.headers.size());
+  size_t index = 0;
+  for (const auto& item : data.headers) {
+    HttpHeaderPtr header(HttpHeader::New());
+    header->name = item.first;
+    header->value = item.second;
+    response->headers[index++] = header.Pass();
+  }
+
+  if (data.body) {
+    uint32_t num_bytes = static_cast<uint32_t>(data.body->size());
+    MojoCreateDataPipeOptions options;
+    options.struct_size = sizeof(MojoCreateDataPipeOptions);
+    options.flags = MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE;
+    options.element_num_bytes = 1;
+    options.capacity_num_bytes = num_bytes;
+    DataPipe data_pipe(options);
+    response->body = data_pipe.consumer_handle.Pass();
+    MojoResult result =
+        WriteDataRaw(data_pipe.producer_handle.get(), data.body->data(),
+                     &num_bytes, MOJO_WRITE_DATA_FLAG_ALL_OR_NONE);
+    EXPECT_EQ(MOJO_RESULT_OK, result);
+  }
+
+  return response.Pass();
+}
+
+void CheckHeaders(const TestHeaders& expected,
+                  const Array<HttpHeaderPtr>& headers) {
+  // The server impl fiddles with Content-Length and Content-Type. So we don't
+  // do a strict check here.
+  std::map<std::string, std::string> header_map;
+  for (size_t i = 0; i < headers.size(); ++i) {
+    std::string lower_name =
+        base::StringToLowerASCII(headers[i]->name.To<std::string>());
+    header_map[lower_name] = headers[i]->value;
+  }
+
+  for (const auto& item : expected) {
+    std::string lower_name = base::StringToLowerASCII(item.first);
+    EXPECT_NE(header_map.end(), header_map.find(lower_name));
+    EXPECT_EQ(item.second, header_map[lower_name]);
+  }
+}
+
+void CheckRequest(const TestRequest& expected, HttpRequestPtr request) {
+  EXPECT_EQ(expected.method, request->method);
+  EXPECT_EQ(expected.url, request->url);
+  CheckHeaders(expected.headers, request->headers);
+  if (expected.body) {
+    EXPECT_TRUE(request->body.is_valid());
+    std::string body;
+    common::BlockingCopyToString(request->body.Pass(), &body);
+    EXPECT_EQ(*expected.body, body);
+  } else {
+    EXPECT_FALSE(request->body.is_valid());
+  }
+}
+
+void CheckResponse(const TestResponse& expected, const std::string& response) {
+  int header_end =
+      net::HttpUtil::LocateEndOfHeaders(response.c_str(), response.size());
+  std::string assembled_headers =
+      net::HttpUtil::AssembleRawHeaders(response.c_str(), header_end);
+  scoped_refptr<net::HttpResponseHeaders> parsed_headers(
+      new net::HttpResponseHeaders(assembled_headers));
+  EXPECT_EQ(expected.status_code,
+            static_cast<uint32_t>(parsed_headers->response_code()));
+  for (const auto& item : expected.headers)
+    EXPECT_TRUE(parsed_headers->HasHeaderValue(item.first, item.second));
+
+  if (expected.body) {
+    EXPECT_NE(-1, header_end);
+    std::string body(response, static_cast<size_t>(header_end));
+    EXPECT_EQ(*expected.body, body);
+  } else {
+    EXPECT_EQ(response.size(), static_cast<size_t>(header_end));
+  }
+}
+
+class TestHttpClient {
+ public:
+  TestHttpClient() : connect_result_(net::OK) {}
+
+  void Connect(const net::IPEndPoint& address) {
+    net::AddressList addresses(address);
+    net::NetLog::Source source;
+    socket_.reset(new net::TCPClientSocket(addresses, NULL, source));
+
+    base::RunLoop run_loop;
+    connect_result_ = socket_->Connect(base::Bind(&TestHttpClient::OnConnect,
+                                                  base::Unretained(this),
+                                                  run_loop.QuitClosure()));
+    if (connect_result_ == net::ERR_IO_PENDING)
+      run_loop.Run();
+
+    ASSERT_EQ(net::OK, connect_result_);
+  }
+
+  void Send(const std::string& data) {
+    write_buffer_ = new net::DrainableIOBuffer(new net::StringIOBuffer(data),
+                                               data.length());
+    Write();
+  }
+
+  // Note: This method determines the end of the response only by Content-Length
+  // and connection termination. Besides, it doesn't truncate at the end of the
+  // response, so |message| may return more data (e.g., part of the next
+  // response).
+  void ReadResponse(std::string* message) {
+    if (!Read(message, 1))
+      return;
+    while (!IsCompleteResponse(*message)) {
+      std::string chunk;
+      if (!Read(&chunk, 1))
+        return;
+      message->append(chunk);
+    }
+    return;
+  }
+
+ private:
+  void OnConnect(const base::Closure& quit_loop, int result) {
+    connect_result_ = result;
+    quit_loop.Run();
+  }
+
+  void Write() {
+    int result = socket_->Write(
+        write_buffer_.get(), write_buffer_->BytesRemaining(),
+        base::Bind(&TestHttpClient::OnWrite, base::Unretained(this)));
+    if (result != net::ERR_IO_PENDING)
+      OnWrite(result);
+  }
+
+  void OnWrite(int result) {
+    ASSERT_GT(result, 0);
+    write_buffer_->DidConsume(result);
+    if (write_buffer_->BytesRemaining())
+      Write();
+  }
+
+  bool Read(std::string* message, int expected_bytes) {
+    int total_bytes_received = 0;
+    message->clear();
+    while (total_bytes_received < expected_bytes) {
+      net::TestCompletionCallback callback;
+      ReadInternal(callback.callback());
+      int bytes_received = callback.WaitForResult();
+      if (bytes_received <= 0)
+        return false;
+
+      total_bytes_received += bytes_received;
+      message->append(read_buffer_->data(), bytes_received);
+    }
+    return true;
+  }
+
+  void ReadInternal(const net::CompletionCallback& callback) {
+    read_buffer_ = new net::IOBufferWithSize(kMaxExpectedResponseLength);
+    int result =
+        socket_->Read(read_buffer_.get(), kMaxExpectedResponseLength, callback);
+    if (result != net::ERR_IO_PENDING)
+      callback.Run(result);
+  }
+
+  bool IsCompleteResponse(const std::string& response) {
+    // Check end of headers first.
+    int end_of_headers =
+        net::HttpUtil::LocateEndOfHeaders(response.data(), response.size());
+    if (end_of_headers < 0)
+      return false;
+
+    // Return true if response has data equal to or more than content length.
+    int64 body_size = static_cast<int64>(response.size()) - end_of_headers;
+    DCHECK_LE(0, body_size);
+    scoped_refptr<net::HttpResponseHeaders> headers(
+        new net::HttpResponseHeaders(net::HttpUtil::AssembleRawHeaders(
+            response.data(), end_of_headers)));
+    return body_size >= headers->GetContentLength();
+  }
+
+  scoped_refptr<net::IOBufferWithSize> read_buffer_;
+  scoped_refptr<net::DrainableIOBuffer> write_buffer_;
+  scoped_ptr<net::TCPClientSocket> socket_;
+  int connect_result_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestHttpClient);
+};
+
+class HttpConnectionDelegateImpl : public HttpConnectionDelegate {
+ public:
+  struct PendingRequest {
+    HttpRequestPtr request;
+    OnReceivedRequestCallback callback;
+  };
+
+  HttpConnectionDelegateImpl(HttpConnectionPtr connection,
+                             InterfaceRequest<HttpConnectionDelegate> request)
+      : connection_(connection.Pass()),
+        binding_(this, request.Pass()),
+        run_loop_(nullptr),
+        wait_for_request_count_(0) {}
+  ~HttpConnectionDelegateImpl() override {}
+
+  // HttpConnectionDelegate implementation:
+  void OnReceivedRequest(HttpRequestPtr request,
+                         const OnReceivedRequestCallback& callback) override {
+    linked_ptr<PendingRequest> pending_request(new PendingRequest);
+    pending_request->request = request.Pass();
+    pending_request->callback = callback;
+    pending_requests_.push_back(pending_request);
+    if (run_loop_ && pending_requests_.size() >= wait_for_request_count_) {
+      wait_for_request_count_ = 0;
+      run_loop_->Quit();
+    }
+  }
+
+  void OnReceivedWebSocketRequest(
+      HttpRequestPtr request,
+      const OnReceivedWebSocketRequestCallback& callback) override {
+    NOTREACHED();
+  }
+
+  void SendResponse(HttpResponsePtr response) {
+    ASSERT_FALSE(pending_requests_.empty());
+    linked_ptr<PendingRequest> request = pending_requests_[0];
+    pending_requests_.erase(pending_requests_.begin());
+    request->callback.Run(response.Pass());
+  }
+
+  void WaitForRequest(size_t count) {
+    DCHECK(!run_loop_);
+
+    wait_for_request_count_ = count;
+    base::RunLoop run_loop;
+    run_loop_ = &run_loop;
+    run_loop.Run();
+    run_loop_ = nullptr;
+  }
+
+  std::vector<linked_ptr<PendingRequest>>& pending_requests() {
+    return pending_requests_;
+  }
+
+ private:
+  HttpConnectionPtr connection_;
+  Binding<HttpConnectionDelegate> binding_;
+  std::vector<linked_ptr<PendingRequest>> pending_requests_;
+  // Pointing to a stack-allocated RunLoop instance.
+  base::RunLoop* run_loop_;
+  size_t wait_for_request_count_;
+
+  DISALLOW_COPY_AND_ASSIGN(HttpConnectionDelegateImpl);
+};
+
+class HttpServerDelegateImpl : public HttpServerDelegate {
+ public:
+  explicit HttpServerDelegateImpl(HttpServerDelegatePtr* delegate_ptr)
+      : binding_(this, delegate_ptr),
+        run_loop_(nullptr),
+        wait_for_connection_count_(0) {}
+  ~HttpServerDelegateImpl() override {}
+
+  // HttpServerDelegate implementation.
+  void OnConnected(HttpConnectionPtr connection,
+                   InterfaceRequest<HttpConnectionDelegate> delegate) override {
+    connections_.push_back(make_linked_ptr(
+        new HttpConnectionDelegateImpl(connection.Pass(), delegate.Pass())));
+    if (run_loop_ && connections_.size() >= wait_for_connection_count_) {
+      wait_for_connection_count_ = 0;
+      run_loop_->Quit();
+    }
+  }
+
+  void WaitForConnection(size_t count) {
+    DCHECK(!run_loop_);
+
+    wait_for_connection_count_ = count;
+    base::RunLoop run_loop;
+    run_loop_ = &run_loop;
+    run_loop.Run();
+    run_loop_ = nullptr;
+  }
+
+  std::vector<linked_ptr<HttpConnectionDelegateImpl>>& connections() {
+    return connections_;
+  }
+
+ private:
+  Binding<HttpServerDelegate> binding_;
+  std::vector<linked_ptr<HttpConnectionDelegateImpl>> connections_;
+  // Pointing to a stack-allocated RunLoop instance.
+  base::RunLoop* run_loop_;
+  size_t wait_for_connection_count_;
+
+  DISALLOW_COPY_AND_ASSIGN(HttpServerDelegateImpl);
+};
+
+class HttpServerAppTest : public test::ApplicationTestBase {
+ public:
+  HttpServerAppTest() : message_loop_(base::MessageLoop::TYPE_IO) {}
+  ~HttpServerAppTest() override {}
+
+ protected:
+  bool ShouldCreateDefaultRunLoop() override { return false; }
+
+  void SetUp() override {
+    ApplicationTestBase::SetUp();
+
+    ApplicationConnection* connection =
+        application_impl()->ConnectToApplication("mojo:network_service");
+    connection->ConnectToService(&network_service_);
+  }
+
+  void CreateHttpServer(HttpServerDelegatePtr delegate,
+                        NetAddressPtr* out_bound_to) {
+    network_service_->CreateHttpServer(
+        GetLocalHostWithAnyPort(), delegate.Pass(),
+        [out_bound_to](NetworkErrorPtr result, NetAddressPtr bound_to) {
+          ASSERT_EQ(net::OK, result->code);
+          EXPECT_NE(0u, bound_to->ipv4->port);
+          *out_bound_to = bound_to.Pass();
+        });
+    network_service_.WaitForIncomingMethodCall();
+  }
+
+  NetworkServicePtr network_service_;
+
+ private:
+  base::MessageLoop message_loop_;
+
+  DISALLOW_COPY_AND_ASSIGN(HttpServerAppTest);
+};
+
+}  // namespace
+
+TEST_F(HttpServerAppTest, BasicHttpRequestResponse) {
+  NetAddressPtr bound_to;
+  HttpServerDelegatePtr server_delegate_ptr;
+  HttpServerDelegateImpl server_delegate_impl(&server_delegate_ptr);
+  CreateHttpServer(server_delegate_ptr.Pass(), &bound_to);
+
+  TestHttpClient client;
+  client.Connect(bound_to.To<net::IPEndPoint>());
+
+  server_delegate_impl.WaitForConnection(1);
+  HttpConnectionDelegateImpl& connection =
+      *server_delegate_impl.connections()[0];
+
+  TestRequest request_data = {"HEAD", "/test", {{"Hello", "World"}}, nullptr};
+  client.Send(MakeRequestMessage(request_data));
+
+  connection.WaitForRequest(1);
+
+  CheckRequest(request_data, connection.pending_requests()[0]->request.Pass());
+
+  TestResponse response_data = {200, {{"Content-Length", "4"}}, nullptr};
+  connection.SendResponse(MakeResponseStruct(response_data));
+  // This causes the underlying TCP connection to be closed. The client can
+  // determine the end of the response based on that.
+  server_delegate_impl.connections().clear();
+
+  std::string response_message;
+  client.ReadResponse(&response_message);
+
+  CheckResponse(response_data, response_message);
+}
+
+TEST_F(HttpServerAppTest, HttpRequestResponseWithBody) {
+  NetAddressPtr bound_to;
+  HttpServerDelegatePtr server_delegate_ptr;
+  HttpServerDelegateImpl server_delegate_impl(&server_delegate_ptr);
+  CreateHttpServer(server_delegate_ptr.Pass(), &bound_to);
+
+  TestHttpClient client;
+  client.Connect(bound_to.To<net::IPEndPoint>());
+
+  server_delegate_impl.WaitForConnection(1);
+  HttpConnectionDelegateImpl& connection =
+      *server_delegate_impl.connections()[0];
+
+  TestRequest request_data = {
+      "Post",
+      "/test",
+      {{"Hello", "World"},
+       {"Content-Length", "23"},
+       {"Content-Type", "text/plain"}},
+      make_scoped_ptr(new std::string("This is a test request!"))};
+  client.Send(MakeRequestMessage(request_data));
+
+  connection.WaitForRequest(1);
+
+  CheckRequest(request_data, connection.pending_requests()[0]->request.Pass());
+
+  TestResponse response_data = {
+      200,
+      {{"Content-Length", "26"}},
+      make_scoped_ptr(new std::string("This is a test response..."))};
+  connection.SendResponse(MakeResponseStruct(response_data));
+
+  std::string response_message;
+  client.ReadResponse(&response_message);
+
+  CheckResponse(response_data, response_message);
+}
+
+}  // namespace mojo
diff --git a/mojo/services/network/public/interfaces/BUILD.gn b/mojo/services/network/public/interfaces/BUILD.gn
index 9b5c50f..79ddbdc 100644
--- a/mojo/services/network/public/interfaces/BUILD.gn
+++ b/mojo/services/network/public/interfaces/BUILD.gn
@@ -9,6 +9,7 @@
   sources = [
     "cookie_store.mojom",
     "http_connection.mojom",
+    "http_message.mojom",
     "http_server.mojom",
     "net_address.mojom",
     "network_error.mojom",
diff --git a/mojo/services/network/public/interfaces/http_connection.mojom b/mojo/services/network/public/interfaces/http_connection.mojom
index bf98038..1733ed22 100644
--- a/mojo/services/network/public/interfaces/http_connection.mojom
+++ b/mojo/services/network/public/interfaces/http_connection.mojom
@@ -4,7 +4,7 @@
 
 module mojo;
 
-import "network/public/interfaces/url_loader.mojom";
+import "network/public/interfaces/http_message.mojom";
 import "network/public/interfaces/network_error.mojom";
 import "network/public/interfaces/web_socket.mojom";
 
@@ -18,7 +18,7 @@
 
 interface HttpConnectionDelegate {
   // Called when an HTTP request is received.
-  OnReceivedRequest(URLRequest request) => (URLResponse response);
+  OnReceivedRequest(HttpRequest request) => (HttpResponse response);
 
   // Called when an WebSocket request is received.
   //
@@ -28,7 +28,7 @@
   // WebSocket should be written to the producer end of the |send_stream|.
   // |web_socket| will be already connected. There is no need to call Connect()
   // on it. But |client| will still receive a DidConnect() notification.
-  OnReceivedWebSocketRequest(URLRequest request)
+  OnReceivedWebSocketRequest(HttpRequest request)
       => (WebSocket&? web_socket,
           handle<data_pipe_consumer>? send_stream,
           WebSocketClient? client);
diff --git a/mojo/services/network/public/interfaces/http_message.mojom b/mojo/services/network/public/interfaces/http_message.mojom
new file mode 100644
index 0000000..b89ba843
--- /dev/null
+++ b/mojo/services/network/public/interfaces/http_message.mojom
@@ -0,0 +1,23 @@
+// 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.
+
+module mojo;
+
+struct HttpHeader {
+  string name;
+  string value;
+};
+
+struct HttpRequest {
+  string method = "GET";
+  string url;
+  array<HttpHeader>? headers;
+  handle<data_pipe_consumer>? body;
+};
+
+struct HttpResponse {
+  uint32 status_code = 200;
+  array<HttpHeader>? headers;
+  handle<data_pipe_consumer>? body;
+};
diff --git a/mojo/services/network/public/interfaces/url_loader.mojom b/mojo/services/network/public/interfaces/url_loader.mojom
index 4ca3f8d..d0a7164 100644
--- a/mojo/services/network/public/interfaces/url_loader.mojom
+++ b/mojo/services/network/public/interfaces/url_loader.mojom
@@ -4,13 +4,9 @@
 
 module mojo;
 
+import "network/public/interfaces/http_message.mojom";
 import "network/public/interfaces/network_error.mojom";
 
-struct HTTPHeader {
-  string name;
-  string value;
-};
-
 struct URLRequest {
   // The URL to load.
   string url;
@@ -19,7 +15,7 @@
   string method = "GET";
 
   // Additional HTTP request headers.
-  array<HTTPHeader>? headers;
+  array<HttpHeader>? headers;
 
   // The payload for the request body, represented as a concatenation of data
   // streams. For HTTP requests, the method must be set to "POST" or "PUT".
@@ -59,7 +55,7 @@
   string? status_line;
 
   // The HTTP response headers.
-  array<HTTPHeader>? headers;
+  array<HttpHeader>? headers;
 
   // The MIME type of the response body.
   string? mime_type;
diff --git a/mojo/services/network/url_loader_impl.cc b/mojo/services/network/url_loader_impl.cc
index 5e2108a..464eda9 100644
--- a/mojo/services/network/url_loader_impl.cc
+++ b/mojo/services/network/url_loader_impl.cc
@@ -31,12 +31,12 @@
     response->status_code = headers->response_code();
     response->status_line = headers->GetStatusLine();
 
-    response->headers = Array<HTTPHeaderPtr>::New(0);
+    response->headers = Array<HttpHeaderPtr>::New(0);
     std::vector<String> header_lines;
     void* iter = nullptr;
     std::string name, value;
     while (headers->EnumerateHeaderLines(&iter, &name, &value)) {
-      HTTPHeaderPtr header = HTTPHeader::New();
+      HttpHeaderPtr header = HttpHeader::New();
       header->name = name;
       header->value = value;
       response->headers.push_back(header.Pass());
diff --git a/mojo/shell/local_fetcher.cc b/mojo/shell/local_fetcher.cc
index 4844483..ff7f7d4e 100644
--- a/mojo/shell/local_fetcher.cc
+++ b/mojo/shell/local_fetcher.cc
@@ -53,8 +53,8 @@
   response->body = data_pipe.consumer_handle.Pass();
   int64 file_size;
   if (base::GetFileSize(path_, &file_size)) {
-    response->headers = Array<HTTPHeaderPtr>(1);
-    HTTPHeaderPtr header = HTTPHeader::New();
+    response->headers = Array<HttpHeaderPtr>(1);
+    HttpHeaderPtr header = HttpHeader::New();
     header->name = "Content-Length";
     header->value = base::StringPrintf("%" PRId64, file_size);
     response->headers[0] = header.Pass();
diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_wrap_glibc.cc b/native_client_sdk/src/libraries/nacl_io/kernel_wrap_glibc.cc
index 308a0929..158c52a 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_wrap_glibc.cc
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_wrap_glibc.cc
@@ -175,6 +175,7 @@
   OP(fdatasync);                         \
   OP(lstat);                             \
   OP(link);                              \
+  OP(rename);                            \
   OP(readlink);                          \
   OP(utimes);
 
@@ -348,6 +349,10 @@
   ERRNO_RTN(ki_link(pathname, newpath));
 }
 
+int WRAP(rename)(const char* pathname, const char* newpath) {
+  ERRNO_RTN(ki_rename(pathname, newpath));
+}
+
 int WRAP(readlink)(const char* pathname,
                    char* buf,
                    size_t count,
diff --git a/native_client_sdk/src/libraries/nacl_io/library.dsc b/native_client_sdk/src/libraries/nacl_io/library.dsc
index 5f20abd..3c67053 100644
--- a/native_client_sdk/src/libraries/nacl_io/library.dsc
+++ b/native_client_sdk/src/libraries/nacl_io/library.dsc
@@ -81,7 +81,6 @@
         "syscalls/pipe.c",
         "syscalls/poll.c",
         "syscalls/realpath.c",
-        "syscalls/rename.c",
         "syscalls/select.c",
         "syscalls/sigaction.c",
         "syscalls/signal.c",
diff --git a/native_client_sdk/src/libraries/nacl_io/syscalls/rename.c b/native_client_sdk/src/libraries/nacl_io/syscalls/rename.c
deleted file mode 100644
index 8ad73af..0000000
--- a/native_client_sdk/src/libraries/nacl_io/syscalls/rename.c
+++ /dev/null
@@ -1,10 +0,0 @@
-/* Copyright (c) 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. */
-
-#include "nacl_io/kernel_intercept.h"
-#include "nacl_io/kernel_wrap.h"
-
-int rename(const char* path, const char* newpath) {
-  return ki_rename(path, newpath);
-}
diff --git a/net/BUILD.gn b/net/BUILD.gn
index b4b37887..ef7ed9d 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -839,6 +839,8 @@
       "proxy/mojo_proxy_resolver_factory_impl.h",
       "proxy/mojo_proxy_resolver_impl.cc",
       "proxy/mojo_proxy_resolver_impl.h",
+      "proxy/proxy_resolver_error_observer_mojo.cc",
+      "proxy/proxy_resolver_error_observer_mojo.h",
     ]
 
     deps = [
@@ -1493,6 +1495,7 @@
         "proxy/load_state_change_coalescer_unittest.cc",
         "proxy/mojo_proxy_resolver_factory_impl_unittest.cc",
         "proxy/mojo_proxy_resolver_impl_unittest.cc",
+        "proxy/proxy_resolver_error_observer_mojo_unittest.cc",
         "proxy/proxy_resolver_mojo_unittest.cc",
         "proxy/proxy_service_mojo_unittest.cc",
       ]
diff --git a/net/base/mime_util.cc b/net/base/mime_util.cc
index 7db410b..0d54d65 100644
--- a/net/base/mime_util.cc
+++ b/net/base/mime_util.cc
@@ -15,14 +15,11 @@
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
 #include "net/base/mime_util.h"
 #include "net/base/platform_mime_util.h"
 #include "net/http/http_util.h"
 
-#if defined(OS_ANDROID)
-#include "base/android/build_info.h"
-#endif
-
 using std::string;
 
 namespace net {
@@ -30,26 +27,6 @@
 // Singleton utility class for mime types.
 class MimeUtil : public PlatformMimeUtil {
  public:
-  enum Codec {
-    INVALID_CODEC,
-    PCM,
-    MP3,
-    MPEG2_AAC_LC,
-    MPEG2_AAC_MAIN,
-    MPEG2_AAC_SSR,
-    MPEG4_AAC_LC,
-    MPEG4_AAC_SBR_v1,
-    MPEG4_AAC_SBR_PS_v2,
-    VORBIS,
-    OPUS,
-    H264_BASELINE,
-    H264_MAIN,
-    H264_HIGH,
-    VP8,
-    VP9,
-    THEORA
-  };
-
   bool GetMimeTypeFromExtension(const base::FilePath::StringType& ext,
                                 std::string* mime_type) const;
 
@@ -59,8 +36,6 @@
   bool GetWellKnownMimeTypeFromExtension(const base::FilePath::StringType& ext,
                                          std::string* mime_type) const;
 
-  bool IsSupportedMediaMimeType(const std::string& mime_type) const;
-
   bool MatchesMimeType(const std::string &mime_type_pattern,
                        const std::string &mime_type) const;
 
@@ -70,94 +45,14 @@
 
   bool IsValidTopLevelMimeType(const std::string& type_string) const;
 
-  bool AreSupportedMediaCodecs(const std::vector<std::string>& codecs) const;
-
-  void ParseCodecString(const std::string& codecs,
-                        std::vector<std::string>* codecs_out,
-                        bool strip);
-
-  bool IsStrictMediaMimeType(const std::string& mime_type) const;
-  SupportsType IsSupportedStrictMediaMimeType(
-      const std::string& mime_type,
-      const std::vector<std::string>& codecs) const;
-
-  void RemoveProprietaryMediaTypesAndCodecsForTests();
-
  private:
   friend struct base::DefaultLazyInstanceTraits<MimeUtil>;
 
-  typedef base::hash_set<std::string> MimeMappings;
-
-  typedef base::hash_set<int> CodecSet;
-  typedef std::map<std::string, CodecSet> StrictMappings;
-  struct CodecEntry {
-    CodecEntry() : codec(INVALID_CODEC), is_ambiguous(true) {}
-    CodecEntry(Codec c, bool ambiguous) : codec(c), is_ambiguous(ambiguous) {}
-    Codec codec;
-    bool is_ambiguous;
-  };
-  typedef std::map<std::string, CodecEntry> StringToCodecMappings;
-
   MimeUtil();
 
-  // Returns IsSupported if all codec IDs in |codecs| are unambiguous
-  // and are supported by the platform. MayBeSupported is returned if
-  // at least one codec ID in |codecs| is ambiguous but all the codecs
-  // are supported by the platform. IsNotSupported is returned if at
-  // least one codec ID  is not supported by the platform.
-  SupportsType AreSupportedCodecs(
-      const CodecSet& supported_codecs,
-      const std::vector<std::string>& codecs) const;
-
-  // For faster lookup, keep hash sets.
-  void InitializeMimeTypeMaps();
-
   bool GetMimeTypeFromExtensionHelper(const base::FilePath::StringType& ext,
                                       bool include_platform_types,
                                       std::string* mime_type) const;
-
-  // Converts a codec ID into an Codec enum value and indicates
-  // whether the conversion was ambiguous.
-  // Returns true if this method was able to map |codec_id| to a specific
-  // Codec enum value. |codec| and |is_ambiguous| are only valid if true
-  // is returned. Otherwise their value is undefined after the call.
-  // |is_ambiguous| is true if |codec_id| did not have enough information to
-  // unambiguously determine the proper Codec enum value. If |is_ambiguous|
-  // is true |codec| contains the best guess for the intended Codec enum value.
-  bool StringToCodec(const std::string& codec_id,
-                     Codec* codec,
-                     bool* is_ambiguous) const;
-
-  // Returns true if |codec| is supported by the platform.
-  // Note: This method will return false if the platform supports proprietary
-  // codecs but |allow_proprietary_codecs_| is set to false.
-  bool IsCodecSupported(Codec codec) const;
-
-  // Returns true if |codec| refers to a proprietary codec.
-  bool IsCodecProprietary(Codec codec) const;
-
-  // Returns true and sets |*default_codec| if |mime_type| has a  default codec
-  // associated with it. Returns false otherwise and the value of
-  // |*default_codec| is undefined.
-  bool GetDefaultCodecLowerCase(const std::string& mime_type_lower_case,
-                                Codec* default_codec) const;
-
-  // Returns true if |mime_type_lower_case| has a default codec associated with
-  // it and IsCodecSupported() returns true for that particular codec.
-  bool IsDefaultCodecSupportedLowerCase(
-      const std::string& mime_type_lower_case) const;
-
-  MimeMappings media_map_;
-
-  // A map of mime_types and hash map of the supported codecs for the mime_type.
-  StrictMappings strict_format_map_;
-
-  // Keeps track of whether proprietary codec support should be
-  // advertised to callers.
-  bool allow_proprietary_codecs_;
-
-  // Lookup table for string compare based string -> Codec mappings.
-  StringToCodecMappings string_to_codec_map_;
 };  // class MimeUtil
 
 // This variable is Leaky because we need to access it from WorkerPool threads.
@@ -297,269 +192,7 @@
   return false;
 }
 
-// A list of media types: http://en.wikipedia.org/wiki/Internet_media_type
-// A comprehensive mime type list: http://plugindoc.mozdev.org/winmime.php
-// This set of codecs is supported by all variations of Chromium.
-static const char* const common_media_types[] = {
-  // Ogg.
-  "audio/ogg",
-  "application/ogg",
-#if !defined(OS_ANDROID)  // Android doesn't support Ogg Theora.
-  "video/ogg",
-#endif
-
-  // WebM.
-  "video/webm",
-  "audio/webm",
-
-  // Wav.
-  "audio/wav",
-  "audio/x-wav",
-
-#if defined(OS_ANDROID)
-  // HLS.
-  "application/vnd.apple.mpegurl",
-  "application/x-mpegurl",
-#endif
-};
-
-// List of proprietary types only supported by Google Chrome.
-static const char* const proprietary_media_types[] = {
-  // MPEG-4.
-  "video/mp4",
-  "video/x-m4v",
-  "audio/mp4",
-  "audio/x-m4a",
-
-  // MP3.
-  "audio/mp3",
-  "audio/x-mp3",
-  "audio/mpeg",
-  "audio/aac",
-
-#if defined(ENABLE_MPEG2TS_STREAM_PARSER)
-  // MPEG-2 TS.
-  "video/mp2t",
-#endif
-};
-
-#if defined(OS_ANDROID)
-static bool IsCodecSupportedOnAndroid(MimeUtil::Codec codec) {
-  switch (codec) {
-    case MimeUtil::INVALID_CODEC:
-      return false;
-
-    case MimeUtil::PCM:
-    case MimeUtil::MP3:
-    case MimeUtil::MPEG4_AAC_LC:
-    case MimeUtil::MPEG4_AAC_SBR_v1:
-    case MimeUtil::MPEG4_AAC_SBR_PS_v2:
-    case MimeUtil::H264_BASELINE:
-    case MimeUtil::H264_MAIN:
-    case MimeUtil::H264_HIGH:
-    case MimeUtil::VP8:
-    case MimeUtil::VORBIS:
-      return true;
-
-    case MimeUtil::MPEG2_AAC_LC:
-    case MimeUtil::MPEG2_AAC_MAIN:
-    case MimeUtil::MPEG2_AAC_SSR:
-      // MPEG-2 variants of AAC are not supported on Android.
-      return false;
-
-    case MimeUtil::VP9:
-      // VP9 is supported only in KitKat+ (API Level 19).
-      return base::android::BuildInfo::GetInstance()->sdk_int() >= 19;
-
-    case MimeUtil::OPUS:
-      // Opus is supported only in Lollipop+ (API Level 21).
-      return base::android::BuildInfo::GetInstance()->sdk_int() >= 21;
-
-    case MimeUtil::THEORA:
-      return false;
-  }
-
-  return false;
-}
-#endif
-
-struct MediaFormatStrict {
-  const char* const mime_type;
-  const char* const codecs_list;
-};
-
-// Following is the list of RFC 6381 compliant codecs:
-//   mp4a.66     - MPEG-2 AAC MAIN
-//   mp4a.67     - MPEG-2 AAC LC
-//   mp4a.68     - MPEG-2 AAC SSR
-//   mp4a.69     - MPEG-2 extension to MPEG-1
-//   mp4a.6B     - MPEG-1 audio
-//   mp4a.40.2   - MPEG-4 AAC LC
-//   mp4a.40.02  - MPEG-4 AAC LC (leading 0 in aud-oti for compatibility)
-//   mp4a.40.5   - MPEG-4 HE-AAC v1 (AAC LC + SBR)
-//   mp4a.40.05  - MPEG-4 HE-AAC v1 (AAC LC + SBR) (leading 0 in aud-oti for
-//                 compatibility)
-//   mp4a.40.29  - MPEG-4 HE-AAC v2 (AAC LC + SBR + PS)
-//
-//   avc1.42E0xx - H.264 Baseline
-//   avc1.4D40xx - H.264 Main
-//   avc1.6400xx - H.264 High
-static const char kMP4AudioCodecsExpression[] =
-    "mp4a.66,mp4a.67,mp4a.68,mp4a.69,mp4a.6B,mp4a.40.2,mp4a.40.02,mp4a.40.5,"
-    "mp4a.40.05,mp4a.40.29";
-static const char kMP4VideoCodecsExpression[] =
-    // This is not a complete list of supported avc1 codecs. It is simply used
-    // to register support for the corresponding Codec enum. Instead of using
-    // strings in these three arrays, we should use the Codec enum values.
-    // This will avoid confusion and unnecessary parsing at runtime.
-    // kUnambiguousCodecStringMap/kAmbiguousCodecStringMap should be the only
-    // mapping from strings to codecs. See crbug.com/461009.
-    "avc1.42E00A,avc1.4D400A,avc1.64000A,"
-    "mp4a.66,mp4a.67,mp4a.68,mp4a.69,mp4a.6B,mp4a.40.2,mp4a.40.02,mp4a.40.5,"
-    "mp4a.40.05,mp4a.40.29";
-
-// These containers are also included in
-// common_media_types/proprietary_media_types. See crbug.com/461012.
-static const MediaFormatStrict format_codec_mappings[] = {
-    {"video/webm", "opus,vorbis,vp8,vp8.0,vp9,vp9.0"},
-    {"audio/webm", "opus,vorbis"},
-    {"audio/wav", "1"},
-    {"audio/x-wav", "1"},
-// Android does not support Opus in Ogg container.
-#if defined(OS_ANDROID)
-    {"video/ogg", "theora,vorbis"},
-    {"audio/ogg", "vorbis"},
-    {"application/ogg", "theora,vorbis"},
-#else
-    {"video/ogg", "opus,theora,vorbis"},
-    {"audio/ogg", "opus,vorbis"},
-    {"application/ogg", "opus,theora,vorbis"},
-#endif
-    {"audio/mpeg", "mp3"},
-    {"audio/mp3", ""},
-    {"audio/x-mp3", ""},
-    {"audio/mp4", kMP4AudioCodecsExpression},
-    {"audio/x-m4a", kMP4AudioCodecsExpression},
-    {"video/mp4", kMP4VideoCodecsExpression},
-    {"video/x-m4v", kMP4VideoCodecsExpression},
-    {"application/x-mpegurl", kMP4VideoCodecsExpression},
-    {"application/vnd.apple.mpegurl", kMP4VideoCodecsExpression}};
-
-struct CodecIDMappings {
-  const char* const codec_id;
-  MimeUtil::Codec codec;
-};
-
-// List of codec IDs that provide enough information to determine the
-// codec and profile being requested.
-//
-// The "mp4a" strings come from RFC 6381.
-static const CodecIDMappings kUnambiguousCodecStringMap[] = {
-    {"1", MimeUtil::PCM},  // We only allow this for WAV so it isn't ambiguous.
-    // avc1/avc3.XXXXXX may be unambiguous; handled by ParseH264CodecID().
-    {"mp3", MimeUtil::MP3},
-    {"mp4a.66", MimeUtil::MPEG2_AAC_MAIN},
-    {"mp4a.67", MimeUtil::MPEG2_AAC_LC},
-    {"mp4a.68", MimeUtil::MPEG2_AAC_SSR},
-    {"mp4a.69", MimeUtil::MP3},
-    {"mp4a.6B", MimeUtil::MP3},
-    {"mp4a.40.2", MimeUtil::MPEG4_AAC_LC},
-    {"mp4a.40.02", MimeUtil::MPEG4_AAC_LC},
-    {"mp4a.40.5", MimeUtil::MPEG4_AAC_SBR_v1},
-    {"mp4a.40.05", MimeUtil::MPEG4_AAC_SBR_v1},
-    {"mp4a.40.29", MimeUtil::MPEG4_AAC_SBR_PS_v2},
-    {"vorbis", MimeUtil::VORBIS},
-    {"opus", MimeUtil::OPUS},
-    {"vp8", MimeUtil::VP8},
-    {"vp8.0", MimeUtil::VP8},
-    {"vp9", MimeUtil::VP9},
-    {"vp9.0", MimeUtil::VP9},
-    {"theora", MimeUtil::THEORA}};
-
-// List of codec IDs that are ambiguous and don't provide
-// enough information to determine the codec and profile.
-// The codec in these entries indicate the codec and profile
-// we assume the user is trying to indicate.
-static const CodecIDMappings kAmbiguousCodecStringMap[] = {
-    {"mp4a.40", MimeUtil::MPEG4_AAC_LC},
-    {"avc1", MimeUtil::H264_BASELINE},
-    {"avc3", MimeUtil::H264_BASELINE},
-    // avc1/avc3.XXXXXX may be ambiguous; handled by ParseH264CodecID().
-};
-
-MimeUtil::MimeUtil() : allow_proprietary_codecs_(false) {
-  InitializeMimeTypeMaps();
-}
-
-SupportsType MimeUtil::AreSupportedCodecs(
-    const CodecSet& supported_codecs,
-    const std::vector<std::string>& codecs) const {
-  DCHECK(!supported_codecs.empty());
-  DCHECK(!codecs.empty());
-
-  SupportsType result = IsSupported;
-  for (size_t i = 0; i < codecs.size(); ++i) {
-    bool is_ambiguous = true;
-    Codec codec = INVALID_CODEC;
-    if (!StringToCodec(codecs[i], &codec, &is_ambiguous))
-      return IsNotSupported;
-
-    if (!IsCodecSupported(codec) ||
-        supported_codecs.find(codec) == supported_codecs.end()) {
-      return IsNotSupported;
-    }
-
-    if (is_ambiguous)
-      result = MayBeSupported;
-  }
-
-  return result;
-}
-
-void MimeUtil::InitializeMimeTypeMaps() {
-  // Initialize the supported media types.
-  for (size_t i = 0; i < arraysize(common_media_types); ++i)
-    media_map_.insert(common_media_types[i]);
-#if defined(USE_PROPRIETARY_CODECS)
-  allow_proprietary_codecs_ = true;
-
-  for (size_t i = 0; i < arraysize(proprietary_media_types); ++i)
-    media_map_.insert(proprietary_media_types[i]);
-#endif
-
-  for (size_t i = 0; i < arraysize(kUnambiguousCodecStringMap); ++i) {
-    string_to_codec_map_[kUnambiguousCodecStringMap[i].codec_id] =
-        CodecEntry(kUnambiguousCodecStringMap[i].codec, false);
-  }
-
-  for (size_t i = 0; i < arraysize(kAmbiguousCodecStringMap); ++i) {
-    string_to_codec_map_[kAmbiguousCodecStringMap[i].codec_id] =
-        CodecEntry(kAmbiguousCodecStringMap[i].codec, true);
-  }
-
-  // Initialize the strict supported media types.
-  for (size_t i = 0; i < arraysize(format_codec_mappings); ++i) {
-    std::vector<std::string> mime_type_codecs;
-    ParseCodecString(format_codec_mappings[i].codecs_list,
-                     &mime_type_codecs,
-                     false);
-
-    CodecSet codecs;
-    for (size_t j = 0; j < mime_type_codecs.size(); ++j) {
-      Codec codec = INVALID_CODEC;
-      bool is_ambiguous = true;
-      CHECK(StringToCodec(mime_type_codecs[j], &codec, &is_ambiguous));
-      DCHECK(!is_ambiguous);
-      codecs.insert(codec);
-    }
-
-    strict_format_map_[format_codec_mappings[i].mime_type] = codecs;
-  }
-}
-
-bool MimeUtil::IsSupportedMediaMimeType(const std::string& mime_type) const {
-  return media_map_.find(base::StringToLowerASCII(mime_type)) !=
-         media_map_.end();
+MimeUtil::MimeUtil() {
 }
 
 // Tests for MIME parameter equality. Each parameter in the |mime_type_pattern|
@@ -703,241 +336,6 @@
   return type_string.size() > 2 && StartsWithASCII(type_string, "x-", false);
 }
 
-bool MimeUtil::AreSupportedMediaCodecs(
-    const std::vector<std::string>& codecs) const {
-  for (size_t i = 0; i < codecs.size(); ++i) {
-    Codec codec = INVALID_CODEC;
-    bool is_ambiguous = true;
-    if (!StringToCodec(codecs[i], &codec, &is_ambiguous) ||
-        !IsCodecSupported(codec)) {
-      return false;
-    }
-  }
-  return true;
-}
-
-void MimeUtil::ParseCodecString(const std::string& codecs,
-                                std::vector<std::string>* codecs_out,
-                                bool strip) {
-  std::string no_quote_codecs;
-  base::TrimString(codecs, "\"", &no_quote_codecs);
-  base::SplitString(no_quote_codecs, ',', codecs_out);
-
-  if (!strip)
-    return;
-
-  // Strip everything past the first '.'
-  for (std::vector<std::string>::iterator it = codecs_out->begin();
-       it != codecs_out->end();
-       ++it) {
-    size_t found = it->find_first_of('.');
-    if (found != std::string::npos)
-      it->resize(found);
-  }
-}
-
-bool MimeUtil::IsStrictMediaMimeType(const std::string& mime_type) const {
-  return strict_format_map_.find(base::StringToLowerASCII(mime_type)) !=
-         strict_format_map_.end();
-}
-
-SupportsType MimeUtil::IsSupportedStrictMediaMimeType(
-    const std::string& mime_type,
-    const std::vector<std::string>& codecs) const {
-  const std::string mime_type_lower_case = base::StringToLowerASCII(mime_type);
-  StrictMappings::const_iterator it_strict_map =
-      strict_format_map_.find(mime_type_lower_case);
-  if (it_strict_map == strict_format_map_.end())
-    return codecs.empty() ? MayBeSupported : IsNotSupported;
-
-  if (it_strict_map->second.empty()) {
-    // We get here if the mimetype does not expect a codecs parameter.
-    return (codecs.empty() &&
-            IsDefaultCodecSupportedLowerCase(mime_type_lower_case))
-               ? IsSupported
-               : IsNotSupported;
-  }
-
-  if (codecs.empty()) {
-    // We get here if the mimetype expects to get a codecs parameter,
-    // but didn't get one. If |mime_type_lower_case| does not have a default
-    // codec the best we can do is say "maybe" because we don't have enough
-    // information.
-    Codec default_codec = INVALID_CODEC;
-    if (!GetDefaultCodecLowerCase(mime_type_lower_case, &default_codec))
-      return MayBeSupported;
-
-    return IsCodecSupported(default_codec) ? IsSupported : IsNotSupported;
-  }
-
-  return AreSupportedCodecs(it_strict_map->second, codecs);
-}
-
-void MimeUtil::RemoveProprietaryMediaTypesAndCodecsForTests() {
-  for (size_t i = 0; i < arraysize(proprietary_media_types); ++i)
-    media_map_.erase(proprietary_media_types[i]);
-  allow_proprietary_codecs_ = false;
-}
-
-// Returns true iff |profile_str| conforms to hex string "42y0", where y is one
-// of [8..F]. Requiring constraint_set0_flag be set and profile_idc be 0x42 is
-// taken from ISO-14496-10 7.3.2.1, 7.4.2.1, and Annex A.2.1.
-//
-// |profile_str| is the first four characters of the H.264 suffix string
-// (ignoring the last 2 characters of the full 6 character suffix that are
-// level_idc). From ISO-14496-10 7.3.2.1, it consists of:
-// 8 bits: profile_idc: required to be 0x42 here.
-// 1 bit: constraint_set0_flag : required to be true here.
-// 1 bit: constraint_set1_flag : ignored here.
-// 1 bit: constraint_set2_flag : ignored here.
-// 1 bit: constraint_set3_flag : ignored here.
-// 4 bits: reserved : required to be 0 here.
-//
-// The spec indicates other ways, not implemented here, that a |profile_str|
-// can indicate a baseline conforming decoder is sufficient for decode in Annex
-// A.2.1: "[profile_idc not necessarily 0x42] with constraint_set0_flag set and
-// in which level_idc and constraint_set3_flag represent a level less than or
-// equal to the specified level."
-static bool IsValidH264BaselineProfile(const std::string& profile_str) {
-  uint32 constraint_set_bits;
-  if (profile_str.size() != 4 ||
-      profile_str[0] != '4' ||
-      profile_str[1] != '2' ||
-      profile_str[3] != '0' ||
-      !base::HexStringToUInt(base::StringPiece(profile_str.c_str() + 2, 1),
-                             &constraint_set_bits)) {
-    return false;
-  }
-
-  return constraint_set_bits >= 8;
-}
-
-static bool IsValidH264Level(const std::string& level_str) {
-  uint32 level;
-  if (level_str.size() != 2 || !base::HexStringToUInt(level_str, &level))
-    return false;
-
-  // Valid levels taken from Table A-1 in ISO-14496-10.
-  // Essentially |level_str| is toHex(10 * level).
-  return ((level >= 10 && level <= 13) ||
-          (level >= 20 && level <= 22) ||
-          (level >= 30 && level <= 32) ||
-          (level >= 40 && level <= 42) ||
-          (level >= 50 && level <= 51));
-}
-
-// Handle parsing H.264 codec IDs as outlined in RFC 6381 and ISO-14496-10.
-//   avc1.42y0xx, y >= 8 - H.264 Baseline
-//   avc1.4D40xx         - H.264 Main
-//   avc1.6400xx         - H.264 High
-//
-//   avc1.xxxxxx & avc3.xxxxxx are considered ambiguous forms that are trying to
-//   signal H.264 Baseline. For example, the idc_level, profile_idc and
-//   constraint_set3_flag pieces may explicitly require decoder to conform to
-//   baseline profile at the specified level (see Annex A and constraint_set0 in
-//   ISO-14496-10).
-static bool ParseH264CodecID(const std::string& codec_id,
-                             MimeUtil::Codec* codec,
-                             bool* is_ambiguous) {
-  // Make sure we have avc1.xxxxxx or avc3.xxxxxx
-  if (codec_id.size() != 11 ||
-      (!StartsWithASCII(codec_id, "avc1.", true) &&
-       !StartsWithASCII(codec_id, "avc3.", true))) {
-    return false;
-  }
-
-  std::string profile = StringToUpperASCII(codec_id.substr(5, 4));
-  if (IsValidH264BaselineProfile(profile)) {
-    *codec = MimeUtil::H264_BASELINE;
-  } else if (profile == "4D40") {
-    *codec = MimeUtil::H264_MAIN;
-  } else if (profile == "6400") {
-    *codec = MimeUtil::H264_HIGH;
-  } else {
-    *codec = MimeUtil::H264_BASELINE;
-    *is_ambiguous = true;
-    return true;
-  }
-
-  *is_ambiguous = !IsValidH264Level(StringToUpperASCII(codec_id.substr(9)));
-  return true;
-}
-
-bool MimeUtil::StringToCodec(const std::string& codec_id,
-                             Codec* codec,
-                             bool* is_ambiguous) const {
-  StringToCodecMappings::const_iterator itr =
-      string_to_codec_map_.find(codec_id);
-  if (itr != string_to_codec_map_.end()) {
-    *codec = itr->second.codec;
-    *is_ambiguous = itr->second.is_ambiguous;
-    return true;
-  }
-
-  // If |codec_id| is not in |string_to_codec_map_|, then we assume that it is
-  // an H.264 codec ID because currently those are the only ones that can't be
-  // stored in the |string_to_codec_map_| and require parsing.
-  return ParseH264CodecID(codec_id, codec, is_ambiguous);
-}
-
-bool MimeUtil::IsCodecSupported(Codec codec) const {
-  DCHECK_NE(codec, INVALID_CODEC);
-
-#if defined(OS_ANDROID)
-  if (!IsCodecSupportedOnAndroid(codec))
-    return false;
-#endif
-
-  return allow_proprietary_codecs_ || !IsCodecProprietary(codec);
-}
-
-bool MimeUtil::IsCodecProprietary(Codec codec) const {
-  switch (codec) {
-    case INVALID_CODEC:
-    case MP3:
-    case MPEG2_AAC_LC:
-    case MPEG2_AAC_MAIN:
-    case MPEG2_AAC_SSR:
-    case MPEG4_AAC_LC:
-    case MPEG4_AAC_SBR_v1:
-    case MPEG4_AAC_SBR_PS_v2:
-    case H264_BASELINE:
-    case H264_MAIN:
-    case H264_HIGH:
-      return true;
-
-    case PCM:
-    case VORBIS:
-    case OPUS:
-    case VP8:
-    case VP9:
-    case THEORA:
-      return false;
-  }
-
-  return true;
-}
-
-bool MimeUtil::GetDefaultCodecLowerCase(const std::string& mime_type_lower_case,
-                                        Codec* default_codec) const {
-  if (mime_type_lower_case == "audio/mpeg" ||
-      mime_type_lower_case == "audio/mp3" ||
-      mime_type_lower_case == "audio/x-mp3") {
-    *default_codec = MimeUtil::MP3;
-    return true;
-  }
-
-  return false;
-}
-
-bool MimeUtil::IsDefaultCodecSupportedLowerCase(
-    const std::string& mime_type_lower_case) const {
-  Codec default_codec = Codec::INVALID_CODEC;
-  if (!GetDefaultCodecLowerCase(mime_type_lower_case, &default_codec))
-    return false;
-  return IsCodecSupported(default_codec);
-}
-
 //----------------------------------------------------------------------------
 // Wrappers for the singleton
 //----------------------------------------------------------------------------
@@ -963,10 +361,6 @@
                                                             extension);
 }
 
-bool IsSupportedMediaMimeType(const std::string& mime_type) {
-  return g_mime_util.Get().IsSupportedMediaMimeType(mime_type);
-}
-
 bool MatchesMimeType(const std::string& mime_type_pattern,
                      const std::string& mime_type) {
   return g_mime_util.Get().MatchesMimeType(mime_type_pattern, mime_type);
@@ -983,26 +377,6 @@
   return g_mime_util.Get().IsValidTopLevelMimeType(type_string);
 }
 
-bool AreSupportedMediaCodecs(const std::vector<std::string>& codecs) {
-  return g_mime_util.Get().AreSupportedMediaCodecs(codecs);
-}
-
-bool IsStrictMediaMimeType(const std::string& mime_type) {
-  return g_mime_util.Get().IsStrictMediaMimeType(mime_type);
-}
-
-SupportsType IsSupportedStrictMediaMimeType(
-    const std::string& mime_type,
-    const std::vector<std::string>& codecs) {
-  return g_mime_util.Get().IsSupportedStrictMediaMimeType(mime_type, codecs);
-}
-
-void ParseCodecString(const std::string& codecs,
-                      std::vector<std::string>* codecs_out,
-                      const bool strip) {
-  g_mime_util.Get().ParseCodecString(codecs, codecs_out, strip);
-}
-
 namespace {
 
 // From http://www.w3schools.com/media/media_mimeref.asp and
@@ -1185,10 +559,6 @@
   HashSetToVector(&unique_extensions, extensions);
 }
 
-void RemoveProprietaryMediaTypesAndCodecsForTests() {
-  g_mime_util.Get().RemoveProprietaryMediaTypesAndCodecsForTests();
-}
-
 void AddMultipartValueForUpload(const std::string& value_name,
                                 const std::string& value,
                                 const std::string& mime_boundary,
diff --git a/net/base/mime_util.h b/net/base/mime_util.h
index 80f440e..d4335a91 100644
--- a/net/base/mime_util.h
+++ b/net/base/mime_util.h
@@ -50,9 +50,6 @@
     const std::string& mime_type,
     base::FilePath::StringType* extension);
 
-// Check to see if a particular MIME type is in our list.
-NET_EXPORT bool IsSupportedMediaMimeType(const std::string& mime_type);
-
 // Returns true if this the mime_type_pattern matches a given mime-type.
 // Checks for absolute matching and wildcards. MIME types are case insensitive.
 NET_EXPORT bool MatchesMimeType(const std::string& mime_type_pattern,
@@ -81,53 +78,6 @@
 // this method.
 NET_EXPORT bool IsValidTopLevelMimeType(const std::string& type_string);
 
-// Returns true if and only if all codecs are supported, false otherwise.
-NET_EXPORT bool AreSupportedMediaCodecs(const std::vector<std::string>& codecs);
-
-// Parses a codec string, populating |codecs_out| with the prefix of each codec
-// in the string |codecs_in|. For example, passed "aaa.b.c,dd.eee", if
-// |strip| == true |codecs_out| will contain {"aaa", "dd"}, if |strip| == false
-// |codecs_out| will contain {"aaa.b.c", "dd.eee"}.
-// See http://www.ietf.org/rfc/rfc4281.txt.
-NET_EXPORT void ParseCodecString(const std::string& codecs,
-                                 std::vector<std::string>* codecs_out,
-                                 bool strip);
-
-// Check to see if a particular MIME type is in our list which only supports a
-// certain subset of codecs.
-NET_EXPORT bool IsStrictMediaMimeType(const std::string& mime_type);
-
-// Indicates that the MIME type and (possible codec string) are supported by the
-// underlying platform.
-enum SupportsType {
-  // The underlying platform is known not to support the given MIME type and
-  // codec combination.
-  IsNotSupported,
-
-  // The underlying platform is known to support the given MIME type and codec
-  // combination.
-  IsSupported,
-
-  // The underlying platform is unsure whether the given MIME type and codec
-  // combination can be rendered or not before actually trying to play it.
-  MayBeSupported
-};
-
-// Checks the |mime_type| and |codecs| against the MIME types known to support
-// only a particular subset of codecs.
-// * Returns IsSupported if the |mime_type| is supported and all the codecs
-//   within the |codecs| are supported for the |mime_type|.
-// * Returns MayBeSupported if the |mime_type| is supported and is known to
-//   support only a subset of codecs, but |codecs| was empty. Also returned if
-//   all the codecs in |codecs| are supported, but additional codec parameters
-//   were supplied (such as profile) for which the support cannot be decided.
-// * Returns IsNotSupported if either the |mime_type| is not supported or the
-//   |mime_type| is supported but at least one of the codecs within |codecs| is
-//   not supported for the |mime_type|.
-NET_EXPORT SupportsType IsSupportedStrictMediaMimeType(
-    const std::string& mime_type,
-    const std::vector<std::string>& codecs);
-
 // Get the extensions associated with the given mime type. There could be
 // multiple extensions for a given mime type, like "html,htm" for "text/html",
 // or "txt,text,html,..." for "text/*".
@@ -137,12 +87,6 @@
     const std::string& mime_type,
     std::vector<base::FilePath::StringType>* extensions);
 
-// Test only method that removes proprietary media types and codecs from the
-// list of supported MIME types and codecs. These types and codecs must be
-// removed to ensure consistent layout test results across all Chromium
-// variations.
-NET_EXPORT void RemoveProprietaryMediaTypesAndCodecsForTests();
-
 // A list of supported certificate-related mime types.
 //
 // A Java counterpart will be generated for this enum.
diff --git a/net/base/mime_util_unittest.cc b/net/base/mime_util_unittest.cc
index dca622f..8a0d15d 100644
--- a/net/base/mime_util_unittest.cc
+++ b/net/base/mime_util_unittest.cc
@@ -5,13 +5,10 @@
 #include "base/basictypes.h"
 #include "base/strings/string_split.h"
 #include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
 #include "net/base/mime_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-#if defined(OS_ANDROID)
-#include "base/android/build_info.h"
-#endif
-
 namespace net {
 
 TEST(MimeUtilTest, ExtensionTest) {
@@ -69,45 +66,6 @@
   }
 }
 
-TEST(MimeUtilTest, LookupTypes) {
-#if defined(OS_ANDROID)
-  EXPECT_TRUE(IsSupportedMediaMimeType("application/vnd.apple.mpegurl"));
-  EXPECT_TRUE(IsSupportedMediaMimeType("application/x-mpegurl"));
-  EXPECT_TRUE(IsSupportedMediaMimeType("Application/X-MPEGURL"));
-#endif
-}
-
-TEST(MimeUtilTest, StrictMediaMimeType) {
-  EXPECT_TRUE(IsStrictMediaMimeType("video/webm"));
-  EXPECT_TRUE(IsStrictMediaMimeType("Video/WEBM"));
-  EXPECT_TRUE(IsStrictMediaMimeType("audio/webm"));
-
-  EXPECT_TRUE(IsStrictMediaMimeType("audio/wav"));
-  EXPECT_TRUE(IsStrictMediaMimeType("audio/x-wav"));
-
-  EXPECT_TRUE(IsStrictMediaMimeType("video/ogg"));
-  EXPECT_TRUE(IsStrictMediaMimeType("audio/ogg"));
-  EXPECT_TRUE(IsStrictMediaMimeType("application/ogg"));
-
-  EXPECT_TRUE(IsStrictMediaMimeType("audio/mpeg"));
-  EXPECT_TRUE(IsStrictMediaMimeType("audio/mp3"));
-  EXPECT_TRUE(IsStrictMediaMimeType("audio/x-mp3"));
-
-  EXPECT_TRUE(IsStrictMediaMimeType("video/mp4"));
-  EXPECT_TRUE(IsStrictMediaMimeType("video/x-m4v"));
-  EXPECT_TRUE(IsStrictMediaMimeType("audio/mp4"));
-  EXPECT_TRUE(IsStrictMediaMimeType("audio/x-m4a"));
-
-  EXPECT_TRUE(IsStrictMediaMimeType("application/x-mpegurl"));
-  EXPECT_TRUE(IsStrictMediaMimeType("application/vnd.apple.mpegurl"));
-
-  EXPECT_FALSE(IsStrictMediaMimeType("video/unknown"));
-  EXPECT_FALSE(IsStrictMediaMimeType("Video/UNKNOWN"));
-  EXPECT_FALSE(IsStrictMediaMimeType("audio/unknown"));
-  EXPECT_FALSE(IsStrictMediaMimeType("application/unknown"));
-  EXPECT_FALSE(IsStrictMediaMimeType("unknown/unknown"));
-}
-
 TEST(MimeUtilTest, MatchesMimeType) {
   // MIME types are case insensitive.
   EXPECT_TRUE(MatchesMimeType("VIDEO/*", "video/x-mpeg"));
@@ -187,104 +145,6 @@
   EXPECT_TRUE(MatchesMimeType("ab/*cd", "ab/xxxcd"));
 }
 
-TEST(MimeUtilTest, CommonMediaMimeType) {
-#if defined(OS_ANDROID)
-  bool HLSSupported;
-  if (base::android::BuildInfo::GetInstance()->sdk_int() < 14)
-    HLSSupported = false;
-  else
-    HLSSupported = true;
-#endif
-
-  EXPECT_TRUE(IsSupportedMediaMimeType("audio/webm"));
-  EXPECT_TRUE(IsSupportedMediaMimeType("video/webm"));
-
-  EXPECT_TRUE(IsSupportedMediaMimeType("audio/wav"));
-  EXPECT_TRUE(IsSupportedMediaMimeType("audio/x-wav"));
-
-  EXPECT_TRUE(IsSupportedMediaMimeType("audio/ogg"));
-  EXPECT_TRUE(IsSupportedMediaMimeType("application/ogg"));
-#if defined(OS_ANDROID)
-  EXPECT_FALSE(IsSupportedMediaMimeType("video/ogg"));
-  EXPECT_EQ(HLSSupported, IsSupportedMediaMimeType("application/x-mpegurl"));
-  EXPECT_EQ(HLSSupported,
-            IsSupportedMediaMimeType("application/vnd.apple.mpegurl"));
-#else
-  EXPECT_TRUE(IsSupportedMediaMimeType("video/ogg"));
-  EXPECT_FALSE(IsSupportedMediaMimeType("application/x-mpegurl"));
-  EXPECT_FALSE(IsSupportedMediaMimeType("application/vnd.apple.mpegurl"));
-#endif  // OS_ANDROID
-
-#if defined(USE_PROPRIETARY_CODECS)
-  EXPECT_TRUE(IsSupportedMediaMimeType("audio/mp4"));
-  EXPECT_TRUE(IsSupportedMediaMimeType("audio/x-m4a"));
-  EXPECT_TRUE(IsSupportedMediaMimeType("video/mp4"));
-  EXPECT_TRUE(IsSupportedMediaMimeType("video/x-m4v"));
-
-  EXPECT_TRUE(IsSupportedMediaMimeType("audio/mp3"));
-  EXPECT_TRUE(IsSupportedMediaMimeType("audio/x-mp3"));
-  EXPECT_TRUE(IsSupportedMediaMimeType("audio/mpeg"));
-  EXPECT_TRUE(IsSupportedMediaMimeType("audio/aac"));
-
-#if defined(ENABLE_MPEG2TS_STREAM_PARSER)
-  EXPECT_TRUE(IsSupportedMediaMimeType("video/mp2t"));
-#else
-  EXPECT_FALSE(IsSupportedMediaMimeType("video/mp2t"));
-#endif
-#else
-  EXPECT_FALSE(IsSupportedMediaMimeType("audio/mp4"));
-  EXPECT_FALSE(IsSupportedMediaMimeType("audio/x-m4a"));
-  EXPECT_FALSE(IsSupportedMediaMimeType("video/mp4"));
-  EXPECT_FALSE(IsSupportedMediaMimeType("video/x-m4v"));
-
-  EXPECT_FALSE(IsSupportedMediaMimeType("audio/mp3"));
-  EXPECT_FALSE(IsSupportedMediaMimeType("audio/x-mp3"));
-  EXPECT_FALSE(IsSupportedMediaMimeType("audio/mpeg"));
-  EXPECT_FALSE(IsSupportedMediaMimeType("audio/aac"));
-#endif  // USE_PROPRIETARY_CODECS
-  EXPECT_FALSE(IsSupportedMediaMimeType("video/mp3"));
-
-  EXPECT_FALSE(IsSupportedMediaMimeType("video/unknown"));
-  EXPECT_FALSE(IsSupportedMediaMimeType("audio/unknown"));
-  EXPECT_FALSE(IsSupportedMediaMimeType("unknown/unknown"));
-}
-
-// Note: codecs should only be a list of 2 or fewer; hence the restriction of
-// results' length to 2.
-TEST(MimeUtilTest, ParseCodecString) {
-  const struct {
-    const char* const original;
-    size_t expected_size;
-    const char* const results[2];
-  } tests[] = {
-    { "\"bogus\"",                  1, { "bogus" }            },
-    { "0",                          1, { "0" }                },
-    { "avc1.42E01E, mp4a.40.2",     2, { "avc1",   "mp4a" }   },
-    { "\"mp4v.20.240, mp4a.40.2\"", 2, { "mp4v",   "mp4a" }   },
-    { "mp4v.20.8, samr",            2, { "mp4v",   "samr" }   },
-    { "\"theora, vorbis\"",         2, { "theora", "vorbis" } },
-    { "",                           0, { }                    },
-    { "\"\"",                       0, { }                    },
-    { "\"   \"",                    0, { }                    },
-    { ",",                          2, { "", "" }             },
-  };
-
-  for (size_t i = 0; i < arraysize(tests); ++i) {
-    std::vector<std::string> codecs_out;
-    ParseCodecString(tests[i].original, &codecs_out, true);
-    ASSERT_EQ(tests[i].expected_size, codecs_out.size());
-    for (size_t j = 0; j < tests[i].expected_size; ++j)
-      EXPECT_EQ(tests[i].results[j], codecs_out[j]);
-  }
-
-  // Test without stripping the codec type.
-  std::vector<std::string> codecs_out;
-  ParseCodecString("avc1.42E01E, mp4a.40.2", &codecs_out, false);
-  ASSERT_EQ(2u, codecs_out.size());
-  EXPECT_EQ("avc1.42E01E", codecs_out[0]);
-  EXPECT_EQ("mp4a.40.2", codecs_out[1]);
-}
-
 TEST(MimeUtilTest, TestParseMimeTypeWithoutParameter) {
   std::string nonAscii("application/nonutf8");
   EXPECT_TRUE(ParseMimeTypeWithoutParameter(nonAscii, NULL, NULL));
diff --git a/net/data/proxy_resolver_v8_tracing_unittest/error_on_load.js b/net/data/proxy_resolver_v8_tracing_unittest/error_on_load.js
new file mode 100644
index 0000000..2379bbf
--- /dev/null
+++ b/net/data/proxy_resolver_v8_tracing_unittest/error_on_load.js
@@ -0,0 +1,11 @@
+// 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.
+
+alert('Prepare to DIE!');
+var x = null;
+return x.split('-');  // Throws exception.
+
+function FindProxyForURL(url, host) {
+  return "PROXY i-approve-this-message:42";
+}
diff --git a/net/dns/dns_transaction_unittest.cc b/net/dns/dns_transaction_unittest.cc
index 2693a5ca..800e394 100644
--- a/net/dns/dns_transaction_unittest.cc
+++ b/net/dns/dns_transaction_unittest.cc
@@ -46,12 +46,12 @@
       *length = base::HostToNet16(query_->io_buffer()->size());
       writes_.push_back(MockWrite(mode,
                                   reinterpret_cast<const char*>(length.get()),
-                                  sizeof(uint16)));
+                                  sizeof(uint16), num_reads_and_writes()));
       lengths_.push_back(length.release());
     }
-    writes_.push_back(MockWrite(mode,
-                                query_->io_buffer()->data(),
-                                query_->io_buffer()->size()));
+    writes_.push_back(MockWrite(mode, query_->io_buffer()->data(),
+                                query_->io_buffer()->size(),
+                                num_reads_and_writes()));
   }
   ~DnsSocketData() {}
 
@@ -66,12 +66,12 @@
       *length = base::HostToNet16(tcp_length);
       reads_.push_back(MockRead(mode,
                                 reinterpret_cast<const char*>(length.get()),
-                                sizeof(uint16)));
+                                sizeof(uint16), num_reads_and_writes()));
       lengths_.push_back(length.release());
     }
-    reads_.push_back(MockRead(mode,
-                              response->io_buffer()->data(),
-                              response->io_buffer()->size()));
+    reads_.push_back(MockRead(mode, response->io_buffer()->data(),
+                              response->io_buffer()->size(),
+                              num_reads_and_writes()));
     responses_.push_back(response.release());
   }
 
@@ -102,19 +102,20 @@
 
   // Add error response.
   void AddReadError(int error, IoMode mode) {
-    reads_.push_back(MockRead(mode, error));
+    reads_.push_back(MockRead(mode, error, num_reads_and_writes()));
   }
 
   // Build, if needed, and return the SocketDataProvider. No new responses
   // should be added afterwards.
-  SocketDataProvider* GetProvider() {
+  SequencedSocketData* GetProvider() {
     if (provider_.get())
       return provider_.get();
     // Terminate the reads with ERR_IO_PENDING to prevent overrun and default to
     // timeout.
-    reads_.push_back(MockRead(ASYNC, ERR_IO_PENDING));
-    provider_.reset(new DelayedSocketData(1, &reads_[0], reads_.size(),
-                                          &writes_[0], writes_.size()));
+    reads_.push_back(
+        MockRead(ASYNC, ERR_IO_PENDING, writes_.size() + reads_.size()));
+    provider_.reset(new SequencedSocketData(&reads_[0], reads_.size(),
+                                            &writes_[0], writes_.size()));
     if (use_tcp_) {
       provider_->set_connect_data(MockConnect(reads_[0].mode, OK));
     }
@@ -125,20 +126,16 @@
     return query_->id();
   }
 
-  // Returns true if the expected query was written to the socket.
-  bool was_written() const {
-    CHECK(provider_.get());
-    return provider_->write_index() > 0;
-  }
-
  private:
+  size_t num_reads_and_writes() const { return reads_.size() + writes_.size(); }
+
   scoped_ptr<DnsQuery> query_;
   bool use_tcp_;
   ScopedVector<uint16> lengths_;
   ScopedVector<DnsResponse> responses_;
   std::vector<MockWrite> writes_;
   std::vector<MockRead> reads_;
-  scoped_ptr<DelayedSocketData> provider_;
+  scoped_ptr<SequencedSocketData> provider_;
 
   DISALLOW_COPY_AND_ASSIGN(DnsSocketData);
 };
@@ -454,7 +451,7 @@
   void TearDown() override {
     // Check that all socket data was at least written to.
     for (size_t i = 0; i < socket_data_.size(); ++i) {
-      EXPECT_TRUE(socket_data_[i]->was_written()) << i;
+      EXPECT_TRUE(socket_data_[i]->GetProvider()->AllWriteDataConsumed()) << i;
     }
   }
 
@@ -517,6 +514,11 @@
   helper1.StartTransaction(transaction_factory_.get());
 
   helper0.Cancel();
+  // Since the transaction has been cancelled, the assocaited socket has been
+  // destroyed, so make sure the data provide does not attempt to callback
+  // to the socket.
+  // TODO(rch): Make the SocketDataProvider and MockSocket do this by default.
+  socket_data_[0]->GetProvider()->set_socket(nullptr);
 
   base::MessageLoop::current()->RunUntilIdle();
 
diff --git a/net/extras/sqlite/sqlite_persistent_cookie_store.cc b/net/extras/sqlite/sqlite_persistent_cookie_store.cc
index 9fdb070..d80464a 100644
--- a/net/extras/sqlite/sqlite_persistent_cookie_store.cc
+++ b/net/extras/sqlite/sqlite_persistent_cookie_store.cc
@@ -1224,10 +1224,14 @@
   if (cookies.empty())
     return;
 
-  // Perform deletion on background task runner.
-  background_task_runner_->PostTask(
-      FROM_HERE,
-      base::Bind(&Backend::BackgroundDeleteAllInList, this, cookies));
+  if (background_task_runner_->RunsTasksOnCurrentThread()) {
+    BackgroundDeleteAllInList(cookies);
+  } else {
+    // Perform deletion on background task runner.
+    PostBackgroundTask(
+        FROM_HERE,
+        base::Bind(&Backend::BackgroundDeleteAllInList, this, cookies));
+  }
 }
 
 void SQLitePersistentCookieStore::Backend::DeleteSessionCookiesOnStartup() {
diff --git a/net/ftp/ftp_network_transaction_unittest.cc b/net/ftp/ftp_network_transaction_unittest.cc
index 79e1687..c242658d 100644
--- a/net/ftp/ftp_network_transaction_unittest.cc
+++ b/net/ftp/ftp_network_transaction_unittest.cc
@@ -128,6 +128,10 @@
     Init();
   }
 
+  bool AllReadDataConsumed() const override { return state_ == QUIT; }
+
+  bool AllWriteDataConsumed() const override { return state_ == QUIT; }
+
   void set_multiline_welcome(bool multiline) { multiline_welcome_ = multiline; }
 
   bool use_epsv() const { return use_epsv_; }
diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc
index cf73369..0dbb20c 100644
--- a/net/http/http_network_transaction.cc
+++ b/net/http/http_network_transaction.cc
@@ -14,6 +14,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/metrics/field_trial.h"
 #include "base/metrics/histogram.h"
+#include "base/metrics/sparse_histogram.h"
 #include "base/profiler/scoped_tracker.h"
 #include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
@@ -95,12 +96,14 @@
 base::Value* NetLogSSLVersionFallbackCallback(
     const GURL* url,
     int net_error,
+    SSLFailureState ssl_failure_state,
     uint16 version_before,
     uint16 version_after,
     NetLogCaptureMode /* capture_mode */) {
   base::DictionaryValue* dict = new base::DictionaryValue();
   dict->SetString("host_and_port", GetHostAndPort(*url));
   dict->SetInteger("net_error", net_error);
+  dict->SetInteger("ssl_failure_state", ssl_failure_state);
   dict->SetInteger("version_before", version_before);
   dict->SetInteger("version_after", version_after);
   return dict;
@@ -129,7 +132,9 @@
       request_(NULL),
       priority_(priority),
       headers_valid_(false),
+      server_ssl_failure_state_(SSL_FAILURE_NONE),
       fallback_error_code_(ERR_SSL_INAPPROPRIATE_FALLBACK),
+      fallback_failure_state_(SSL_FAILURE_NONE),
       request_headers_(),
       read_buf_len_(0),
       total_received_bytes_(0),
@@ -499,12 +504,14 @@
 }
 
 void HttpNetworkTransaction::OnStreamFailed(int result,
-                                            const SSLConfig& used_ssl_config) {
+                                            const SSLConfig& used_ssl_config,
+                                            SSLFailureState ssl_failure_state) {
   DCHECK_EQ(STATE_CREATE_STREAM_COMPLETE, next_state_);
   DCHECK_NE(OK, result);
   DCHECK(stream_request_.get());
   DCHECK(!stream_.get());
   server_ssl_config_ = used_ssl_config;
+  server_ssl_failure_state_ = ssl_failure_state;
 
   OnIOComplete(result);
 }
@@ -1349,10 +1356,11 @@
   if (should_fallback) {
     net_log_.AddEvent(
         NetLog::TYPE_SSL_VERSION_FALLBACK,
-        base::Bind(&NetLogSSLVersionFallbackCallback,
-                   &request_->url, error, server_ssl_config_.version_max,
+        base::Bind(&NetLogSSLVersionFallbackCallback, &request_->url, error,
+                   server_ssl_failure_state_, server_ssl_config_.version_max,
                    version_max));
     fallback_error_code_ = error;
+    fallback_failure_state_ = server_ssl_failure_state_;
     server_ssl_config_.version_max = version_max;
     server_ssl_config_.version_fallback = true;
     ResetConnectionAndRequestForResend();
@@ -1468,6 +1476,15 @@
 
   UMA_HISTOGRAM_BOOLEAN("Net.ConnectionUsedSSLDeprecatedCipherFallback2",
                         server_ssl_config_.enable_deprecated_cipher_suites);
+
+  if (server_ssl_config_.version_fallback) {
+    // Record the error code which triggered the fallback and the state the
+    // handshake was in.
+    UMA_HISTOGRAM_SPARSE_SLOWLY("Net.SSLFallbackErrorCode",
+                                -fallback_error_code_);
+    UMA_HISTOGRAM_ENUMERATION("Net.SSLFallbackFailureState",
+                              fallback_failure_state_, SSL_FAILURE_MAX);
+  }
 }
 
 HttpResponseHeaders* HttpNetworkTransaction::GetResponseHeaders() const {
diff --git a/net/http/http_network_transaction.h b/net/http/http_network_transaction.h
index 09e0a972..5ea3999 100644
--- a/net/http/http_network_transaction.h
+++ b/net/http/http_network_transaction.h
@@ -22,6 +22,7 @@
 #include "net/proxy/proxy_service.h"
 #include "net/socket/connection_attempts.h"
 #include "net/ssl/ssl_config_service.h"
+#include "net/ssl/ssl_failure_state.h"
 #include "net/websockets/websocket_handshake_stream_base.h"
 
 namespace net {
@@ -85,7 +86,9 @@
       const SSLConfig& used_ssl_config,
       const ProxyInfo& used_proxy_info,
       WebSocketHandshakeStreamBase* stream) override;
-  void OnStreamFailed(int status, const SSLConfig& used_ssl_config) override;
+  void OnStreamFailed(int status,
+                      const SSLConfig& used_ssl_config,
+                      SSLFailureState ssl_failure_state) override;
   void OnCertificateError(int status,
                           const SSLConfig& used_ssl_config,
                           const SSLInfo& ssl_info) override;
@@ -294,12 +297,16 @@
 
   SSLConfig server_ssl_config_;
   SSLConfig proxy_ssl_config_;
+  // The SSLFailureState of the most recent failed stream.
+  SSLFailureState server_ssl_failure_state_;
   // fallback_error_code contains the error code that caused the last TLS
   // fallback. If the fallback connection results in
   // ERR_SSL_INAPPROPRIATE_FALLBACK (i.e. the server indicated that the
   // fallback should not have been needed) then we use this value to return the
   // original error that triggered the fallback.
   int fallback_error_code_;
+  // The SSLFailureState which caused the last TLS version fallback.
+  SSLFailureState fallback_failure_state_;
 
   HttpRequestHeaders request_headers_;
 
diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc
index ea328a5..0991940 100644
--- a/net/http/http_network_transaction_unittest.cc
+++ b/net/http/http_network_transaction_unittest.cc
@@ -127,7 +127,7 @@
   if (!params->GetList("headers", &header_list))
     return false;
   std::string double_quote_headers;
-  base::JSONWriter::Write(header_list, &double_quote_headers);
+  base::JSONWriter::Write(*header_list, &double_quote_headers);
   base::ReplaceChars(double_quote_headers, "\"", "'", headers);
   return true;
 }
@@ -3686,22 +3686,22 @@
       spdy_util_.ConstructSpdyWindowUpdate(1, wrapped_body->size()));
 
   MockWrite spdy_writes[] = {
-      CreateMockWrite(*connect, 1),
-      CreateMockWrite(*wrapped_get, 3),
-      CreateMockWrite(*window_update_get_resp, 5),
+      CreateMockWrite(*connect, 0),
+      CreateMockWrite(*wrapped_get, 2),
+      CreateMockWrite(*window_update_get_resp, 6),
       CreateMockWrite(*window_update_body, 7),
   };
 
   MockRead spdy_reads[] = {
-      CreateMockRead(*conn_resp, 2, ASYNC),
+      CreateMockRead(*conn_resp, 1, ASYNC),
+      MockRead(ASYNC, ERR_IO_PENDING, 3),
       CreateMockRead(*wrapped_get_resp, 4, ASYNC),
-      CreateMockRead(*wrapped_body, 6, ASYNC),
+      CreateMockRead(*wrapped_body, 5, ASYNC),
       MockRead(ASYNC, 0, 8),
   };
 
-  OrderedSocketData spdy_data(
-      spdy_reads, arraysize(spdy_reads),
-      spdy_writes, arraysize(spdy_writes));
+  SequencedSocketData spdy_data(spdy_reads, arraysize(spdy_reads), spdy_writes,
+                                arraysize(spdy_writes));
   session_deps_.socket_factory->AddSocketDataProvider(&spdy_data);
 
   SSLSocketDataProvider ssl(ASYNC, OK);
@@ -3716,6 +3716,10 @@
   int rv = trans->Start(&request, callback1.callback(), log.bound());
   EXPECT_EQ(ERR_IO_PENDING, rv);
 
+  // Allow the SpdyProxyClientSocket's write callback to complete.
+  base::MessageLoop::current()->RunUntilIdle();
+  // Now allow the read of the response to complete.
+  spdy_data.CompleteRead();
   rv = callback1.WaitForResult();
   EXPECT_EQ(OK, rv);
 
@@ -11861,8 +11865,8 @@
       reads.push_back(MockRead(ASYNC, OK, 3));
     }
 
-    OrderedSocketData data(vector_as_array(&reads), reads.size(),
-                           vector_as_array(&writes), writes.size());
+    SequencedSocketData data(vector_as_array(&reads), reads.size(),
+                             vector_as_array(&writes), writes.size());
     session_deps_.socket_factory->AddSocketDataProvider(&data);
 
     // Connection to the origin fails.
@@ -11907,6 +11911,10 @@
 
     int rv = trans1->Start(&request1, callback1.callback(), BoundNetLog());
     EXPECT_EQ(ERR_IO_PENDING, rv);
+    base::MessageLoop::current()->RunUntilIdle();
+    if (data.IsReadPaused()) {
+      data.CompleteRead();
+    }
     rv = callback1.WaitForResult();
     if (valid) {
       EXPECT_EQ(OK, rv);
diff --git a/net/http/http_server_properties_manager_unittest.cc b/net/http/http_server_properties_manager_unittest.cc
index 7ab6ef06..414613cd 100644
--- a/net/http/http_server_properties_manager_unittest.cc
+++ b/net/http/http_server_properties_manager_unittest.cc
@@ -708,7 +708,7 @@
   ASSERT_NE(nullptr, http_server_properties);
   std::string preferences_json;
   EXPECT_TRUE(
-      base::JSONWriter::Write(http_server_properties, &preferences_json));
+      base::JSONWriter::Write(*http_server_properties, &preferences_json));
   EXPECT_EQ(expected_json, preferences_json);
 }
 
diff --git a/net/http/http_stream_factory.h b/net/http/http_stream_factory.h
index 60ff9d2..b53ee45f 100644
--- a/net/http/http_stream_factory.h
+++ b/net/http/http_stream_factory.h
@@ -17,6 +17,7 @@
 #include "net/base/request_priority.h"
 #include "net/http/http_server_properties.h"
 #include "net/socket/connection_attempts.h"
+#include "net/ssl/ssl_failure_state.h"
 // This file can be included from net/http even though
 // it is in net/websockets because it doesn't
 // introduce any link dependency to net/websockets.
@@ -86,9 +87,11 @@
     // This is the failure to create a stream case.
     // |used_ssl_config| indicates the actual SSL configuration used for this
     // stream, since the HttpStreamRequest may have modified the configuration
-    // during stream processing.
+    // during stream processing. If an SSL handshake failed, |ssl_failure_state|
+    // is the state the SSLClientSocket was in.
     virtual void OnStreamFailed(int status,
-                                const SSLConfig& used_ssl_config) = 0;
+                                const SSLConfig& used_ssl_config,
+                                SSLFailureState ssl_failure_state) = 0;
 
     // Called when we have a certificate error for the request.
     // |used_ssl_config| indicates the actual SSL configuration used for this
diff --git a/net/http/http_stream_factory_impl_job.cc b/net/http/http_stream_factory_impl_job.cc
index 1d17b08..b986415 100644
--- a/net/http/http_stream_factory_impl_job.cc
+++ b/net/http/http_stream_factory_impl_job.cc
@@ -40,6 +40,7 @@
 #include "net/spdy/spdy_session.h"
 #include "net/spdy/spdy_session_pool.h"
 #include "net/ssl/ssl_cert_request_info.h"
+#include "net/ssl/ssl_failure_state.h"
 
 namespace net {
 
@@ -364,10 +365,14 @@
 
   MaybeCopyConnectionAttemptsFromSocketOrHandle();
 
-  if (IsOrphaned())
+  if (IsOrphaned()) {
     stream_factory_->OnOrphanedJobComplete(this);
-  else
-    request_->OnStreamFailed(this, result, server_ssl_config_);
+  } else {
+    SSLFailureState ssl_failure_state =
+        connection_ ? connection_->ssl_failure_state() : SSL_FAILURE_NONE;
+    request_->OnStreamFailed(this, result, server_ssl_config_,
+                             ssl_failure_state);
+  }
   // |this| may be deleted after this call.
 }
 
@@ -799,7 +804,6 @@
     HostPortPair destination = proxy_info_.is_quic()
                                    ? proxy_info_.proxy_server().host_port_pair()
                                    : server_;
-    next_state_ = STATE_INIT_CONNECTION_COMPLETE;
     bool secure_quic = using_ssl_ || proxy_info_.is_quic();
     int rv = quic_request_.Request(
         destination, secure_quic, request_info_.privacy_mode,
diff --git a/net/http/http_stream_factory_impl_request.cc b/net/http/http_stream_factory_impl_request.cc
index d8a4b5b6..53548b1 100644
--- a/net/http/http_stream_factory_impl_request.cc
+++ b/net/http/http_stream_factory_impl_request.cc
@@ -116,7 +116,8 @@
 void HttpStreamFactoryImpl::Request::OnStreamFailed(
     Job* job,
     int status,
-    const SSLConfig& used_ssl_config) {
+    const SSLConfig& used_ssl_config,
+    SSLFailureState ssl_failure_state) {
   DCHECK_NE(OK, status);
   DCHECK(job);
   if (!bound_job_.get()) {
@@ -139,7 +140,7 @@
   } else {
     DCHECK(jobs_.empty());
   }
-  delegate_->OnStreamFailed(status, used_ssl_config);
+  delegate_->OnStreamFailed(status, used_ssl_config, ssl_failure_state);
 }
 
 void HttpStreamFactoryImpl::Request::OnCertificateError(
diff --git a/net/http/http_stream_factory_impl_request.h b/net/http/http_stream_factory_impl_request.h
index 7bc41afc..2244253 100644
--- a/net/http/http_stream_factory_impl_request.h
+++ b/net/http/http_stream_factory_impl_request.h
@@ -12,6 +12,7 @@
 #include "net/socket/connection_attempts.h"
 #include "net/socket/ssl_client_socket.h"
 #include "net/spdy/spdy_session_key.h"
+#include "net/ssl/ssl_failure_state.h"
 #include "url/gurl.h"
 
 namespace net {
@@ -81,7 +82,10 @@
                                        const SSLConfig& used_ssl_config,
                                        const ProxyInfo& used_proxy_info,
                                        WebSocketHandshakeStreamBase* stream);
-  void OnStreamFailed(Job* job, int status, const SSLConfig& used_ssl_config);
+  void OnStreamFailed(Job* job,
+                      int status,
+                      const SSLConfig& used_ssl_config,
+                      SSLFailureState ssl_failure_state);
   void OnCertificateError(Job* job,
                           int status,
                           const SSLConfig& used_ssl_config,
diff --git a/net/http/http_stream_factory_impl_request_unittest.cc b/net/http/http_stream_factory_impl_request_unittest.cc
index b7afbfe..65a9637 100644
--- a/net/http/http_stream_factory_impl_request_unittest.cc
+++ b/net/http/http_stream_factory_impl_request_unittest.cc
@@ -8,6 +8,7 @@
 #include "net/proxy/proxy_info.h"
 #include "net/proxy/proxy_service.h"
 #include "net/spdy/spdy_test_util_common.h"
+#include "net/ssl/ssl_failure_state.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace net {
@@ -38,7 +39,9 @@
       const SSLConfig& used_ssl_config,
       const ProxyInfo& used_proxy_info,
       WebSocketHandshakeStreamBase* stream) override {}
-  void OnStreamFailed(int status, const SSLConfig& used_ssl_config) override {}
+  void OnStreamFailed(int status,
+                      const SSLConfig& used_ssl_config,
+                      SSLFailureState ssl_failure_state) override {}
   void OnCertificateError(int status,
                           const SSLConfig& used_ssl_config,
                           const SSLInfo& ssl_info) override {}
@@ -85,7 +88,7 @@
   EXPECT_EQ(MEDIUM, job->priority());
 
   // Make |job| the bound job.
-  request.OnStreamFailed(job, ERR_FAILED, SSLConfig());
+  request.OnStreamFailed(job, ERR_FAILED, SSLConfig(), SSL_FAILURE_NONE);
 
   request.SetPriority(IDLE);
   EXPECT_EQ(IDLE, job->priority());
diff --git a/net/http/http_stream_factory_impl_unittest.cc b/net/http/http_stream_factory_impl_unittest.cc
index 1c0b982..6b20b9a7 100644
--- a/net/http/http_stream_factory_impl_unittest.cc
+++ b/net/http/http_stream_factory_impl_unittest.cc
@@ -165,7 +165,9 @@
     used_proxy_info_ = used_proxy_info;
   }
 
-  void OnStreamFailed(int status, const SSLConfig& used_ssl_config) override {}
+  void OnStreamFailed(int status,
+                      const SSLConfig& used_ssl_config,
+                      SSLFailureState ssl_failure_state) override {}
 
   void OnCertificateError(int status,
                           const SSLConfig& used_ssl_config,
diff --git a/net/http/transport_security_persister.cc b/net/http/transport_security_persister.cc
index 08aa07e..22422009 100644
--- a/net/http/transport_security_persister.cc
+++ b/net/http/transport_security_persister.cc
@@ -171,9 +171,8 @@
     toplevel.Set(HashedDomainToExternalString(hostname), serialized);
   }
 
-  base::JSONWriter::WriteWithOptions(&toplevel,
-                                     base::JSONWriter::OPTIONS_PRETTY_PRINT,
-                                     output);
+  base::JSONWriter::WriteWithOptions(
+      toplevel, base::JSONWriter::OPTIONS_PRETTY_PRINT, output);
   return true;
 }
 
diff --git a/net/interfaces/proxy_resolver_service.mojom b/net/interfaces/proxy_resolver_service.mojom
index 57ab121..68f798e 100644
--- a/net/interfaces/proxy_resolver_service.mojom
+++ b/net/interfaces/proxy_resolver_service.mojom
@@ -42,11 +42,16 @@
   LoadStateChanged(int32 load_state);
 };
 
+interface ProxyResolverErrorObserver {
+  OnPacScriptError(int32 line_number, string error);
+};
+
 interface ProxyResolverFactory {
-  // TODO(amistry): Add NetLog and ProxyResolverErrorObserver.
+  // TODO(amistry): Add NetLog.
   CreateResolver(string pac_script,
                  ProxyResolver& resolver,
                  HostResolver host_resolver,
+                 ProxyResolverErrorObserver? error_observer,
                  ProxyResolverFactoryRequestClient client);
 };
 
diff --git a/net/log/test_net_log_entry.cc b/net/log/test_net_log_entry.cc
index 948693b..34e9ffa 100644
--- a/net/log/test_net_log_entry.cc
+++ b/net/log/test_net_log_entry.cc
@@ -76,7 +76,7 @@
   if (!params)
     return std::string();
   std::string json;
-  base::JSONWriter::Write(params.get(), &json);
+  base::JSONWriter::Write(*params, &json);
   return json;
 }
 
diff --git a/net/log/trace_net_log_observer.cc b/net/log/trace_net_log_observer.cc
index 2ce8bc0..4978e64c 100644
--- a/net/log/trace_net_log_observer.cc
+++ b/net/log/trace_net_log_observer.cc
@@ -32,7 +32,7 @@
   void AppendAsTraceFormat(std::string* out) const override {
     if (value_) {
       std::string tmp;
-      base::JSONWriter::Write(value_.get(), &tmp);
+      base::JSONWriter::Write(*value_, &tmp);
       *out += tmp;
     } else {
       *out += "\"\"";
diff --git a/net/log/write_to_file_net_log_observer.cc b/net/log/write_to_file_net_log_observer.cc
index 8ef5a71..5c4f951 100644
--- a/net/log/write_to_file_net_log_observer.cc
+++ b/net/log/write_to_file_net_log_observer.cc
@@ -43,12 +43,11 @@
   // different source and event types, as they may be added and removed
   // between Chrome versions.
   std::string json;
-  if (constants) {
-    base::JSONWriter::Write(constants, &json);
-  } else {
-    scoped_ptr<base::DictionaryValue> scoped_constants(GetNetConstants());
-    base::JSONWriter::Write(scoped_constants.get(), &json);
-  }
+  if (constants)
+    base::JSONWriter::Write(*constants, &json);
+  else
+    base::JSONWriter::Write(*GetNetConstants(), &json);
+
   fprintf(file_.get(), "{\"constants\": %s,\n", json.c_str());
 
   // Start events array.  It's closed in StopObserving().
@@ -78,9 +77,8 @@
     DCHECK(url_request_context->CalledOnValidThread());
 
     std::string json;
-    scoped_ptr<base::DictionaryValue> net_info =
-        GetNetInfo(url_request_context, NET_INFO_ALL_SOURCES);
-    base::JSONWriter::Write(net_info.get(), &json);
+    base::JSONWriter::Write(
+        *GetNetInfo(url_request_context, NET_INFO_ALL_SOURCES), &json);
     fprintf(file_.get(), ",\"tabInfo\": %s\n", json.c_str());
   }
   fprintf(file_.get(), "}");
@@ -94,7 +92,7 @@
   // work, lines cannot be pretty printed.
   scoped_ptr<base::Value> value(entry.ToValue());
   std::string json;
-  base::JSONWriter::Write(value.get(), &json);
+  base::JSONWriter::Write(*value, &json);
   fprintf(file_.get(), "%s%s", (added_events_ ? ",\n" : ""), json.c_str());
   added_events_ = true;
 }
diff --git a/net/net.gyp b/net/net.gyp
index e3d858c6..588e13e 100644
--- a/net/net.gyp
+++ b/net/net.gyp
@@ -5,7 +5,9 @@
 {
   'variables': {
     'chromium_code': 1,
-
+    # Defines an extra set of libs with an alternate copy of org.apache.http.
+    # TODO(yfriedman): Remove this when crbug.com/488192 is fixed.
+    'net_test_extra_libs': [],
     'linux_link_kerberos%': 0,
     'conditions': [
       ['chromeos==1 or embedded==1 or OS=="android" or OS=="ios"', {
@@ -319,6 +321,7 @@
               'proxy/load_state_change_coalescer_unittest.cc',
               'proxy/mojo_proxy_resolver_factory_impl_unittest.cc',
               'proxy/mojo_proxy_resolver_impl_unittest.cc',
+              'proxy/proxy_resolver_error_observer_mojo_unittest.cc',
               'proxy/proxy_resolver_mojo_unittest.cc',
               'proxy/proxy_service_mojo_unittest.cc',
             ],
@@ -925,6 +928,8 @@
             'proxy/mojo_proxy_resolver_factory_impl.h',
             'proxy/mojo_proxy_resolver_impl.cc',
             'proxy/mojo_proxy_resolver_impl.h',
+            'proxy/proxy_resolver_error_observer_mojo.cc',
+            'proxy/proxy_resolver_error_observer_mojo.h',
           ],
           'dependencies': [
             'mojo_type_converters',
@@ -1402,7 +1407,8 @@
           },
           'dependencies': [
             'url_request_failed_job_java',
-            '../base/base.gyp:base_java'
+            '../base/base.gyp:base_java',
+            '<@(net_test_extra_libs)',
           ],
           'includes': [ '../build/java.gypi' ],
         },
diff --git a/net/net.gypi b/net/net.gypi
index c2148c0..3510fc36 100644
--- a/net/net.gypi
+++ b/net/net.gypi
@@ -170,6 +170,7 @@
       'ssl/ssl_config.h',
       'ssl/ssl_config_service.cc',
       'ssl/ssl_config_service.h',
+      'ssl/ssl_failure_state.h',
       'ssl/ssl_info.cc',
       'ssl/ssl_info.h',
     ],
@@ -1478,6 +1479,7 @@
       'proxy/proxy_config_unittest.cc',
       'proxy/proxy_info_unittest.cc',
       'proxy/proxy_list_unittest.cc',
+      'proxy/proxy_resolver_error_observer_mojo_unittest.cc',
       'proxy/proxy_resolver_mojo_unittest.cc',
       'proxy/proxy_resolver_factory_unittest.cc',
       'proxy/proxy_resolver_v8_tracing_unittest.cc',
diff --git a/net/proxy/in_process_mojo_proxy_resolver_factory.cc b/net/proxy/in_process_mojo_proxy_resolver_factory.cc
index b38a093..cb1cf21 100644
--- a/net/proxy/in_process_mojo_proxy_resolver_factory.cc
+++ b/net/proxy/in_process_mojo_proxy_resolver_factory.cc
@@ -30,9 +30,10 @@
     const mojo::String& pac_script,
     mojo::InterfaceRequest<interfaces::ProxyResolver> req,
     interfaces::HostResolverPtr host_resolver,
+    interfaces::ProxyResolverErrorObserverPtr error_observer,
     interfaces::ProxyResolverFactoryRequestClientPtr client) {
   factory_->CreateResolver(pac_script, req.Pass(), host_resolver.Pass(),
-                           client.Pass());
+                           error_observer.Pass(), client.Pass());
   return nullptr;
 }
 
diff --git a/net/proxy/in_process_mojo_proxy_resolver_factory.h b/net/proxy/in_process_mojo_proxy_resolver_factory.h
index 8794614f..86895e92 100644
--- a/net/proxy/in_process_mojo_proxy_resolver_factory.h
+++ b/net/proxy/in_process_mojo_proxy_resolver_factory.h
@@ -25,6 +25,7 @@
       const mojo::String& pac_script,
       mojo::InterfaceRequest<interfaces::ProxyResolver> req,
       interfaces::HostResolverPtr host_resolver,
+      interfaces::ProxyResolverErrorObserverPtr error_observer,
       interfaces::ProxyResolverFactoryRequestClientPtr client) override;
 
  private:
diff --git a/net/proxy/mojo_proxy_resolver_factory.h b/net/proxy/mojo_proxy_resolver_factory.h
index a27b81a..89b70f4 100644
--- a/net/proxy/mojo_proxy_resolver_factory.h
+++ b/net/proxy/mojo_proxy_resolver_factory.h
@@ -24,6 +24,7 @@
       const mojo::String& pac_script,
       mojo::InterfaceRequest<interfaces::ProxyResolver> req,
       interfaces::HostResolverPtr host_resolver,
+      interfaces::ProxyResolverErrorObserverPtr error_observer,
       interfaces::ProxyResolverFactoryRequestClientPtr client) = 0;
 
  protected:
diff --git a/net/proxy/mojo_proxy_resolver_factory_impl.cc b/net/proxy/mojo_proxy_resolver_factory_impl.cc
index 9134495b..4a95aa72 100644
--- a/net/proxy/mojo_proxy_resolver_factory_impl.cc
+++ b/net/proxy/mojo_proxy_resolver_factory_impl.cc
@@ -10,6 +10,7 @@
 #include "net/base/net_errors.h"
 #include "net/dns/host_resolver_mojo.h"
 #include "net/proxy/mojo_proxy_resolver_impl.h"
+#include "net/proxy/proxy_resolver_error_observer_mojo.h"
 #include "net/proxy/proxy_resolver_factory.h"
 #include "net/proxy/proxy_resolver_v8.h"
 #include "net/proxy/proxy_resolver_v8_tracing.h"
@@ -18,30 +19,18 @@
 namespace net {
 namespace {
 
-class DefaultProxyResolverFactory : public LegacyProxyResolverFactory {
- public:
-  DefaultProxyResolverFactory(
-      HostResolver* host_resolver,
-      const ProxyResolver::LoadStateChangedCallback& callback)
-      : LegacyProxyResolverFactory(true),
-        host_resolver_(host_resolver),
-        callback_(callback) {}
-
-  scoped_ptr<ProxyResolver> CreateProxyResolver() override {
-    return make_scoped_ptr(new ProxyResolverV8Tracing(host_resolver_, nullptr,
-                                                      nullptr, callback_));
-  }
-
- private:
-  HostResolver* const host_resolver_;
-  const ProxyResolver::LoadStateChangedCallback callback_;
-};
+scoped_ptr<ProxyResolverErrorObserver> ReturnErrorObserver(
+    scoped_ptr<ProxyResolverErrorObserver> error_observer) {
+  return error_observer;
+}
 
 scoped_ptr<ProxyResolverFactory> CreateDefaultProxyResolver(
     HostResolver* host_resolver,
+    scoped_ptr<ProxyResolverErrorObserver> error_observer,
     const ProxyResolver::LoadStateChangedCallback& callback) {
-  return make_scoped_ptr(
-      new DefaultProxyResolverFactory(host_resolver, callback));
+  return make_scoped_ptr(new ProxyResolverFactoryV8Tracing(
+      host_resolver, nullptr, callback,
+      base::Bind(&ReturnErrorObserver, base::Passed(&error_observer))));
 }
 
 class LoadStateChangeForwarder
@@ -121,6 +110,7 @@
       const MojoProxyResolverFactoryImpl::Factory& proxy_resolver_factory,
       mojo::InterfaceRequest<interfaces::ProxyResolver> request,
       interfaces::HostResolverPtr host_resolver,
+      interfaces::ProxyResolverErrorObserverPtr error_observer,
       interfaces::ProxyResolverFactoryRequestClientPtr client);
   ~Job() override;
 
@@ -148,6 +138,7 @@
     const MojoProxyResolverFactoryImpl::Factory& proxy_resolver_factory,
     mojo::InterfaceRequest<interfaces::ProxyResolver> request,
     interfaces::HostResolverPtr host_resolver,
+    interfaces::ProxyResolverErrorObserverPtr error_observer,
     interfaces::ProxyResolverFactoryRequestClientPtr client)
     : parent_(factory),
       host_resolver_(new HostResolverMojo(
@@ -158,6 +149,7 @@
       proxy_request_(request.Pass()),
       factory_(proxy_resolver_factory.Run(
           host_resolver_.get(),
+          ProxyResolverErrorObserverMojo::Create(error_observer.Pass()),
           base::Bind(&LoadStateChangeForwarder::OnLoadStateChanged,
                      load_state_change_forwarder_))),
       client_ptr_(client.Pass()) {
@@ -209,13 +201,14 @@
     const mojo::String& pac_script,
     mojo::InterfaceRequest<interfaces::ProxyResolver> request,
     interfaces::HostResolverPtr host_resolver,
+    interfaces::ProxyResolverErrorObserverPtr error_observer,
     interfaces::ProxyResolverFactoryRequestClientPtr client) {
   // The Job will call RemoveJob on |this| when either the create request
   // finishes or |request| or |client| encounters a connection error.
   jobs_.insert(new Job(
       this, ProxyResolverScriptData::FromUTF8(pac_script.To<std::string>()),
       proxy_resolver_impl_factory_, request.Pass(), host_resolver.Pass(),
-      client.Pass()));
+      error_observer.Pass(), client.Pass()));
 }
 
 void MojoProxyResolverFactoryImpl::RemoveJob(Job* job) {
diff --git a/net/proxy/mojo_proxy_resolver_factory_impl.h b/net/proxy/mojo_proxy_resolver_factory_impl.h
index 29bc6536..bf652b7 100644
--- a/net/proxy/mojo_proxy_resolver_factory_impl.h
+++ b/net/proxy/mojo_proxy_resolver_factory_impl.h
@@ -14,12 +14,14 @@
 
 namespace net {
 class HostResolver;
+class ProxyResolverErrorObserver;
 class ProxyResolverFactory;
 
 class MojoProxyResolverFactoryImpl : public interfaces::ProxyResolverFactory {
  public:
   using Factory = base::Callback<scoped_ptr<net::ProxyResolverFactory>(
       HostResolver*,
+      scoped_ptr<ProxyResolverErrorObserver>,
       const ProxyResolver::LoadStateChangedCallback&)>;
 
   explicit MojoProxyResolverFactoryImpl(
@@ -38,6 +40,7 @@
       const mojo::String& pac_script,
       mojo::InterfaceRequest<interfaces::ProxyResolver> request,
       interfaces::HostResolverPtr host_resolver,
+      interfaces::ProxyResolverErrorObserverPtr error_observer,
       interfaces::ProxyResolverFactoryRequestClientPtr client) override;
 
   void RemoveJob(Job* job);
diff --git a/net/proxy/mojo_proxy_resolver_factory_impl_unittest.cc b/net/proxy/mojo_proxy_resolver_factory_impl_unittest.cc
index c5fb69b..2fe9d81b 100644
--- a/net/proxy/mojo_proxy_resolver_factory_impl_unittest.cc
+++ b/net/proxy/mojo_proxy_resolver_factory_impl_unittest.cc
@@ -7,6 +7,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "net/base/test_completion_callback.h"
 #include "net/proxy/mock_proxy_resolver.h"
+#include "net/proxy/proxy_resolver_error_observer.h"
 #include "net/test/event_waiter.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/mojo/src/mojo/public/cpp/bindings/binding.h"
@@ -75,6 +76,7 @@
 
   scoped_ptr<ProxyResolverFactory> CreateFakeProxyResolverFactory(
       HostResolver* host_resolver,
+      scoped_ptr<ProxyResolverErrorObserver> error_observer,
       const ProxyResolver::LoadStateChangedCallback& callback) {
     EXPECT_TRUE(host_resolver);
     EXPECT_FALSE(callback.is_null());
@@ -105,12 +107,14 @@
   interfaces::HostResolverPtr host_resolver;
   mojo::InterfaceRequest<interfaces::HostResolver> host_resolver_request =
       mojo::GetProxy(&host_resolver);
+  interfaces::ProxyResolverErrorObserverPtr error_observer;
+  mojo::GetProxy(&error_observer);
   interfaces::ProxyResolverFactoryRequestClientPtr client_ptr;
   mojo::Binding<ProxyResolverFactoryRequestClient> client_binding(
       this, mojo::GetProxy(&client_ptr));
-  factory_->CreateResolver(mojo::String::From(kScriptData),
-                           mojo::GetProxy(&proxy_resolver),
-                           host_resolver.Pass(), client_ptr.Pass());
+  factory_->CreateResolver(
+      mojo::String::From(kScriptData), mojo::GetProxy(&proxy_resolver),
+      host_resolver.Pass(), error_observer.Pass(), client_ptr.Pass());
   proxy_resolver.set_error_handler(this);
   waiter_.WaitForEvent(RESOLVER_CREATED);
   EXPECT_EQ(0, instances_destroyed_);
@@ -136,12 +140,14 @@
       mojo::GetProxy(&host_resolver);
   mojo::Binding<interfaces::HostResolver> binding(nullptr, &host_resolver);
   binding.set_error_handler(this);
+  interfaces::ProxyResolverErrorObserverPtr error_observer;
+  mojo::GetProxy(&error_observer);
   interfaces::ProxyResolverFactoryRequestClientPtr client_ptr;
   mojo::Binding<ProxyResolverFactoryRequestClient> client_binding(
       this, mojo::GetProxy(&client_ptr));
-  factory_->CreateResolver(mojo::String::From(kScriptData),
-                           mojo::GetProxy(&proxy_resolver),
-                           host_resolver.Pass(), client_ptr.Pass());
+  factory_->CreateResolver(
+      mojo::String::From(kScriptData), mojo::GetProxy(&proxy_resolver),
+      host_resolver.Pass(), error_observer.Pass(), client_ptr.Pass());
   proxy_resolver.set_error_handler(this);
   waiter_.WaitForEvent(RESOLVER_CREATED);
   EXPECT_EQ(0, instances_destroyed_);
@@ -165,12 +171,14 @@
   interfaces::HostResolverPtr host_resolver;
   mojo::InterfaceRequest<interfaces::HostResolver> host_resolver_request =
       mojo::GetProxy(&host_resolver);
+  interfaces::ProxyResolverErrorObserverPtr error_observer;
+  mojo::GetProxy(&error_observer);
   interfaces::ProxyResolverFactoryRequestClientPtr client_ptr;
   mojo::Binding<ProxyResolverFactoryRequestClient> client_binding(
       this, mojo::GetProxy(&client_ptr));
-  factory_->CreateResolver(mojo::String::From(kScriptData),
-                           mojo::GetProxy(&proxy_resolver),
-                           host_resolver.Pass(), client_ptr.Pass());
+  factory_->CreateResolver(
+      mojo::String::From(kScriptData), mojo::GetProxy(&proxy_resolver),
+      host_resolver.Pass(), error_observer.Pass(), client_ptr.Pass());
   proxy_resolver.set_error_handler(this);
   waiter_.WaitForEvent(RESOLVER_CREATED);
   EXPECT_EQ(0, instances_destroyed_);
@@ -195,12 +203,14 @@
   interfaces::HostResolverPtr host_resolver;
   mojo::InterfaceRequest<interfaces::HostResolver> host_resolver_request =
       mojo::GetProxy(&host_resolver);
+  interfaces::ProxyResolverErrorObserverPtr error_observer;
+  mojo::GetProxy(&error_observer);
   interfaces::ProxyResolverFactoryRequestClientPtr client_ptr;
   mojo::Binding<ProxyResolverFactoryRequestClient> client_binding(
       this, mojo::GetProxy(&client_ptr));
-  factory_->CreateResolver(mojo::String::From(kScriptData),
-                           mojo::GetProxy(&proxy_resolver),
-                           host_resolver.Pass(), client_ptr.Pass());
+  factory_->CreateResolver(
+      mojo::String::From(kScriptData), mojo::GetProxy(&proxy_resolver),
+      host_resolver.Pass(), error_observer.Pass(), client_ptr.Pass());
   proxy_resolver.set_error_handler(this);
   waiter_.WaitForEvent(RESOLVER_CREATED);
   EXPECT_EQ(0, instances_destroyed_);
@@ -220,12 +230,14 @@
   interfaces::HostResolverPtr host_resolver;
   mojo::InterfaceRequest<interfaces::HostResolver> host_resolver_request =
       mojo::GetProxy(&host_resolver);
+  interfaces::ProxyResolverErrorObserverPtr error_observer;
+  mojo::GetProxy(&error_observer);
   interfaces::ProxyResolverFactoryRequestClientPtr client_ptr;
   mojo::Binding<ProxyResolverFactoryRequestClient> client_binding(
       this, mojo::GetProxy(&client_ptr));
-  factory_->CreateResolver(mojo::String::From(kScriptData),
-                           mojo::GetProxy(&proxy_resolver),
-                           host_resolver.Pass(), client_ptr.Pass());
+  factory_->CreateResolver(
+      mojo::String::From(kScriptData), mojo::GetProxy(&proxy_resolver),
+      host_resolver.Pass(), error_observer.Pass(), client_ptr.Pass());
   proxy_resolver.set_error_handler(this);
   waiter_.WaitForEvent(RESOLVER_CREATED);
   EXPECT_EQ(0, instances_destroyed_);
@@ -247,12 +259,14 @@
       mojo::GetProxy(&host_resolver);
   mojo::Binding<interfaces::HostResolver> binding(nullptr, &host_resolver);
   binding.set_error_handler(this);
+  interfaces::ProxyResolverErrorObserverPtr error_observer;
+  mojo::GetProxy(&error_observer);
   interfaces::ProxyResolverFactoryRequestClientPtr client_ptr;
   mojo::Binding<ProxyResolverFactoryRequestClient> client_binding(
       this, mojo::GetProxy(&client_ptr));
-  factory_->CreateResolver(mojo::String::From(kScriptData),
-                           mojo::GetProxy(&proxy_resolver),
-                           host_resolver.Pass(), client_ptr.Pass());
+  factory_->CreateResolver(
+      mojo::String::From(kScriptData), mojo::GetProxy(&proxy_resolver),
+      host_resolver.Pass(), error_observer.Pass(), client_ptr.Pass());
   proxy_resolver.set_error_handler(this);
   waiter_.WaitForEvent(RESOLVER_CREATED);
   EXPECT_EQ(0, instances_destroyed_);
@@ -271,12 +285,14 @@
       mojo::GetProxy(&host_resolver);
   mojo::Binding<interfaces::HostResolver> binding(nullptr, &host_resolver);
   binding.set_error_handler(this);
+  interfaces::ProxyResolverErrorObserverPtr error_observer;
+  mojo::GetProxy(&error_observer);
   interfaces::ProxyResolverFactoryRequestClientPtr client_ptr;
   mojo::Binding<ProxyResolverFactoryRequestClient> client_binding(
       this, mojo::GetProxy(&client_ptr));
-  factory_->CreateResolver(mojo::String::From(kScriptData),
-                           mojo::GetProxy(&proxy_resolver),
-                           host_resolver.Pass(), client_ptr.Pass());
+  factory_->CreateResolver(
+      mojo::String::From(kScriptData), mojo::GetProxy(&proxy_resolver),
+      host_resolver.Pass(), error_observer.Pass(), client_ptr.Pass());
   proxy_resolver.set_error_handler(this);
   client_binding.set_error_handler(this);
   waiter_.WaitForEvent(RESOLVER_CREATED);
diff --git a/net/proxy/network_delegate_error_observer.cc b/net/proxy/network_delegate_error_observer.cc
index e92065b..1bb0537 100644
--- a/net/proxy/network_delegate_error_observer.cc
+++ b/net/proxy/network_delegate_error_observer.cc
@@ -74,6 +74,14 @@
   core_->Shutdown();
 }
 
+// static
+scoped_ptr<ProxyResolverErrorObserver> NetworkDelegateErrorObserver::Create(
+    NetworkDelegate* network_delegate,
+    const scoped_refptr<base::SingleThreadTaskRunner>& origin_runner) {
+  return make_scoped_ptr(
+      new NetworkDelegateErrorObserver(network_delegate, origin_runner.get()));
+}
+
 void NetworkDelegateErrorObserver::OnPACScriptError(
     int line_number,
     const base::string16& error) {
diff --git a/net/proxy/network_delegate_error_observer.h b/net/proxy/network_delegate_error_observer.h
index 2ae649c..2463913f 100644
--- a/net/proxy/network_delegate_error_observer.h
+++ b/net/proxy/network_delegate_error_observer.h
@@ -7,6 +7,7 @@
 
 #include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
 #include "net/proxy/proxy_resolver_error_observer.h"
 
 namespace base {
@@ -26,6 +27,10 @@
                                base::SingleThreadTaskRunner* origin_runner);
   ~NetworkDelegateErrorObserver() override;
 
+  static scoped_ptr<ProxyResolverErrorObserver> Create(
+      NetworkDelegate* network_delegate,
+      const scoped_refptr<base::SingleThreadTaskRunner>& origin_runner);
+
   // ProxyResolverErrorObserver implementation.
   void OnPACScriptError(int line_number, const base::string16& error) override;
 
diff --git a/net/proxy/proxy_resolver_error_observer_mojo.cc b/net/proxy/proxy_resolver_error_observer_mojo.cc
new file mode 100644
index 0000000..a63d5d9
--- /dev/null
+++ b/net/proxy/proxy_resolver_error_observer_mojo.cc
@@ -0,0 +1,46 @@
+// 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 "net/proxy/proxy_resolver_error_observer_mojo.h"
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/thread_task_runner_handle.h"
+#include "mojo/common/common_type_converters.h"
+
+namespace net {
+
+// static
+scoped_ptr<ProxyResolverErrorObserver> ProxyResolverErrorObserverMojo::Create(
+    interfaces::ProxyResolverErrorObserverPtr error_observer) {
+  if (!error_observer)
+    return nullptr;
+
+  return scoped_ptr<ProxyResolverErrorObserver>(
+      new ProxyResolverErrorObserverMojo(error_observer.Pass()));
+}
+
+void ProxyResolverErrorObserverMojo::OnPACScriptError(
+    int line_number,
+    const base::string16& error) {
+  if (!task_runner_->RunsTasksOnCurrentThread()) {
+    task_runner_->PostTask(
+        FROM_HERE, base::Bind(&ProxyResolverErrorObserverMojo::OnPACScriptError,
+                              weak_this_, line_number, error));
+    return;
+  }
+  error_observer_->OnPacScriptError(line_number, mojo::String::From(error));
+}
+
+ProxyResolverErrorObserverMojo::ProxyResolverErrorObserverMojo(
+    interfaces::ProxyResolverErrorObserverPtr error_observer)
+    : error_observer_(error_observer.Pass()),
+      task_runner_(base::ThreadTaskRunnerHandle::Get()),
+      weak_factory_(this) {
+  weak_this_ = weak_factory_.GetWeakPtr();
+}
+
+ProxyResolverErrorObserverMojo::~ProxyResolverErrorObserverMojo() = default;
+
+}  // namespace net
diff --git a/net/proxy/proxy_resolver_error_observer_mojo.h b/net/proxy/proxy_resolver_error_observer_mojo.h
new file mode 100644
index 0000000..95a8ff9
--- /dev/null
+++ b/net/proxy/proxy_resolver_error_observer_mojo.h
@@ -0,0 +1,43 @@
+// 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 NET_PROXY_PROXY_RESOLVER_ERROR_OBSERVER_MOJO_H_
+#define NET_PROXY_PROXY_RESOLVER_ERROR_OBSERVER_MOJO_H_
+
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/single_thread_task_runner.h"
+#include "net/interfaces/proxy_resolver_service.mojom.h"
+#include "net/proxy/proxy_resolver_error_observer.h"
+
+namespace net {
+
+// An implementation of ProxyResolverErrorObserver that forwards errors to an
+// interfaces::ProxyResolverErrorObserver mojo interface.
+class ProxyResolverErrorObserverMojo : public ProxyResolverErrorObserver {
+ public:
+  static scoped_ptr<ProxyResolverErrorObserver> Create(
+      interfaces::ProxyResolverErrorObserverPtr error_observer);
+
+  void OnPACScriptError(int line_number, const base::string16& error) override;
+
+ private:
+  explicit ProxyResolverErrorObserverMojo(
+      interfaces::ProxyResolverErrorObserverPtr error_observer);
+  ~ProxyResolverErrorObserverMojo() override;
+
+  // |error_observer_| may only be accessed when running on |task_runner_|.
+  interfaces::ProxyResolverErrorObserverPtr error_observer_;
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+
+  // Creating a new WeakPtr is only valid on the original thread, but copying an
+  // existing WeakPtr is valid on any thread so keep |weak_this_| ready to copy.
+  base::WeakPtr<ProxyResolverErrorObserverMojo> weak_this_;
+  base::WeakPtrFactory<ProxyResolverErrorObserverMojo> weak_factory_;
+};
+
+}  // namespace net
+
+#endif  // NET_PROXY_PROXY_RESOLVER_ERROR_OBSERVER_MOJO_H_
diff --git a/net/proxy/proxy_resolver_error_observer_mojo_unittest.cc b/net/proxy/proxy_resolver_error_observer_mojo_unittest.cc
new file mode 100644
index 0000000..d28bd059
--- /dev/null
+++ b/net/proxy/proxy_resolver_error_observer_mojo_unittest.cc
@@ -0,0 +1,103 @@
+// 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 "net/proxy/proxy_resolver_error_observer_mojo.h"
+
+#include <utility>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread.h"
+#include "mojo/common/common_type_converters.h"
+#include "net/test/event_waiter.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+namespace {
+
+class ErrorObserverClient : public interfaces::ProxyResolverErrorObserver {
+ public:
+  enum Event {
+    ERROR_RECEIVED,
+  };
+
+  explicit ErrorObserverClient(
+      mojo::InterfaceRequest<interfaces::ProxyResolverErrorObserver> request);
+
+  EventWaiter<Event>& event_waiter() { return event_waiter_; }
+  const std::vector<std::pair<int, base::string16>>& errors() const {
+    return errors_;
+  }
+
+ private:
+  void OnPacScriptError(int32_t line_number,
+                        const mojo::String& error) override;
+
+  mojo::Binding<interfaces::ProxyResolverErrorObserver> binding_;
+  EventWaiter<Event> event_waiter_;
+  std::vector<std::pair<int, base::string16>> errors_;
+
+  DISALLOW_COPY_AND_ASSIGN(ErrorObserverClient);
+};
+
+ErrorObserverClient::ErrorObserverClient(
+    mojo::InterfaceRequest<interfaces::ProxyResolverErrorObserver> request)
+    : binding_(this, request.Pass()) {
+}
+
+void ErrorObserverClient::OnPacScriptError(int32_t line_number,
+                                           const mojo::String& error) {
+  errors_.push_back(std::make_pair(line_number, error.To<base::string16>()));
+  event_waiter_.NotifyEvent(ERROR_RECEIVED);
+}
+
+}  // namespace
+
+class ProxyResolverErrorObserverMojoTest : public testing::Test {
+ public:
+  ProxyResolverErrorObserver& error_observer() { return *error_observer_; }
+  ErrorObserverClient& client() { return *client_; }
+
+ private:
+  void SetUp() override {
+    interfaces::ProxyResolverErrorObserverPtr error_observer_ptr;
+    client_.reset(new ErrorObserverClient(mojo::GetProxy(&error_observer_ptr)));
+    error_observer_ =
+        ProxyResolverErrorObserverMojo::Create(error_observer_ptr.Pass());
+    ASSERT_TRUE(error_observer_);
+  }
+
+  scoped_ptr<ErrorObserverClient> client_;
+  scoped_ptr<ProxyResolverErrorObserver> error_observer_;
+};
+
+TEST_F(ProxyResolverErrorObserverMojoTest, NullHandle) {
+  EXPECT_FALSE(ProxyResolverErrorObserverMojo::Create(
+      interfaces::ProxyResolverErrorObserverPtr()));
+}
+
+TEST_F(ProxyResolverErrorObserverMojoTest, ErrorReportedOnMainThread) {
+  base::string16 error(base::ASCIIToUTF16("error message"));
+  error_observer().OnPACScriptError(123, error);
+  client().event_waiter().WaitForEvent(ErrorObserverClient::ERROR_RECEIVED);
+  ASSERT_EQ(1u, client().errors().size());
+  EXPECT_EQ(123, client().errors()[0].first);
+  EXPECT_EQ(error, client().errors()[0].second);
+}
+
+TEST_F(ProxyResolverErrorObserverMojoTest, ErrorReportedOnAnotherThread) {
+  base::Thread other_thread("error reporting thread");
+  base::string16 error(base::ASCIIToUTF16("error message"));
+  other_thread.Start();
+  other_thread.message_loop()->PostTask(
+      FROM_HERE, base::Bind(&ProxyResolverErrorObserver::OnPACScriptError,
+                            base::Unretained(&error_observer()), 123, error));
+  client().event_waiter().WaitForEvent(ErrorObserverClient::ERROR_RECEIVED);
+  ASSERT_EQ(1u, client().errors().size());
+  EXPECT_EQ(123, client().errors()[0].first);
+  EXPECT_EQ(error, client().errors()[0].second);
+}
+
+}  // namespace net
diff --git a/net/proxy/proxy_resolver_mojo.cc b/net/proxy/proxy_resolver_mojo.cc
index c676827..c0e38fb2 100644
--- a/net/proxy/proxy_resolver_mojo.cc
+++ b/net/proxy/proxy_resolver_mojo.cc
@@ -4,20 +4,123 @@
 
 #include "net/proxy/proxy_resolver_mojo.h"
 
+#include <set>
+
 #include "base/bind.h"
 #include "base/logging.h"
 #include "base/stl_util.h"
+#include "base/threading/thread_checker.h"
 #include "mojo/common/common_type_converters.h"
 #include "mojo/common/url_type_converters.h"
+#include "net/base/load_states.h"
 #include "net/base/net_errors.h"
 #include "net/dns/mojo_host_resolver_impl.h"
+#include "net/interfaces/host_resolver_service.mojom.h"
+#include "net/interfaces/proxy_resolver_service.mojom.h"
 #include "net/proxy/mojo_proxy_resolver_factory.h"
 #include "net/proxy/mojo_proxy_type_converters.h"
 #include "net/proxy/proxy_info.h"
+#include "net/proxy/proxy_resolver.h"
+#include "net/proxy/proxy_resolver_error_observer.h"
+#include "net/proxy/proxy_resolver_script_data.h"
 #include "third_party/mojo/src/mojo/public/cpp/bindings/binding.h"
 #include "third_party/mojo/src/mojo/public/cpp/bindings/error_handler.h"
 
 namespace net {
+namespace {
+
+class ErrorObserverHolder : public interfaces::ProxyResolverErrorObserver {
+ public:
+  ErrorObserverHolder(
+      scoped_ptr<net::ProxyResolverErrorObserver> error_observer,
+      mojo::InterfaceRequest<interfaces::ProxyResolverErrorObserver> request);
+  ~ErrorObserverHolder() override;
+
+  void OnPacScriptError(int32_t line_number,
+                        const mojo::String& error) override;
+
+ private:
+  scoped_ptr<net::ProxyResolverErrorObserver> error_observer_;
+  mojo::Binding<interfaces::ProxyResolverErrorObserver> binding_;
+
+  DISALLOW_COPY_AND_ASSIGN(ErrorObserverHolder);
+};
+
+ErrorObserverHolder::ErrorObserverHolder(
+    scoped_ptr<net::ProxyResolverErrorObserver> error_observer,
+    mojo::InterfaceRequest<interfaces::ProxyResolverErrorObserver> request)
+    : error_observer_(error_observer.Pass()), binding_(this, request.Pass()) {
+}
+
+ErrorObserverHolder::~ErrorObserverHolder() = default;
+
+void ErrorObserverHolder::OnPacScriptError(int32_t line_number,
+                                           const mojo::String& error) {
+  DCHECK(error_observer_);
+  error_observer_->OnPACScriptError(line_number, error.To<base::string16>());
+}
+
+// Implementation of ProxyResolver that connects to a Mojo service to evaluate
+// PAC scripts. This implementation only knows about Mojo services, and
+// therefore that service may live in or out of process.
+//
+// This implementation reports disconnections from the Mojo service (i.e. if the
+// service is out-of-process and that process crashes) using the error code
+// ERR_PAC_SCRIPT_TERMINATED.
+class ProxyResolverMojo : public ProxyResolver, public mojo::ErrorHandler {
+ public:
+  // Constructs a ProxyResolverMojo that connects to a mojo proxy resolver
+  // implementation using |resolver_ptr|. The implementation uses
+  // |host_resolver| as the DNS resolver, using |host_resolver_binding| to
+  // communicate with it. When deleted, the closure contained within
+  // |on_delete_callback_runner| will be run.
+  // TODO(amistry): Add NetLog.
+  ProxyResolverMojo(
+      interfaces::ProxyResolverPtr resolver_ptr,
+      scoped_ptr<interfaces::HostResolver> host_resolver,
+      scoped_ptr<mojo::Binding<interfaces::HostResolver>> host_resolver_binding,
+      scoped_ptr<base::ScopedClosureRunner> on_delete_callback_runner,
+      scoped_ptr<ErrorObserverHolder> error_observer);
+  ~ProxyResolverMojo() override;
+
+  // ProxyResolver implementation:
+  int GetProxyForURL(const GURL& url,
+                     ProxyInfo* results,
+                     const net::CompletionCallback& callback,
+                     RequestHandle* request,
+                     const BoundNetLog& net_log) override;
+  void CancelRequest(RequestHandle request) override;
+  LoadState GetLoadState(RequestHandle request) const override;
+  void CancelSetPacScript() override;
+  int SetPacScript(const scoped_refptr<ProxyResolverScriptData>& pac_script,
+                   const net::CompletionCallback& callback) override;
+
+ private:
+  class Job;
+
+  // Overridden from mojo::ErrorHandler:
+  void OnConnectionError() override;
+
+  void RemoveJob(Job* job);
+
+  // Connection to the Mojo proxy resolver.
+  interfaces::ProxyResolverPtr mojo_proxy_resolver_ptr_;
+
+  // Mojo host resolver service and binding.
+  scoped_ptr<interfaces::HostResolver> mojo_host_resolver_;
+  scoped_ptr<mojo::Binding<interfaces::HostResolver>>
+      mojo_host_resolver_binding_;
+
+  scoped_ptr<ErrorObserverHolder> error_observer_;
+
+  std::set<Job*> pending_jobs_;
+
+  base::ThreadChecker thread_checker_;
+
+  scoped_ptr<base::ScopedClosureRunner> on_delete_callback_runner_;
+
+  DISALLOW_COPY_AND_ASSIGN(ProxyResolverMojo);
+};
 
 class ProxyResolverMojo::Job : public interfaces::ProxyResolverRequestClient,
                                public mojo::ErrorHandler {
@@ -114,11 +217,13 @@
     interfaces::ProxyResolverPtr resolver_ptr,
     scoped_ptr<interfaces::HostResolver> host_resolver,
     scoped_ptr<mojo::Binding<interfaces::HostResolver>> host_resolver_binding,
-    scoped_ptr<base::ScopedClosureRunner> on_delete_callback_runner)
+    scoped_ptr<base::ScopedClosureRunner> on_delete_callback_runner,
+    scoped_ptr<ErrorObserverHolder> error_observer)
     : ProxyResolver(true),
       mojo_proxy_resolver_ptr_(resolver_ptr.Pass()),
       mojo_host_resolver_(host_resolver.Pass()),
       mojo_host_resolver_binding_(host_resolver_binding.Pass()),
+      error_observer_(error_observer.Pass()),
       on_delete_callback_runner_(on_delete_callback_runner.Pass()) {
   mojo_proxy_resolver_ptr_.set_error_handler(this);
 }
@@ -187,6 +292,8 @@
   return job->load_state();
 }
 
+}  // namespace
+
 class ProxyResolverFactoryMojo::Job
     : public interfaces::ProxyResolverFactoryRequestClient,
       public mojo::ErrorHandler,
@@ -205,11 +312,20 @@
             new mojo::Binding<interfaces::HostResolver>(host_resolver_.get())) {
     interfaces::HostResolverPtr host_resolver_ptr;
     interfaces::ProxyResolverFactoryRequestClientPtr client_ptr;
+    interfaces::ProxyResolverErrorObserverPtr error_observer_ptr;
     binding_.Bind(mojo::GetProxy(&client_ptr));
+    if (!factory_->error_observer_factory_.is_null()) {
+      scoped_ptr<ProxyResolverErrorObserver> error_observer =
+          factory_->error_observer_factory_.Run();
+      if (error_observer) {
+        error_observer_.reset(new ErrorObserverHolder(
+            error_observer.Pass(), mojo::GetProxy(&error_observer_ptr)));
+      }
+    }
     host_resolver_binding_->Bind(mojo::GetProxy(&host_resolver_ptr));
     on_delete_callback_runner_ = factory_->mojo_proxy_factory_->CreateResolver(
         mojo::String::From(pac_script->utf16()), mojo::GetProxy(&resolver_ptr_),
-        host_resolver_ptr.Pass(), client_ptr.Pass());
+        host_resolver_ptr.Pass(), error_observer_ptr.Pass(), client_ptr.Pass());
     resolver_ptr_.set_error_handler(this);
     binding_.set_error_handler(this);
   }
@@ -226,7 +342,8 @@
     if (error == OK) {
       resolver_->reset(new ProxyResolverMojo(
           resolver_ptr_.Pass(), host_resolver_.Pass(),
-          host_resolver_binding_.Pass(), on_delete_callback_runner_.Pass()));
+          host_resolver_binding_.Pass(), on_delete_callback_runner_.Pass(),
+          error_observer_.Pass()));
     }
     on_delete_callback_runner_.reset();
     callback_.Run(error);
@@ -240,14 +357,18 @@
   scoped_ptr<interfaces::HostResolver> host_resolver_;
   scoped_ptr<mojo::Binding<interfaces::HostResolver>> host_resolver_binding_;
   scoped_ptr<base::ScopedClosureRunner> on_delete_callback_runner_;
+  scoped_ptr<ErrorObserverHolder> error_observer_;
 };
 
 ProxyResolverFactoryMojo::ProxyResolverFactoryMojo(
     MojoProxyResolverFactory* mojo_proxy_factory,
-    HostResolver* host_resolver)
+    HostResolver* host_resolver,
+    const base::Callback<scoped_ptr<ProxyResolverErrorObserver>()>&
+        error_observer_factory)
     : ProxyResolverFactory(true),
       mojo_proxy_factory_(mojo_proxy_factory),
-      host_resolver_(host_resolver) {
+      host_resolver_(host_resolver),
+      error_observer_factory_(error_observer_factory) {
 }
 
 ProxyResolverFactoryMojo::~ProxyResolverFactoryMojo() = default;
diff --git a/net/proxy/proxy_resolver_mojo.h b/net/proxy/proxy_resolver_mojo.h
index ada4352..7c827462 100644
--- a/net/proxy/proxy_resolver_mojo.h
+++ b/net/proxy/proxy_resolver_mojo.h
@@ -5,95 +5,27 @@
 #ifndef NET_PROXY_PROXY_RESOLVER_MOJO_H_
 #define NET_PROXY_PROXY_RESOLVER_MOJO_H_
 
-#include <set>
-
-#include "base/callback_helpers.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/threading/thread_checker.h"
 #include "net/base/completion_callback.h"
-#include "net/base/load_states.h"
-#include "net/interfaces/host_resolver_service.mojom.h"
-#include "net/interfaces/proxy_resolver_service.mojom.h"
-#include "net/proxy/proxy_resolver.h"
 #include "net/proxy/proxy_resolver_factory.h"
-#include "net/proxy/proxy_resolver_script_data.h"
 #include "third_party/mojo/src/mojo/public/cpp/bindings/binding.h"
 
-class GURL;
-
 namespace net {
-
-class BoundNetLog;
 class HostResolver;
-class ProxyInfo;
+class ProxyResolverErrorObserver;
+class ProxyResolverScriptData;
 class MojoProxyResolverFactory;
 
-// Implementation of ProxyResolver that connects to a Mojo service to evaluate
-// PAC scripts. This implementation only knows about Mojo services, and
-// therefore that service may live in or out of process.
-//
-// This implementation reports disconnections from the Mojo service (i.e. if the
-// service is out-of-process and that process crashes) using the error code
-// ERR_PAC_SCRIPT_TERMINATED.
-class ProxyResolverMojo : public ProxyResolver, public mojo::ErrorHandler {
- public:
-  // Constructs a ProxyResolverMojo that connects to a mojo proxy resolver
-  // implementation using |resolver_ptr|. The implementation uses
-  // |host_resolver| as the DNS resolver, using |host_resolver_binding| to
-  // communicate with it. When deleted, the closure contained within
-  // |on_delete_callback_runner| will be run.
-  // TODO(amistry): Add ProxyResolverErrorObserver and NetLog.
-  ProxyResolverMojo(
-      interfaces::ProxyResolverPtr resolver_ptr,
-      scoped_ptr<interfaces::HostResolver> host_resolver,
-      scoped_ptr<mojo::Binding<interfaces::HostResolver>> host_resolver_binding,
-      scoped_ptr<base::ScopedClosureRunner> on_delete_callback_runner);
-  ~ProxyResolverMojo() override;
-
-  // ProxyResolver implementation:
-  int GetProxyForURL(const GURL& url,
-                     ProxyInfo* results,
-                     const net::CompletionCallback& callback,
-                     RequestHandle* request,
-                     const BoundNetLog& net_log) override;
-  void CancelRequest(RequestHandle request) override;
-  LoadState GetLoadState(RequestHandle request) const override;
-  void CancelSetPacScript() override;
-  int SetPacScript(const scoped_refptr<ProxyResolverScriptData>& pac_script,
-                   const net::CompletionCallback& callback) override;
-
- private:
-  class Job;
-
-  // Overridden from mojo::ErrorHandler:
-  void OnConnectionError() override;
-
-  void RemoveJob(Job* job);
-
-  // Connection to the Mojo proxy resolver.
-  interfaces::ProxyResolverPtr mojo_proxy_resolver_ptr_;
-
-  // Mojo host resolver service and binding.
-  scoped_ptr<interfaces::HostResolver> mojo_host_resolver_;
-  scoped_ptr<mojo::Binding<interfaces::HostResolver>>
-      mojo_host_resolver_binding_;
-
-  std::set<Job*> pending_jobs_;
-
-  base::ThreadChecker thread_checker_;
-
-  scoped_ptr<base::ScopedClosureRunner> on_delete_callback_runner_;
-
-  DISALLOW_COPY_AND_ASSIGN(ProxyResolverMojo);
-};
-
 // Implementation of ProxyResolverFactory that connects to a Mojo service to
 // create implementations of a Mojo proxy resolver to back a ProxyResolverMojo.
 class ProxyResolverFactoryMojo : public ProxyResolverFactory {
  public:
-  ProxyResolverFactoryMojo(MojoProxyResolverFactory* mojo_proxy_factory,
-                           HostResolver* host_resolver);
+  ProxyResolverFactoryMojo(
+      MojoProxyResolverFactory* mojo_proxy_factory,
+      HostResolver* host_resolver,
+      const base::Callback<scoped_ptr<ProxyResolverErrorObserver>()>&
+          error_observer_factory);
   ~ProxyResolverFactoryMojo() override;
 
   // ProxyResolverFactory override.
@@ -108,6 +40,8 @@
 
   MojoProxyResolverFactory* const mojo_proxy_factory_;
   HostResolver* const host_resolver_;
+  const base::Callback<scoped_ptr<ProxyResolverErrorObserver>()>
+      error_observer_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(ProxyResolverFactoryMojo);
 };
diff --git a/net/proxy/proxy_resolver_mojo_unittest.cc b/net/proxy/proxy_resolver_mojo_unittest.cc
index 83bdf004..a99e755 100644
--- a/net/proxy/proxy_resolver_mojo_unittest.cc
+++ b/net/proxy/proxy_resolver_mojo_unittest.cc
@@ -15,12 +15,15 @@
 #include "base/run_loop.h"
 #include "base/stl_util.h"
 #include "mojo/common/common_type_converters.h"
+#include "net/base/load_states.h"
 #include "net/base/net_errors.h"
 #include "net/base/test_completion_callback.h"
 #include "net/log/net_log.h"
 #include "net/proxy/mojo_proxy_resolver_factory.h"
 #include "net/proxy/mojo_proxy_type_converters.h"
 #include "net/proxy/proxy_info.h"
+#include "net/proxy/proxy_resolver.h"
+#include "net/proxy/proxy_resolver_error_observer.h"
 #include "net/proxy/proxy_resolver_script_data.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/mojo/src/mojo/public/cpp/bindings/binding.h"
@@ -316,6 +319,7 @@
       const mojo::String& pac_url,
       mojo::InterfaceRequest<interfaces::ProxyResolver> request,
       interfaces::HostResolverPtr host_resolver,
+      interfaces::ProxyResolverErrorObserverPtr error_observer,
       interfaces::ProxyResolverFactoryRequestClientPtr client) override;
 
   void WakeWaiter();
@@ -368,6 +372,7 @@
     const mojo::String& pac_script,
     mojo::InterfaceRequest<interfaces::ProxyResolver> request,
     interfaces::HostResolverPtr host_resolver,
+    interfaces::ProxyResolverErrorObserverPtr error_observer,
     interfaces::ProxyResolverFactoryRequestClientPtr client) {
   ASSERT_FALSE(create_resolver_actions_.empty());
   CreateProxyResolverAction action = create_resolver_actions_.front();
@@ -409,8 +414,9 @@
   void SetUp() override {
     mock_proxy_resolver_factory_.reset(new MockMojoProxyResolverFactory(
         &mock_proxy_resolver_, mojo::GetProxy(&factory_ptr_)));
-    proxy_resolver_factory_mojo_.reset(
-        new ProxyResolverFactoryMojo(this, nullptr));
+    proxy_resolver_factory_mojo_.reset(new ProxyResolverFactoryMojo(
+        this, nullptr,
+        base::Callback<scoped_ptr<ProxyResolverErrorObserver>()>()));
   }
 
   scoped_ptr<Request> MakeRequest(const GURL& url) {
@@ -421,9 +427,10 @@
       const mojo::String& pac_script,
       mojo::InterfaceRequest<interfaces::ProxyResolver> req,
       interfaces::HostResolverPtr host_resolver,
+      interfaces::ProxyResolverErrorObserverPtr error_observer,
       interfaces::ProxyResolverFactoryRequestClientPtr client) override {
     factory_ptr_->CreateResolver(pac_script, req.Pass(), host_resolver.Pass(),
-                                 client.Pass());
+                                 error_observer.Pass(), client.Pass());
     return make_scoped_ptr(
         new base::ScopedClosureRunner(on_delete_callback_.closure()));
   }
diff --git a/net/proxy/proxy_resolver_v8_tracing.cc b/net/proxy/proxy_resolver_v8_tracing.cc
index 921cd55..448a512 100644
--- a/net/proxy/proxy_resolver_v8_tracing.cc
+++ b/net/proxy/proxy_resolver_v8_tracing.cc
@@ -4,6 +4,10 @@
 
 #include "net/proxy/proxy_resolver_v8_tracing.h"
 
+#include <map>
+#include <string>
+#include <vector>
+
 #include "base/bind.h"
 #include "base/single_thread_task_runner.h"
 #include "base/strings/stringprintf.h"
@@ -64,10 +68,9 @@
   return dict;
 }
 
-}  // namespace
-
 // The Job class is responsible for executing GetProxyForURL() and
-// SetPacScript(), since both of these operations share similar code.
+// creating ProxyResolverV8 instances, since both of these operations share
+// similar code.
 //
 // The DNS for these operations can operate in either blocking or
 // non-blocking mode. Blocking mode is used as a fallback when the PAC script
@@ -80,17 +83,41 @@
 // The lifetime of Jobs does not exceed that of the ProxyResolverV8Tracing that
 // spawned it. Destruction might happen on either the origin thread or the
 // worker thread.
-class ProxyResolverV8Tracing::Job
-    : public base::RefCountedThreadSafe<ProxyResolverV8Tracing::Job>,
-      public ProxyResolverV8::JSBindings {
+class Job : public base::RefCountedThreadSafe<Job>,
+            public ProxyResolverV8::JSBindings {
  public:
-  // |parent| is non-owned. It is the ProxyResolverV8Tracing that spawned this
-  // Job, and must oulive it.
-  explicit Job(ProxyResolverV8Tracing* parent);
+  struct Params {
+    Params(
+        const scoped_refptr<base::SingleThreadTaskRunner>& worker_task_runner,
+        HostResolver* host_resolver,
+        ProxyResolverErrorObserver* error_observer,
+        NetLog* net_log,
+        ProxyResolver::LoadStateChangedCallback on_load_state_changed,
+        int* num_outstanding_callbacks)
+        : v8_resolver(nullptr),
+          worker_task_runner(worker_task_runner),
+          host_resolver(host_resolver),
+          error_observer(error_observer),
+          net_log(net_log),
+          on_load_state_changed(on_load_state_changed),
+          num_outstanding_callbacks(num_outstanding_callbacks) {}
+
+    ProxyResolverV8* v8_resolver;
+    scoped_refptr<base::SingleThreadTaskRunner> worker_task_runner;
+    HostResolver* host_resolver;
+    ProxyResolverErrorObserver* error_observer;
+    NetLog* net_log;
+    ProxyResolver::LoadStateChangedCallback on_load_state_changed;
+    int* num_outstanding_callbacks;
+  };
+  // |params| is non-owned. It contains the parameters for this Job, and must
+  // outlive it.
+  explicit Job(const Params* params);
 
   // Called from origin thread.
-  void StartSetPacScript(
+  void StartCreateV8Resolver(
       const scoped_refptr<ProxyResolverScriptData>& script_data,
+      scoped_ptr<ProxyResolverV8>* resolver,
       const CompletionCallback& callback);
 
   // Called from origin thread.
@@ -107,10 +134,10 @@
 
  private:
   typedef std::map<std::string, std::string> DnsCache;
-  friend class base::RefCountedThreadSafe<ProxyResolverV8Tracing::Job>;
+  friend class base::RefCountedThreadSafe<Job>;
 
   enum Operation {
-    SET_PAC_SCRIPT,
+    CREATE_V8_RESOLVER,
     GET_PROXY_FOR_URL,
   };
 
@@ -129,7 +156,7 @@
   void ReleaseCallback();
 
   ProxyResolverV8* v8_resolver();
-  base::MessageLoop* worker_loop();
+  const scoped_refptr<base::SingleThreadTaskRunner>& worker_task_runner();
   HostResolver* host_resolver();
   ProxyResolverErrorObserver* error_observer();
   NetLog* net_log();
@@ -203,9 +230,9 @@
   // completion callback is expected to run.
   scoped_refptr<base::SingleThreadTaskRunner> origin_runner_;
 
-  // The ProxyResolverV8Tracing which spawned this Job.
+  // The Parameters for this Job.
   // Initialized on origin thread and then accessed from both threads.
-  ProxyResolverV8Tracing* parent_;
+  const Params* const params_;
 
   // The callback to run (on the origin thread) when the Job finishes.
   // Should only be accessed from origin thread.
@@ -236,10 +263,11 @@
   scoped_refptr<Job> owned_self_reference_;
 
   // -------------------------------------------------------
-  // State specific to SET_PAC_SCRIPT.
+  // State specific to CREATE_V8_RESOLVER.
   // -------------------------------------------------------
 
   scoped_refptr<ProxyResolverScriptData> script_data_;
+  scoped_ptr<ProxyResolverV8>* resolver_out_;
 
   // -------------------------------------------------------
   // State specific to GET_PROXY_FOR_URL.
@@ -295,34 +323,82 @@
   AddressList pending_dns_addresses_;
 };
 
-ProxyResolverV8Tracing::Job::Job(ProxyResolverV8Tracing* parent)
+class ProxyResolverV8Tracing : public ProxyResolver,
+                               public base::NonThreadSafe {
+ public:
+  // Constructs a ProxyResolver that will issue DNS requests through
+  // |job_params->host_resolver|, forward Javascript errors through
+  // |error_observer|, and log Javascript errors and alerts to
+  // |job_params->net_log|. When the LoadState for a request changes,
+  // |job_params->on_load_state_changed| will be invoked with the RequestHandle
+  // for that request with the new LoadState.
+  //
+  // Note that the constructor takes ownership of |error_observer|, whereas
+  // |job_params->host_resolver| and |job_params->net_log| are expected to
+  // outlive |this|.
+  ProxyResolverV8Tracing(scoped_ptr<ProxyResolverErrorObserver> error_observer,
+                         scoped_ptr<base::Thread> thread,
+                         scoped_ptr<ProxyResolverV8> resolver,
+                         scoped_ptr<Job::Params> job_params);
+
+  ~ProxyResolverV8Tracing() override;
+
+  // ProxyResolver implementation:
+  int GetProxyForURL(const GURL& url,
+                     ProxyInfo* results,
+                     const CompletionCallback& callback,
+                     RequestHandle* request,
+                     const BoundNetLog& net_log) override;
+  void CancelRequest(RequestHandle request) override;
+  LoadState GetLoadState(RequestHandle request) const override;
+  void CancelSetPacScript() override;
+  int SetPacScript(const scoped_refptr<ProxyResolverScriptData>& script_data,
+                   const CompletionCallback& callback) override;
+
+ private:
+  // The worker thread on which the ProxyResolverV8 will be run.
+  scoped_ptr<base::Thread> thread_;
+  scoped_ptr<ProxyResolverV8> v8_resolver_;
+
+  scoped_ptr<ProxyResolverErrorObserver> error_observer_;
+
+  scoped_ptr<Job::Params> job_params_;
+
+  // The number of outstanding (non-cancelled) jobs.
+  int num_outstanding_callbacks_;
+
+  DISALLOW_COPY_AND_ASSIGN(ProxyResolverV8Tracing);
+};
+
+Job::Job(const Job::Params* params)
     : origin_runner_(base::ThreadTaskRunnerHandle::Get()),
-      parent_(parent),
+      params_(params),
       event_(true, false),
       last_num_dns_(0),
       pending_dns_(NULL) {
   CheckIsOnOriginThread();
 }
 
-void ProxyResolverV8Tracing::Job::StartSetPacScript(
+void Job::StartCreateV8Resolver(
     const scoped_refptr<ProxyResolverScriptData>& script_data,
+    scoped_ptr<ProxyResolverV8>* resolver,
     const CompletionCallback& callback) {
   CheckIsOnOriginThread();
 
+  resolver_out_ = resolver;
   script_data_ = script_data;
 
   // Script initialization uses blocking DNS since there isn't any
   // advantage to using non-blocking mode here. That is because the
   // parent ProxyService can't submit any ProxyResolve requests until
   // initialization has completed successfully!
-  Start(SET_PAC_SCRIPT, true /*blocking*/, callback);
+  Start(CREATE_V8_RESOLVER, true /*blocking*/, callback);
 }
 
-void ProxyResolverV8Tracing::Job::StartGetProxyForURL(
-    const GURL& url,
-    ProxyInfo* results,
-    const BoundNetLog& net_log,
-    const CompletionCallback& callback) {
+void Job::StartGetProxyForURL(const GURL& url,
+                              ProxyInfo* results,
+                              const BoundNetLog& net_log,
+                              const CompletionCallback& callback) {
   CheckIsOnOriginThread();
 
   url_ = url;
@@ -332,7 +408,7 @@
   Start(GET_PROXY_FOR_URL, false /*non-blocking*/, callback);
 }
 
-void ProxyResolverV8Tracing::Job::Cancel() {
+void Job::Cancel() {
   CheckIsOnOriginThread();
 
   // There are several possibilities to consider for cancellation:
@@ -367,7 +443,7 @@
   owned_self_reference_ = NULL;
 }
 
-LoadState ProxyResolverV8Tracing::Job::GetLoadState() const {
+LoadState Job::GetLoadState() const {
   CheckIsOnOriginThread();
 
   if (pending_dns_)
@@ -376,66 +452,65 @@
   return LOAD_STATE_RESOLVING_PROXY_FOR_URL;
 }
 
-ProxyResolverV8Tracing::Job::~Job() {
+Job::~Job() {
   DCHECK(!pending_dns_);
   DCHECK(callback_.is_null());
 }
 
-void ProxyResolverV8Tracing::Job::CheckIsOnWorkerThread() const {
-  DCHECK_EQ(base::MessageLoop::current(), parent_->thread_->message_loop());
+void Job::CheckIsOnWorkerThread() const {
+  DCHECK(params_->worker_task_runner->BelongsToCurrentThread());
 }
 
-void ProxyResolverV8Tracing::Job::CheckIsOnOriginThread() const {
+void Job::CheckIsOnOriginThread() const {
   DCHECK(origin_runner_->BelongsToCurrentThread());
 }
 
-void ProxyResolverV8Tracing::Job::SetCallback(
-    const CompletionCallback& callback) {
+void Job::SetCallback(const CompletionCallback& callback) {
   CheckIsOnOriginThread();
   DCHECK(callback_.is_null());
-  parent_->num_outstanding_callbacks_++;
+  (*params_->num_outstanding_callbacks)++;
   callback_ = callback;
 }
 
-void ProxyResolverV8Tracing::Job::ReleaseCallback() {
+void Job::ReleaseCallback() {
   CheckIsOnOriginThread();
   DCHECK(!callback_.is_null());
-  CHECK_GT(parent_->num_outstanding_callbacks_, 0);
-  parent_->num_outstanding_callbacks_--;
+  CHECK_GT(*params_->num_outstanding_callbacks, 0);
+  (*params_->num_outstanding_callbacks)--;
   callback_.Reset();
 
   // For good measure, clear this other user-owned pointer.
   user_results_ = NULL;
 }
 
-ProxyResolverV8* ProxyResolverV8Tracing::Job::v8_resolver() {
-  return parent_->v8_resolver_.get();
+ProxyResolverV8* Job::v8_resolver() {
+  return params_->v8_resolver;
 }
 
-base::MessageLoop* ProxyResolverV8Tracing::Job::worker_loop() {
-  return parent_->thread_->message_loop();
+const scoped_refptr<base::SingleThreadTaskRunner>& Job::worker_task_runner() {
+  return params_->worker_task_runner;
 }
 
-HostResolver* ProxyResolverV8Tracing::Job::host_resolver() {
-  return parent_->host_resolver_;
+HostResolver* Job::host_resolver() {
+  return params_->host_resolver;
 }
 
-ProxyResolverErrorObserver* ProxyResolverV8Tracing::Job::error_observer() {
-  return parent_->error_observer_.get();
+ProxyResolverErrorObserver* Job::error_observer() {
+  return params_->error_observer;
 }
 
-NetLog* ProxyResolverV8Tracing::Job::net_log() {
-  return parent_->net_log_;
+NetLog* Job::net_log() {
+  return params_->net_log;
 }
 
-void ProxyResolverV8Tracing::Job::NotifyCaller(int result) {
+void Job::NotifyCaller(int result) {
   CheckIsOnWorkerThread();
 
   origin_runner_->PostTask(
       FROM_HERE, base::Bind(&Job::NotifyCallerOnOriginLoop, this, result));
 }
 
-void ProxyResolverV8Tracing::Job::NotifyCallerOnOriginLoop(int result) {
+void Job::NotifyCallerOnOriginLoop(int result) {
   CheckIsOnOriginThread();
 
   if (cancelled_.IsSet())
@@ -448,13 +523,6 @@
     *user_results_ = results_;
   }
 
-  // There is only ever 1 outstanding SET_PAC_SCRIPT job. It needs to be
-  // tracked to support cancellation.
-  if (operation_ == SET_PAC_SCRIPT) {
-    DCHECK_EQ(parent_->set_pac_script_job_.get(), this);
-    parent_->set_pac_script_job_ = NULL;
-  }
-
   CompletionCallback callback = callback_;
   ReleaseCallback();
   callback.Run(result);
@@ -462,8 +530,9 @@
   owned_self_reference_ = NULL;
 }
 
-void ProxyResolverV8Tracing::Job::Start(Operation op, bool blocking_dns,
-                                        const CompletionCallback& callback) {
+void Job::Start(Operation op,
+                bool blocking_dns,
+                const CompletionCallback& callback) {
   CheckIsOnOriginThread();
 
   operation_ = op;
@@ -472,12 +541,12 @@
 
   owned_self_reference_ = this;
 
-  worker_loop()->PostTask(FROM_HERE,
-      blocking_dns_ ? base::Bind(&Job::ExecuteBlocking, this) :
-                      base::Bind(&Job::ExecuteNonBlocking, this));
+  worker_task_runner()->PostTask(
+      FROM_HERE, blocking_dns_ ? base::Bind(&Job::ExecuteBlocking, this)
+                               : base::Bind(&Job::ExecuteNonBlocking, this));
 }
 
-void ProxyResolverV8Tracing::Job::ExecuteBlocking() {
+void Job::ExecuteBlocking() {
   CheckIsOnWorkerThread();
   DCHECK(blocking_dns_);
 
@@ -487,7 +556,7 @@
   NotifyCaller(ExecuteProxyResolver());
 }
 
-void ProxyResolverV8Tracing::Job::ExecuteNonBlocking() {
+void Job::ExecuteNonBlocking() {
   CheckIsOnWorkerThread();
   DCHECK(!blocking_dns_);
 
@@ -518,18 +587,23 @@
   NotifyCaller(result);
 }
 
-int ProxyResolverV8Tracing::Job::ExecuteProxyResolver() {
-  JSBindings* prev_bindings = v8_resolver()->js_bindings();
-  v8_resolver()->set_js_bindings(this);
-
+int Job::ExecuteProxyResolver() {
   int result = ERR_UNEXPECTED;  // Initialized to silence warnings.
 
   switch (operation_) {
-    case SET_PAC_SCRIPT:
-      result = v8_resolver()->SetPacScript(
-          script_data_, CompletionCallback());
+    case CREATE_V8_RESOLVER: {
+      scoped_ptr<ProxyResolverV8> resolver(new ProxyResolverV8);
+      resolver->set_js_bindings(this);
+      result = resolver->SetPacScript(script_data_, CompletionCallback());
+      resolver->set_js_bindings(nullptr);
+      if (result == OK)
+        *resolver_out_ = resolver.Pass();
       break;
-    case GET_PROXY_FOR_URL:
+    }
+    case GET_PROXY_FOR_URL: {
+      JSBindings* prev_bindings = v8_resolver()->js_bindings();
+      v8_resolver()->set_js_bindings(this);
+
       result = v8_resolver()->GetProxyForURL(
         url_,
         // Important: Do not write directly into |user_results_|, since if the
@@ -539,18 +613,18 @@
         CompletionCallback(),
         NULL,
         bound_net_log_);
+      v8_resolver()->set_js_bindings(prev_bindings);
       break;
+    }
   }
 
-  v8_resolver()->set_js_bindings(prev_bindings);
-
   return result;
 }
 
-bool ProxyResolverV8Tracing::Job::ResolveDns(const std::string& host,
-                                             ResolveDnsOperation op,
-                                             std::string* output,
-                                             bool* terminate) {
+bool Job::ResolveDns(const std::string& host,
+                     ResolveDnsOperation op,
+                     std::string* output,
+                     bool* terminate) {
   if (cancelled_.IsSet()) {
     *terminate = true;
     return false;
@@ -566,18 +640,17 @@
       ResolveDnsNonBlocking(host, op, output, terminate);
 }
 
-void ProxyResolverV8Tracing::Job::Alert(const base::string16& message) {
+void Job::Alert(const base::string16& message) {
   HandleAlertOrError(true, -1, message);
 }
 
-void ProxyResolverV8Tracing::Job::OnError(int line_number,
-                                          const base::string16& error) {
+void Job::OnError(int line_number, const base::string16& error) {
   HandleAlertOrError(false, line_number, error);
 }
 
-bool ProxyResolverV8Tracing::Job::ResolveDnsBlocking(const std::string& host,
-                                                     ResolveDnsOperation op,
-                                                     std::string* output) {
+bool Job::ResolveDnsBlocking(const std::string& host,
+                             ResolveDnsOperation op,
+                             std::string* output) {
   CheckIsOnWorkerThread();
 
   // Check if the DNS result for this host has already been cached.
@@ -601,10 +674,10 @@
   return rv;
 }
 
-bool ProxyResolverV8Tracing::Job::ResolveDnsNonBlocking(const std::string& host,
-                                                        ResolveDnsOperation op,
-                                                        std::string* output,
-                                                        bool* terminate) {
+bool Job::ResolveDnsNonBlocking(const std::string& host,
+                                ResolveDnsOperation op,
+                                std::string* output,
+                                bool* terminate) {
   CheckIsOnWorkerThread();
 
   if (abandoned_) {
@@ -654,10 +727,9 @@
   return false;
 }
 
-bool ProxyResolverV8Tracing::Job::PostDnsOperationAndWait(
-    const std::string& host, ResolveDnsOperation op,
-    bool* completed_synchronously) {
-
+bool Job::PostDnsOperationAndWait(const std::string& host,
+                                  ResolveDnsOperation op,
+                                  bool* completed_synchronously) {
   // Post the DNS request to the origin thread.
   DCHECK(!pending_dns_);
   pending_dns_host_ = host;
@@ -676,7 +748,7 @@
   return true;
 }
 
-void ProxyResolverV8Tracing::Job::DoDnsOperation() {
+void Job::DoDnsOperation() {
   CheckIsOnOriginThread();
   DCHECK(!pending_dns_);
 
@@ -708,8 +780,8 @@
   } else {
     DCHECK(dns_request);
     pending_dns_ = dns_request;
-    if (!parent_->on_load_state_changed_.is_null()) {
-      parent_->on_load_state_changed_.Run(
+    if (!params_->on_load_state_changed.is_null()) {
+      params_->on_load_state_changed.Run(
           this, LOAD_STATE_RESOLVING_HOST_IN_PROXY_SCRIPT);
     }
     // OnDnsOperationComplete() will be called by host resolver on completion.
@@ -722,7 +794,7 @@
   }
 }
 
-void ProxyResolverV8Tracing::Job::OnDnsOperationComplete(int result) {
+void Job::OnDnsOperationComplete(int result) {
   CheckIsOnOriginThread();
 
   DCHECK(!cancelled_.IsSet());
@@ -732,10 +804,10 @@
                       pending_dns_addresses_);
   pending_dns_ = NULL;
 
-  if (!parent_->on_load_state_changed_.is_null() &&
+  if (!params_->on_load_state_changed.is_null() &&
       !pending_dns_completed_synchronously_ && !cancelled_.IsSet()) {
-    parent_->on_load_state_changed_.Run(this,
-                                        LOAD_STATE_RESOLVING_PROXY_FOR_URL);
+    params_->on_load_state_changed.Run(this,
+                                       LOAD_STATE_RESOLVING_PROXY_FOR_URL);
   }
 
   if (blocking_dns_) {
@@ -746,12 +818,12 @@
   if (!blocking_dns_ && !pending_dns_completed_synchronously_) {
     // Restart. This time it should make more progress due to having
     // cached items.
-    worker_loop()->PostTask(FROM_HERE,
-                            base::Bind(&Job::ExecuteNonBlocking, this));
+    worker_task_runner()->PostTask(FROM_HERE,
+                                   base::Bind(&Job::ExecuteNonBlocking, this));
   }
 }
 
-void ProxyResolverV8Tracing::Job::ScheduleRestartWithBlockingDns() {
+void Job::ScheduleRestartWithBlockingDns() {
   CheckIsOnWorkerThread();
 
   DCHECK(!should_restart_with_blocking_dns_);
@@ -764,11 +836,10 @@
   should_restart_with_blocking_dns_ = true;
 }
 
-bool ProxyResolverV8Tracing::Job::GetDnsFromLocalCache(
-    const std::string& host,
-    ResolveDnsOperation op,
-    std::string* output,
-    bool* return_value) {
+bool Job::GetDnsFromLocalCache(const std::string& host,
+                               ResolveDnsOperation op,
+                               std::string* output,
+                               bool* return_value) {
   CheckIsOnWorkerThread();
 
   DnsCache::const_iterator it = dns_cache_.find(MakeDnsCacheKey(host, op));
@@ -780,11 +851,10 @@
   return true;
 }
 
-void ProxyResolverV8Tracing::Job::SaveDnsToLocalCache(
-    const std::string& host,
-    ResolveDnsOperation op,
-    int net_error,
-    const AddressList& addresses) {
+void Job::SaveDnsToLocalCache(const std::string& host,
+                              ResolveDnsOperation op,
+                              int net_error,
+                              const AddressList& addresses) {
   CheckIsOnOriginThread();
 
   // Serialize the result into a string to save to the cache.
@@ -809,8 +879,8 @@
 }
 
 // static
-HostResolver::RequestInfo ProxyResolverV8Tracing::Job::MakeDnsRequestInfo(
-    const std::string& host, ResolveDnsOperation op) {
+HostResolver::RequestInfo Job::MakeDnsRequestInfo(const std::string& host,
+                                                  ResolveDnsOperation op) {
   HostPortPair host_port = HostPortPair(host, 80);
   if (op == MY_IP_ADDRESS || op == MY_IP_ADDRESS_EX) {
     host_port.set_host(GetHostName());
@@ -831,15 +901,14 @@
   return info;
 }
 
-std::string ProxyResolverV8Tracing::Job::MakeDnsCacheKey(
-    const std::string& host, ResolveDnsOperation op) {
+std::string Job::MakeDnsCacheKey(const std::string& host,
+                                 ResolveDnsOperation op) {
   return base::StringPrintf("%d:%s", op, host.c_str());
 }
 
-void ProxyResolverV8Tracing::Job::HandleAlertOrError(
-    bool is_alert,
-    int line_number,
-    const base::string16& message) {
+void Job::HandleAlertOrError(bool is_alert,
+                             int line_number,
+                             const base::string16& message) {
   CheckIsOnWorkerThread();
 
   if (cancelled_.IsSet())
@@ -871,7 +940,7 @@
   alerts_and_errors_.push_back(entry);
 }
 
-void ProxyResolverV8Tracing::Job::DispatchBufferedAlertsAndErrors() {
+void Job::DispatchBufferedAlertsAndErrors() {
   CheckIsOnWorkerThread();
   DCHECK(!blocking_dns_);
   DCHECK(!abandoned_);
@@ -882,8 +951,9 @@
   }
 }
 
-void ProxyResolverV8Tracing::Job::DispatchAlertOrError(
-    bool is_alert, int line_number, const base::string16& message) {
+void Job::DispatchAlertOrError(bool is_alert,
+                               int line_number,
+                               const base::string16& message) {
   CheckIsOnWorkerThread();
 
   // Note that the handling of cancellation is racy with regard to
@@ -925,7 +995,7 @@
   }
 }
 
-void ProxyResolverV8Tracing::Job::LogEventToCurrentRequestAndGlobally(
+void Job::LogEventToCurrentRequestAndGlobally(
     NetLog::EventType type,
     const NetLog::ParametersCallback& parameters_callback) {
   CheckIsOnWorkerThread();
@@ -937,46 +1007,26 @@
 }
 
 ProxyResolverV8Tracing::ProxyResolverV8Tracing(
-    HostResolver* host_resolver,
-    ProxyResolverErrorObserver* error_observer,
-    NetLog* net_log)
-    : ProxyResolverV8Tracing(host_resolver,
-                             error_observer,
-                             net_log,
-                             LoadStateChangedCallback()) {
-}
-
-ProxyResolverV8Tracing::ProxyResolverV8Tracing(
-    HostResolver* host_resolver,
-    ProxyResolverErrorObserver* error_observer,
-    NetLog* net_log,
-    const LoadStateChangedCallback& on_load_state_changed)
+    scoped_ptr<ProxyResolverErrorObserver> error_observer,
+    scoped_ptr<base::Thread> thread,
+    scoped_ptr<ProxyResolverV8> resolver,
+    scoped_ptr<Job::Params> job_params)
     : ProxyResolver(true /*expects_pac_bytes*/),
-      host_resolver_(host_resolver),
-      error_observer_(error_observer),
-      net_log_(net_log),
-      num_outstanding_callbacks_(0),
-      on_load_state_changed_(on_load_state_changed) {
-  DCHECK(host_resolver);
-  // Start up the thread.
-  thread_.reset(new base::Thread("Proxy resolver"));
-  base::Thread::Options options;
-  options.timer_slack = base::TIMER_SLACK_MAXIMUM;
-  CHECK(thread_->StartWithOptions(options));
-
-  v8_resolver_.reset(new ProxyResolverV8);
+      thread_(thread.Pass()),
+      v8_resolver_(resolver.Pass()),
+      error_observer_(error_observer.Pass()),
+      job_params_(job_params.Pass()),
+      num_outstanding_callbacks_(0) {
+  job_params_->num_outstanding_callbacks = &num_outstanding_callbacks_;
 }
 
 ProxyResolverV8Tracing::~ProxyResolverV8Tracing() {
   // Note, all requests should have been cancelled.
-  CHECK(!set_pac_script_job_.get());
   CHECK_EQ(0, num_outstanding_callbacks_);
 
-  // Join the worker thread. See http://crbug.com/69710. Note that we call
-  // Stop() here instead of simply clearing thread_ since there may be pending
-  // callbacks on the worker thread which want to dereference thread_.
+  // Join the worker thread. See http://crbug.com/69710.
   base::ThreadRestrictions::ScopedAllowIO allow_io;
-  thread_->Stop();
+  thread_.reset();
 }
 
 int ProxyResolverV8Tracing::GetProxyForURL(const GURL& url,
@@ -986,9 +1036,8 @@
                                            const BoundNetLog& net_log) {
   DCHECK(CalledOnValidThread());
   DCHECK(!callback.is_null());
-  DCHECK(!set_pac_script_job_.get());
 
-  scoped_refptr<Job> job = new Job(this);
+  scoped_refptr<Job> job = new Job(job_params_.get());
 
   if (request)
     *request = job.get();
@@ -1008,27 +1057,144 @@
 }
 
 void ProxyResolverV8Tracing::CancelSetPacScript() {
-  DCHECK(set_pac_script_job_.get());
-  set_pac_script_job_->Cancel();
-  set_pac_script_job_ = NULL;
+  NOTREACHED();
 }
 
 int ProxyResolverV8Tracing::SetPacScript(
     const scoped_refptr<ProxyResolverScriptData>& script_data,
     const CompletionCallback& callback) {
-  DCHECK(CalledOnValidThread());
-  DCHECK(!callback.is_null());
+  NOTREACHED();
+  return ERR_NOT_IMPLEMENTED;
+}
 
-  // Note that there should not be any outstanding (non-cancelled) Jobs when
-  // setting the PAC script (ProxyService should guarantee this). If there are,
-  // then they might complete in strange ways after the new script is set.
-  DCHECK(!set_pac_script_job_.get());
-  CHECK_EQ(0, num_outstanding_callbacks_);
+}  // namespace
 
-  set_pac_script_job_ = new Job(this);
-  set_pac_script_job_->StartSetPacScript(script_data, callback);
+class ProxyResolverFactoryV8Tracing::CreateJob
+    : public ProxyResolverFactory::Request {
+ public:
+  CreateJob(ProxyResolverFactoryV8Tracing* factory,
+            HostResolver* host_resolver,
+            scoped_ptr<ProxyResolverErrorObserver> error_observer,
+            NetLog* net_log,
+            const ProxyResolver::LoadStateChangedCallback&
+                load_state_changed_callback,
+            const scoped_refptr<ProxyResolverScriptData>& pac_script,
+            scoped_ptr<ProxyResolver>* resolver_out,
+            const CompletionCallback& callback)
+      : factory_(factory),
+        thread_(new base::Thread("Proxy Resolver")),
+        error_observer_(error_observer.Pass()),
+        resolver_out_(resolver_out),
+        callback_(callback),
+        num_outstanding_callbacks_(0) {
+    // Start up the thread.
+    base::Thread::Options options;
+    options.timer_slack = base::TIMER_SLACK_MAXIMUM;
+    CHECK(thread_->StartWithOptions(options));
+    job_params_.reset(new Job::Params(
+        thread_->task_runner(), host_resolver, error_observer_.get(), net_log,
+        load_state_changed_callback, &num_outstanding_callbacks_));
+    create_resolver_job_ = new Job(job_params_.get());
+    create_resolver_job_->StartCreateV8Resolver(
+        pac_script, &v8_resolver_,
+        base::Bind(
+            &ProxyResolverFactoryV8Tracing::CreateJob::OnV8ResolverCreated,
+            base::Unretained(this)));
+  }
 
+  ~CreateJob() override {
+    if (factory_) {
+      factory_->RemoveJob(this);
+      DCHECK(create_resolver_job_);
+      create_resolver_job_->Cancel();
+      StopWorkerThread();
+    }
+    DCHECK_EQ(0, num_outstanding_callbacks_);
+  }
+
+  void FactoryDestroyed() {
+    factory_ = nullptr;
+    create_resolver_job_->Cancel();
+    create_resolver_job_ = nullptr;
+    StopWorkerThread();
+  }
+
+ private:
+  void OnV8ResolverCreated(int error) {
+    DCHECK(factory_);
+    if (error == OK) {
+      job_params_->v8_resolver = v8_resolver_.get();
+      resolver_out_->reset(
+          new ProxyResolverV8Tracing(error_observer_.Pass(), thread_.Pass(),
+                                     v8_resolver_.Pass(), job_params_.Pass()));
+    } else {
+      StopWorkerThread();
+    }
+
+    factory_->RemoveJob(this);
+    factory_ = nullptr;
+    create_resolver_job_ = nullptr;
+    callback_.Run(error);
+  }
+
+  void StopWorkerThread() {
+    // Join the worker thread. See http://crbug.com/69710.
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
+    thread_.reset();
+  }
+
+  ProxyResolverFactoryV8Tracing* factory_;
+  scoped_ptr<base::Thread> thread_;
+  scoped_ptr<ProxyResolverErrorObserver> error_observer_;
+  scoped_ptr<Job::Params> job_params_;
+  scoped_refptr<Job> create_resolver_job_;
+  scoped_ptr<ProxyResolverV8> v8_resolver_;
+  scoped_ptr<ProxyResolver>* resolver_out_;
+  const CompletionCallback callback_;
+  int num_outstanding_callbacks_;
+
+  DISALLOW_COPY_AND_ASSIGN(CreateJob);
+};
+
+ProxyResolverFactoryV8Tracing::ProxyResolverFactoryV8Tracing(
+    HostResolver* host_resolver,
+    NetLog* net_log,
+    const ProxyResolver::LoadStateChangedCallback& callback,
+    const base::Callback<scoped_ptr<ProxyResolverErrorObserver>()>&
+        error_observer_factory)
+    : ProxyResolverFactory(true),
+      host_resolver_(host_resolver),
+      net_log_(net_log),
+      load_state_changed_callback_(callback),
+      error_observer_factory_(error_observer_factory) {
+}
+
+ProxyResolverFactoryV8Tracing::~ProxyResolverFactoryV8Tracing() {
+  for (auto job : jobs_) {
+    job->FactoryDestroyed();
+  }
+}
+
+// ProxyResolverFactory override.
+int ProxyResolverFactoryV8Tracing::CreateProxyResolver(
+    const scoped_refptr<ProxyResolverScriptData>& pac_script,
+    scoped_ptr<ProxyResolver>* resolver,
+    const CompletionCallback& callback,
+    scoped_ptr<Request>* request) {
+  scoped_ptr<CreateJob> job(new CreateJob(
+      this, host_resolver_,
+      error_observer_factory_.is_null() ? nullptr
+                                        : error_observer_factory_.Run(),
+      net_log_, load_state_changed_callback_, pac_script, resolver, callback));
+  jobs_.insert(job.get());
+  *request = job.Pass();
   return ERR_IO_PENDING;
 }
 
+void ProxyResolverFactoryV8Tracing::RemoveJob(
+    ProxyResolverFactoryV8Tracing::CreateJob* job) {
+  size_t erased = jobs_.erase(job);
+  DCHECK_EQ(1u, erased);
+}
+
 }  // namespace net
diff --git a/net/proxy/proxy_resolver_v8_tracing.h b/net/proxy/proxy_resolver_v8_tracing.h
index 48afd47..c2a9de5 100644
--- a/net/proxy/proxy_resolver_v8_tracing.h
+++ b/net/proxy/proxy_resolver_v8_tracing.h
@@ -5,93 +5,62 @@
 #ifndef NET_PROXY_PROXY_RESOLVER_V8_TRACING_H_
 #define NET_PROXY_PROXY_RESOLVER_V8_TRACING_H_
 
+#include <set>
+
 #include "base/basictypes.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/threading/non_thread_safe.h"
 #include "net/base/net_export.h"
 #include "net/proxy/proxy_resolver.h"
-
-namespace base {
-class Thread;
-class SingleThreadTaskRunner;
-}  // namespace base
+#include "net/proxy/proxy_resolver_factory.h"
 
 namespace net {
 
 class HostResolver;
 class NetLog;
 class ProxyResolverErrorObserver;
-class ProxyResolverV8;
 
-// ProxyResolverV8Tracing is a non-blocking ProxyResolver. It executes
+// ProxyResolverFactoryV8Tracing is a ProxyResolverFactory that returns
+// non-blocking ProxyResolver instances. Each ProxyResolver instance executes
 // ProxyResolverV8 on a single helper thread, and does some magic to avoid
 // blocking in DNS. For more details see the design document:
 // https://docs.google.com/a/google.com/document/d/16Ij5OcVnR3s0MH4Z5XkhI9VTPoMJdaBn9rKreAmGOdE/edit?pli=1
-class NET_EXPORT_PRIVATE ProxyResolverV8Tracing
-    : public ProxyResolver,
-      NON_EXPORTED_BASE(public base::NonThreadSafe) {
+class NET_EXPORT ProxyResolverFactoryV8Tracing : public ProxyResolverFactory {
  public:
-  // Constructs a ProxyResolver that will issue DNS requests through
-  // |host_resolver|, forward Javascript errors through |error_observer|, and
-  // log Javascript errors and alerts to |net_log|.
-  //
-  // Note that the constructor takes ownership of |error_observer|, whereas
-  // |host_resolver| and |net_log| are expected to outlive |this|.
-  ProxyResolverV8Tracing(HostResolver* host_resolver,
-                         ProxyResolverErrorObserver* error_observer,
-                         NetLog* net_log);
+  // Note that |host_resolver| and |net_log| are expected to outlive |this| and
+  // any ProxyResolver instances created using |this|. |error_observer_factory|
+  // will be invoked once per CreateProxyResolver() call to create a
+  // ProxyResolverErrorObserver to be used by the ProxyResolver instance
+  // returned by that call.
+  ProxyResolverFactoryV8Tracing(
+      HostResolver* host_resolver,
+      NetLog* net_log,
+      const ProxyResolver::LoadStateChangedCallback& callback,
+      const base::Callback<scoped_ptr<ProxyResolverErrorObserver>()>&
+          error_observer_factory);
+  ~ProxyResolverFactoryV8Tracing() override;
 
-  // Constructs a ProxyResolver that will issue DNS requests through
-  // |host_resolver|, forward Javascript errors through |error_observer|, and
-  // log Javascript errors and alerts to |net_log|. When the LoadState for a
-  // request changes, |on_load_state_changed| will be invoked with the
-  // RequestHandle for that request with the new LoadState.
-  //
-  // Note that the constructor takes ownership of |error_observer|, whereas
-  // |host_resolver| and |net_log| are expected to outlive |this|.
-  ProxyResolverV8Tracing(HostResolver* host_resolver,
-                         ProxyResolverErrorObserver* error_observer,
-                         NetLog* net_log,
-                         const LoadStateChangedCallback& on_load_state_changed);
-
-  ~ProxyResolverV8Tracing() override;
-
-  // ProxyResolver implementation:
-  int GetProxyForURL(const GURL& url,
-                     ProxyInfo* results,
-                     const CompletionCallback& callback,
-                     RequestHandle* request,
-                     const BoundNetLog& net_log) override;
-  void CancelRequest(RequestHandle request) override;
-  LoadState GetLoadState(RequestHandle request) const override;
-  void CancelSetPacScript() override;
-  int SetPacScript(const scoped_refptr<ProxyResolverScriptData>& script_data,
-                   const CompletionCallback& callback) override;
+  // ProxyResolverFactory override.
+  int CreateProxyResolver(
+      const scoped_refptr<ProxyResolverScriptData>& pac_script,
+      scoped_ptr<ProxyResolver>* resolver,
+      const CompletionCallback& callback,
+      scoped_ptr<Request>* request) override;
 
  private:
-  class Job;
+  class CreateJob;
 
-  // The worker thread on which the ProxyResolverV8 will be run.
-  scoped_ptr<base::Thread> thread_;
-  scoped_ptr<ProxyResolverV8> v8_resolver_;
+  void RemoveJob(CreateJob* job);
 
-  // Non-owned host resolver, which is to be operated on the origin thread.
-  HostResolver* host_resolver_;
+  HostResolver* const host_resolver_;
+  NetLog* const net_log_;
+  const ProxyResolver::LoadStateChangedCallback load_state_changed_callback_;
+  const base::Callback<scoped_ptr<ProxyResolverErrorObserver>()>
+      error_observer_factory_;
 
-  scoped_ptr<ProxyResolverErrorObserver> error_observer_;
-  NetLog* net_log_;
+  std::set<CreateJob*> jobs_;
 
-  // The outstanding SetPacScript operation, or NULL.
-  scoped_refptr<Job> set_pac_script_job_;
-
-  // The number of outstanding (non-cancelled) jobs.
-  int num_outstanding_callbacks_;
-
-  // Invoked when the load state for a request changes.
-  const LoadStateChangedCallback on_load_state_changed_;
-
-  DISALLOW_COPY_AND_ASSIGN(ProxyResolverV8Tracing);
+  DISALLOW_COPY_AND_ASSIGN(ProxyResolverFactoryV8Tracing);
 };
 
 }  // namespace net
diff --git a/net/proxy/proxy_resolver_v8_tracing_unittest.cc b/net/proxy/proxy_resolver_v8_tracing_unittest.cc
index f52b1d4..296853c 100644
--- a/net/proxy/proxy_resolver_v8_tracing_unittest.cc
+++ b/net/proxy/proxy_resolver_v8_tracing_unittest.cc
@@ -4,6 +4,8 @@
 
 #include "net/proxy/proxy_resolver_v8_tracing.h"
 
+#include <string>
+
 #include "base/files/file_util.h"
 #include "base/message_loop/message_loop.h"
 #include "base/path_service.h"
@@ -60,12 +62,28 @@
   return ProxyResolverScriptData::FromUTF8(file_contents);
 }
 
-void InitResolver(ProxyResolverV8Tracing* resolver, const char* filename) {
+scoped_ptr<ProxyResolverErrorObserver> ReturnErrorObserver(
+    scoped_ptr<ProxyResolverErrorObserver> error_observer) {
+  return error_observer;
+}
+
+scoped_ptr<ProxyResolver> CreateResolver(
+    NetLog* net_log,
+    HostResolver* host_resolver,
+    scoped_ptr<ProxyResolverErrorObserver> error_observer,
+    const char* filename) {
+  scoped_ptr<ProxyResolver> resolver;
+  ProxyResolverFactoryV8Tracing factory(
+      host_resolver, net_log, ProxyResolver::LoadStateChangedCallback(),
+      base::Bind(&ReturnErrorObserver, base::Passed(&error_observer)));
   TestCompletionCallback callback;
-  int rv =
-      resolver->SetPacScript(LoadScriptData(filename), callback.callback());
+  scoped_ptr<ProxyResolverFactory::Request> request;
+  int rv = factory.CreateProxyResolver(LoadScriptData(filename), &resolver,
+                                       callback.callback(), &request);
   EXPECT_EQ(ERR_IO_PENDING, rv);
   EXPECT_EQ(OK, callback.WaitForResult());
+  EXPECT_TRUE(resolver);
+  return resolver.Pass();
 }
 
 class MockErrorObserver : public ProxyResolverErrorObserver {
@@ -102,16 +120,16 @@
   BoundTestNetLog request_log;
   MockCachingHostResolver host_resolver;
   MockErrorObserver* error_observer = new MockErrorObserver;
-  ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log);
 
-  InitResolver(&resolver, "simple.js");
+  scoped_ptr<ProxyResolver> resolver = CreateResolver(
+      &log, &host_resolver, make_scoped_ptr(error_observer), "simple.js");
 
   TestCompletionCallback callback;
   ProxyInfo proxy_info;
 
-  int rv = resolver.GetProxyForURL(
-      GURL("http://foo/"), &proxy_info, callback.callback(),
-      NULL, request_log.bound());
+  int rv =
+      resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info,
+                               callback.callback(), NULL, request_log.bound());
 
   EXPECT_EQ(ERR_IO_PENDING, rv);
   EXPECT_EQ(OK, callback.WaitForResult());
@@ -133,16 +151,16 @@
   BoundTestNetLog request_log;
   MockCachingHostResolver host_resolver;
   MockErrorObserver* error_observer = new MockErrorObserver;
-  ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log);
 
-  InitResolver(&resolver, "error.js");
+  scoped_ptr<ProxyResolver> resolver = CreateResolver(
+      &log, &host_resolver, make_scoped_ptr(error_observer), "error.js");
 
   TestCompletionCallback callback;
   ProxyInfo proxy_info;
 
-  int rv = resolver.GetProxyForURL(
-      GURL("http://throw-an-error/"), &proxy_info, callback.callback(), NULL,
-      request_log.bound());
+  int rv =
+      resolver->GetProxyForURL(GURL("http://throw-an-error/"), &proxy_info,
+                               callback.callback(), NULL, request_log.bound());
 
   EXPECT_EQ(ERR_IO_PENDING, rv);
   EXPECT_EQ(ERR_PAC_SCRIPT_FAILED, callback.WaitForResult());
@@ -179,19 +197,17 @@
   BoundTestNetLog request_log;
   MockCachingHostResolver host_resolver;
   MockErrorObserver* error_observer = new MockErrorObserver;
-  ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log);
 
-  InitResolver(&resolver, "too_many_alerts.js");
+  scoped_ptr<ProxyResolver> resolver =
+      CreateResolver(&log, &host_resolver, make_scoped_ptr(error_observer),
+                     "too_many_alerts.js");
 
   TestCompletionCallback callback;
   ProxyInfo proxy_info;
 
-  int rv = resolver.GetProxyForURL(
-      GURL("http://foo/"),
-      &proxy_info,
-      callback.callback(),
-      NULL,
-      request_log.bound());
+  int rv =
+      resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info,
+                               callback.callback(), NULL, request_log.bound());
 
   EXPECT_EQ(ERR_IO_PENDING, rv);
   EXPECT_EQ(OK, callback.WaitForResult());
@@ -230,19 +246,17 @@
   BoundTestNetLog request_log;
   MockCachingHostResolver host_resolver;
   MockErrorObserver* error_observer = new MockErrorObserver;
-  ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log);
 
-  InitResolver(&resolver, "too_many_empty_alerts.js");
+  scoped_ptr<ProxyResolver> resolver =
+      CreateResolver(&log, &host_resolver, make_scoped_ptr(error_observer),
+                     "too_many_empty_alerts.js");
 
   TestCompletionCallback callback;
   ProxyInfo proxy_info;
 
-  int rv = resolver.GetProxyForURL(
-      GURL("http://foo/"),
-      &proxy_info,
-      callback.callback(),
-      NULL,
-      request_log.bound());
+  int rv =
+      resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info,
+                               callback.callback(), NULL, request_log.bound());
 
   EXPECT_EQ(ERR_IO_PENDING, rv);
   EXPECT_EQ(OK, callback.WaitForResult());
@@ -279,7 +293,6 @@
   BoundTestNetLog request_log;
   MockCachingHostResolver host_resolver;
   MockErrorObserver* error_observer = new MockErrorObserver;
-  ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log);
 
   host_resolver.rules()->AddRuleForAddressFamily(
       "host1", ADDRESS_FAMILY_IPV4, "166.155.144.44");
@@ -293,17 +306,15 @@
       "*", ADDRESS_FAMILY_IPV4, "122.133.144.155");
   host_resolver.rules()->AddRule("*", "133.122.100.200");
 
-  InitResolver(&resolver, "dns.js");
+  scoped_ptr<ProxyResolver> resolver = CreateResolver(
+      &log, &host_resolver, make_scoped_ptr(error_observer), "dns.js");
 
   TestCompletionCallback callback;
   ProxyInfo proxy_info;
 
-  int rv = resolver.GetProxyForURL(
-      GURL("http://foo/"),
-      &proxy_info,
-      callback.callback(),
-      NULL,
-      request_log.bound());
+  int rv =
+      resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info,
+                               callback.callback(), NULL, request_log.bound());
 
   EXPECT_EQ(ERR_IO_PENDING, rv);
   EXPECT_EQ(OK, callback.WaitForResult());
@@ -356,23 +367,20 @@
   BoundTestNetLog request_log;
   MockCachingHostResolver host_resolver;
   MockErrorObserver* error_observer = new MockErrorObserver;
-  ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log);
 
   host_resolver.rules()->AddRule("foopy", "166.155.144.11");
   host_resolver.rules()->AddRule("*", "122.133.144.155");
 
-  InitResolver(&resolver, "simple_dns.js");
+  scoped_ptr<ProxyResolver> resolver = CreateResolver(
+      &log, &host_resolver, make_scoped_ptr(error_observer), "simple_dns.js");
 
   TestCompletionCallback callback1;
   TestCompletionCallback callback2;
   ProxyInfo proxy_info;
 
-  int rv = resolver.GetProxyForURL(
-      GURL("http://foopy/req1"),
-      &proxy_info,
-      callback1.callback(),
-      NULL,
-      request_log.bound());
+  int rv =
+      resolver->GetProxyForURL(GURL("http://foopy/req1"), &proxy_info,
+                               callback1.callback(), NULL, request_log.bound());
 
   EXPECT_EQ(ERR_IO_PENDING, rv);
   EXPECT_EQ(OK, callback1.WaitForResult());
@@ -383,12 +391,9 @@
   // The first request took 2 restarts, hence on g_iteration=3.
   EXPECT_EQ("166.155.144.11:3", proxy_info.proxy_server().ToURI());
 
-  rv = resolver.GetProxyForURL(
-      GURL("http://foopy/req2"),
-      &proxy_info,
-      callback2.callback(),
-      NULL,
-      request_log.bound());
+  rv =
+      resolver->GetProxyForURL(GURL("http://foopy/req2"), &proxy_info,
+                               callback2.callback(), NULL, request_log.bound());
 
   EXPECT_EQ(ERR_IO_PENDING, rv);
   EXPECT_EQ(OK, callback2.WaitForResult());
@@ -413,20 +418,21 @@
   BoundTestNetLog request_log;
   MockCachingHostResolver host_resolver;
   MockErrorObserver* error_observer = new MockErrorObserver;
-  ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log);
 
   host_resolver.rules()->AddRule("host1", "166.155.144.11");
   host_resolver.rules()->AddRule("crazy4", "133.199.111.4");
   host_resolver.rules()->AddRule("*", "122.133.144.155");
 
-  InitResolver(&resolver, "global_sideffects1.js");
+  scoped_ptr<ProxyResolver> resolver =
+      CreateResolver(&log, &host_resolver, make_scoped_ptr(error_observer),
+                     "global_sideffects1.js");
 
   TestCompletionCallback callback;
   ProxyInfo proxy_info;
 
-  int rv = resolver.GetProxyForURL(
-      GURL("http://foo/"), &proxy_info, callback.callback(), NULL,
-      request_log.bound());
+  int rv =
+      resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info,
+                               callback.callback(), NULL, request_log.bound());
   EXPECT_EQ(ERR_IO_PENDING, rv);
   EXPECT_EQ(OK, callback.WaitForResult());
 
@@ -465,7 +471,6 @@
   BoundTestNetLog request_log;
   MockCachingHostResolver host_resolver;
   MockErrorObserver* error_observer = new MockErrorObserver;
-  ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log);
 
   host_resolver.rules()->AddRule("host1", "166.155.144.11");
   host_resolver.rules()->AddRule("host2", "166.155.144.22");
@@ -473,14 +478,16 @@
   host_resolver.rules()->AddRule("host4", "166.155.144.44");
   host_resolver.rules()->AddRule("*", "122.133.144.155");
 
-  InitResolver(&resolver, "global_sideffects2.js");
+  scoped_ptr<ProxyResolver> resolver =
+      CreateResolver(&log, &host_resolver, make_scoped_ptr(error_observer),
+                     "global_sideffects2.js");
 
   TestCompletionCallback callback;
   ProxyInfo proxy_info;
 
-  int rv = resolver.GetProxyForURL(
-      GURL("http://foo/"), &proxy_info, callback.callback(), NULL,
-      request_log.bound());
+  int rv =
+      resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info,
+                               callback.callback(), NULL, request_log.bound());
   EXPECT_EQ(ERR_IO_PENDING, rv);
   EXPECT_EQ(OK, callback.WaitForResult());
 
@@ -505,19 +512,20 @@
   BoundTestNetLog request_log;
   MockCachingHostResolver host_resolver;
   MockErrorObserver* error_observer = new MockErrorObserver;
-  ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log);
 
   host_resolver.rules()->AddRule("host*", "166.155.144.11");
   host_resolver.rules()->AddRule("*", "122.133.144.155");
 
-  InitResolver(&resolver, "global_sideffects3.js");
+  scoped_ptr<ProxyResolver> resolver =
+      CreateResolver(&log, &host_resolver, make_scoped_ptr(error_observer),
+                     "global_sideffects3.js");
 
   TestCompletionCallback callback;
   ProxyInfo proxy_info;
 
-  int rv = resolver.GetProxyForURL(
-      GURL("http://foo/"), &proxy_info, callback.callback(), NULL,
-      request_log.bound());
+  int rv =
+      resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info,
+                               callback.callback(), NULL, request_log.bound());
   EXPECT_EQ(ERR_IO_PENDING, rv);
   EXPECT_EQ(OK, callback.WaitForResult());
 
@@ -548,19 +556,20 @@
   BoundTestNetLog request_log;
   MockCachingHostResolver host_resolver;
   MockErrorObserver* error_observer = new MockErrorObserver;
-  ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log);
 
   host_resolver.rules()->AddRule("host*", "166.155.144.11");
   host_resolver.rules()->AddRule("*", "122.133.144.155");
 
-  InitResolver(&resolver, "global_sideffects4.js");
+  scoped_ptr<ProxyResolver> resolver =
+      CreateResolver(&log, &host_resolver, make_scoped_ptr(error_observer),
+                     "global_sideffects4.js");
 
   TestCompletionCallback callback;
   ProxyInfo proxy_info;
 
-  int rv = resolver.GetProxyForURL(
-      GURL("http://foo/"), &proxy_info, callback.callback(), NULL,
-      request_log.bound());
+  int rv =
+      resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info,
+                               callback.callback(), NULL, request_log.bound());
   EXPECT_EQ(ERR_IO_PENDING, rv);
   EXPECT_EQ(OK, callback.WaitForResult());
 
@@ -582,12 +591,13 @@
   MockCachingHostResolver host_resolver;
   host_resolver.set_synchronous_mode(synchronous_host_resolver);
   MockErrorObserver* error_observer = new MockErrorObserver;
-  ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log);
 
   host_resolver.rules()->AddRule("host1", "91.13.12.1");
   host_resolver.rules()->AddRule("host2", "91.13.12.2");
 
-  InitResolver(&resolver, "dns_during_init.js");
+  scoped_ptr<ProxyResolver> resolver =
+      CreateResolver(&log, &host_resolver, make_scoped_ptr(error_observer),
+                     "dns_during_init.js");
 
   // Initialization did 2 dnsResolves.
   EXPECT_EQ(2u, host_resolver.num_resolve());
@@ -601,9 +611,9 @@
   TestCompletionCallback callback;
   ProxyInfo proxy_info;
 
-  int rv = resolver.GetProxyForURL(
-      GURL("http://foo/"), &proxy_info, callback.callback(), NULL,
-      request_log.bound());
+  int rv =
+      resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info,
+                               callback.callback(), NULL, request_log.bound());
   EXPECT_EQ(ERR_IO_PENDING, rv);
   EXPECT_EQ(OK, callback.WaitForResult());
 
@@ -651,25 +661,25 @@
 TEST_F(ProxyResolverV8TracingTest, CancelAll) {
   MockCachingHostResolver host_resolver;
   MockErrorObserver* error_observer = new MockErrorObserver;
-  ProxyResolverV8Tracing resolver(&host_resolver, error_observer, NULL);
 
   host_resolver.rules()->AddSimulatedFailure("*");
 
-  InitResolver(&resolver, "dns.js");
+  scoped_ptr<ProxyResolver> resolver = CreateResolver(
+      nullptr, &host_resolver, make_scoped_ptr(error_observer), "dns.js");
 
   const size_t kNumRequests = 5;
   ProxyInfo proxy_info[kNumRequests];
   ProxyResolver::RequestHandle request[kNumRequests];
 
   for (size_t i = 0; i < kNumRequests; ++i) {
-    int rv = resolver.GetProxyForURL(
-        GURL("http://foo/"), &proxy_info[i],
-        base::Bind(&CrashCallback), &request[i], BoundNetLog());
+    int rv = resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info[i],
+                                      base::Bind(&CrashCallback), &request[i],
+                                      BoundNetLog());
     EXPECT_EQ(ERR_IO_PENDING, rv);
   }
 
   for (size_t i = 0; i < kNumRequests; ++i) {
-    resolver.CancelRequest(request[i]);
+    resolver->CancelRequest(request[i]);
   }
 }
 
@@ -679,11 +689,11 @@
 TEST_F(ProxyResolverV8TracingTest, CancelSome) {
   MockCachingHostResolver host_resolver;
   MockErrorObserver* error_observer = new MockErrorObserver;
-  ProxyResolverV8Tracing resolver(&host_resolver, error_observer, NULL);
 
   host_resolver.rules()->AddSimulatedFailure("*");
 
-  InitResolver(&resolver, "dns.js");
+  scoped_ptr<ProxyResolver> resolver = CreateResolver(
+      nullptr, &host_resolver, make_scoped_ptr(error_observer), "dns.js");
 
   ProxyInfo proxy_info1;
   ProxyInfo proxy_info2;
@@ -691,17 +701,16 @@
   ProxyResolver::RequestHandle request2;
   TestCompletionCallback callback;
 
-  int rv = resolver.GetProxyForURL(
-      GURL("http://foo/"), &proxy_info1,
-      base::Bind(&CrashCallback), &request1, BoundNetLog());
+  int rv = resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info1,
+                                    base::Bind(&CrashCallback), &request1,
+                                    BoundNetLog());
   EXPECT_EQ(ERR_IO_PENDING, rv);
 
-  rv = resolver.GetProxyForURL(
-      GURL("http://foo/"), &proxy_info2,
-      callback.callback(), &request2, BoundNetLog());
+  rv = resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info2,
+                                callback.callback(), &request2, BoundNetLog());
   EXPECT_EQ(ERR_IO_PENDING, rv);
 
-  resolver.CancelRequest(request1);
+  resolver->CancelRequest(request1);
 
   EXPECT_EQ(OK, callback.WaitForResult());
 }
@@ -711,11 +720,11 @@
 TEST_F(ProxyResolverV8TracingTest, CancelWhilePendingCompletionTask) {
   MockCachingHostResolver host_resolver;
   MockErrorObserver* error_observer = new MockErrorObserver;
-  ProxyResolverV8Tracing resolver(&host_resolver, error_observer, NULL);
 
   host_resolver.rules()->AddSimulatedFailure("*");
 
-  InitResolver(&resolver, "error.js");
+  scoped_ptr<ProxyResolver> resolver = CreateResolver(
+      nullptr, &host_resolver, make_scoped_ptr(error_observer), "error.js");
 
   ProxyInfo proxy_info1;
   ProxyInfo proxy_info2;
@@ -725,14 +734,13 @@
   ProxyResolver::RequestHandle request3;
   TestCompletionCallback callback;
 
-  int rv = resolver.GetProxyForURL(
-      GURL("http://foo/"), &proxy_info1,
-      base::Bind(&CrashCallback), &request1, BoundNetLog());
+  int rv = resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info1,
+                                    base::Bind(&CrashCallback), &request1,
+                                    BoundNetLog());
   EXPECT_EQ(ERR_IO_PENDING, rv);
 
-  rv = resolver.GetProxyForURL(
-      GURL("http://throw-an-error/"), &proxy_info2,
-      callback.callback(), &request2, BoundNetLog());
+  rv = resolver->GetProxyForURL(GURL("http://throw-an-error/"), &proxy_info2,
+                                callback.callback(), &request2, BoundNetLog());
   EXPECT_EQ(ERR_IO_PENDING, rv);
 
   // Wait until the first request has finished running on the worker thread.
@@ -741,14 +749,14 @@
 
   // Cancel the first request, while it has a pending completion task on
   // the origin thread.
-  resolver.CancelRequest(request1);
+  resolver->CancelRequest(request1);
 
   EXPECT_EQ(ERR_PAC_SCRIPT_FAILED, callback.WaitForResult());
 
   // Start another request, to make sure it is able to complete.
-  rv = resolver.GetProxyForURL(
-      GURL("http://i-have-no-idea-what-im-doing/"), &proxy_info3,
-      callback.callback(), &request3, BoundNetLog());
+  rv = resolver->GetProxyForURL(GURL("http://i-have-no-idea-what-im-doing/"),
+                                &proxy_info3, callback.callback(), &request3,
+                                BoundNetLog());
   EXPECT_EQ(ERR_IO_PENDING, rv);
 
   EXPECT_EQ(OK, callback.WaitForResult());
@@ -829,33 +837,33 @@
 TEST_F(ProxyResolverV8TracingTest, CancelWhileOutstandingNonBlockingDns) {
   BlockableHostResolver host_resolver;
   MockErrorObserver* error_observer = new MockErrorObserver;
-  ProxyResolverV8Tracing resolver(&host_resolver, error_observer, NULL);
 
-  InitResolver(&resolver, "dns.js");
+  scoped_ptr<ProxyResolver> resolver = CreateResolver(
+      nullptr, &host_resolver, make_scoped_ptr(error_observer), "dns.js");
 
   ProxyInfo proxy_info1;
   ProxyInfo proxy_info2;
   ProxyResolver::RequestHandle request1;
   ProxyResolver::RequestHandle request2;
 
-  int rv = resolver.GetProxyForURL(
-      GURL("http://foo/req1"), &proxy_info1,
-      base::Bind(&CrashCallback), &request1, BoundNetLog());
+  int rv = resolver->GetProxyForURL(GURL("http://foo/req1"), &proxy_info1,
+                                    base::Bind(&CrashCallback), &request1,
+                                    BoundNetLog());
 
   EXPECT_EQ(ERR_IO_PENDING, rv);
 
   host_resolver.WaitUntilRequestIsReceived();
 
-  rv = resolver.GetProxyForURL(
-      GURL("http://foo/req2"), &proxy_info2,
-      base::Bind(&CrashCallback), &request2, BoundNetLog());
+  rv = resolver->GetProxyForURL(GURL("http://foo/req2"), &proxy_info2,
+                                base::Bind(&CrashCallback), &request2,
+                                BoundNetLog());
 
   EXPECT_EQ(ERR_IO_PENDING, rv);
 
   host_resolver.WaitUntilRequestIsReceived();
 
-  resolver.CancelRequest(request1);
-  resolver.CancelRequest(request2);
+  resolver->CancelRequest(request1);
+  resolver->CancelRequest(request2);
 
   EXPECT_EQ(2, host_resolver.num_cancelled_requests());
 
@@ -864,7 +872,7 @@
   // should have been cancelled.
 }
 
-void CancelRequestAndPause(ProxyResolverV8Tracing* resolver,
+void CancelRequestAndPause(ProxyResolver* resolver,
                            ProxyResolver::RequestHandle request) {
   resolver->CancelRequest(request);
 
@@ -880,21 +888,21 @@
 TEST_F(ProxyResolverV8TracingTest, CancelWhileBlockedInNonBlockingDns) {
   BlockableHostResolver host_resolver;
   MockErrorObserver* error_observer = new MockErrorObserver;
-  ProxyResolverV8Tracing resolver(&host_resolver, error_observer, NULL);
 
-  InitResolver(&resolver, "dns.js");
+  scoped_ptr<ProxyResolver> resolver = CreateResolver(
+      nullptr, &host_resolver, make_scoped_ptr(error_observer), "dns.js");
 
   ProxyInfo proxy_info;
   ProxyResolver::RequestHandle request;
 
-  int rv = resolver.GetProxyForURL(
-      GURL("http://foo/"), &proxy_info,
-      base::Bind(&CrashCallback), &request, BoundNetLog());
+  int rv = resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info,
+                                    base::Bind(&CrashCallback), &request,
+                                    BoundNetLog());
 
   EXPECT_EQ(ERR_IO_PENDING, rv);
 
   host_resolver.SetAction(
-      base::Bind(CancelRequestAndPause, &resolver, request));
+      base::Bind(CancelRequestAndPause, resolver.get(), request));
 
   host_resolver.WaitUntilRequestIsReceived();
 
@@ -909,16 +917,16 @@
 TEST_F(ProxyResolverV8TracingTest, CancelWhileBlockedInNonBlockingDns2) {
   MockCachingHostResolver host_resolver;
   MockErrorObserver* error_observer = new MockErrorObserver;
-  ProxyResolverV8Tracing resolver(&host_resolver, error_observer, NULL);
 
-  InitResolver(&resolver, "dns.js");
+  scoped_ptr<ProxyResolver> resolver = CreateResolver(
+      nullptr, &host_resolver, make_scoped_ptr(error_observer), "dns.js");
 
   ProxyInfo proxy_info;
   ProxyResolver::RequestHandle request;
 
-  int rv = resolver.GetProxyForURL(
-      GURL("http://foo/"), &proxy_info,
-      base::Bind(&CrashCallback), &request, BoundNetLog());
+  int rv = resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info,
+                                    base::Bind(&CrashCallback), &request,
+                                    BoundNetLog());
 
   EXPECT_EQ(ERR_IO_PENDING, rv);
 
@@ -926,28 +934,75 @@
   // work whatever the delay is here, but it is most useful if the delay
   // is large enough to allow a task to be posted back.
   base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(10));
-  resolver.CancelRequest(request);
+  resolver->CancelRequest(request);
 
   EXPECT_EQ(0u, host_resolver.num_resolve());
 }
 
-TEST_F(ProxyResolverV8TracingTest, CancelSetPacWhileOutstandingBlockingDns) {
+TEST_F(ProxyResolverV8TracingTest,
+       CancelCreateResolverWhileOutstandingBlockingDns) {
   BlockableHostResolver host_resolver;
   MockErrorObserver* error_observer = new MockErrorObserver;
 
-  ProxyResolverV8Tracing resolver(&host_resolver, error_observer, NULL);
+  ProxyResolverFactoryV8Tracing factory(
+      &host_resolver, nullptr, ProxyResolver::LoadStateChangedCallback(),
+      base::Bind(&ReturnErrorObserver,
+                 base::Passed(make_scoped_ptr(error_observer))));
 
-  int rv =
-      resolver.SetPacScript(LoadScriptData("dns_during_init.js"),
-      base::Bind(&CrashCallback));
+  scoped_ptr<ProxyResolver> resolver;
+  scoped_ptr<ProxyResolverFactory::Request> request;
+  int rv = factory.CreateProxyResolver(LoadScriptData("dns_during_init.js"),
+                                       &resolver, base::Bind(&CrashCallback),
+                                       &request);
   EXPECT_EQ(ERR_IO_PENDING, rv);
 
   host_resolver.WaitUntilRequestIsReceived();
 
-  resolver.CancelSetPacScript();
+  request.reset();
   EXPECT_EQ(1, host_resolver.num_cancelled_requests());
 }
 
+TEST_F(ProxyResolverV8TracingTest, DeleteFactoryWhileOutstandingBlockingDns) {
+  BlockableHostResolver host_resolver;
+  MockErrorObserver* error_observer = new MockErrorObserver;
+
+  scoped_ptr<ProxyResolver> resolver;
+  scoped_ptr<ProxyResolverFactory::Request> request;
+  {
+    ProxyResolverFactoryV8Tracing factory(
+        &host_resolver, nullptr, ProxyResolver::LoadStateChangedCallback(),
+        base::Bind(&ReturnErrorObserver,
+                   base::Passed(make_scoped_ptr(error_observer))));
+
+    int rv = factory.CreateProxyResolver(LoadScriptData("dns_during_init.js"),
+                                         &resolver, base::Bind(&CrashCallback),
+                                         &request);
+    EXPECT_EQ(ERR_IO_PENDING, rv);
+    host_resolver.WaitUntilRequestIsReceived();
+  }
+  EXPECT_EQ(1, host_resolver.num_cancelled_requests());
+}
+
+TEST_F(ProxyResolverV8TracingTest, ErrorLoadingScript) {
+  BlockableHostResolver host_resolver;
+  MockErrorObserver* error_observer = new MockErrorObserver;
+
+  ProxyResolverFactoryV8Tracing factory(
+      &host_resolver, nullptr, ProxyResolver::LoadStateChangedCallback(),
+      base::Bind(&ReturnErrorObserver,
+                 base::Passed(make_scoped_ptr(error_observer))));
+
+  scoped_ptr<ProxyResolver> resolver;
+  scoped_ptr<ProxyResolverFactory::Request> request;
+  TestCompletionCallback callback;
+  int rv =
+      factory.CreateProxyResolver(LoadScriptData("error_on_load.js"), &resolver,
+                                  callback.callback(), &request);
+  EXPECT_EQ(ERR_IO_PENDING, rv);
+  EXPECT_EQ(ERR_PAC_SCRIPT_FAILED, callback.WaitForResult());
+  EXPECT_FALSE(resolver);
+}
+
 // This tests that the execution of a PAC script is terminated when the DNS
 // dependencies are missing. If the test fails, then it will hang.
 TEST_F(ProxyResolverV8TracingTest, Terminate) {
@@ -955,22 +1010,19 @@
   BoundTestNetLog request_log;
   MockCachingHostResolver host_resolver;
   MockErrorObserver* error_observer = new MockErrorObserver;
-  ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log);
 
   host_resolver.rules()->AddRule("host1", "182.111.0.222");
   host_resolver.rules()->AddRule("host2", "111.33.44.55");
 
-  InitResolver(&resolver, "terminate.js");
+  scoped_ptr<ProxyResolver> resolver = CreateResolver(
+      &log, &host_resolver, make_scoped_ptr(error_observer), "terminate.js");
 
   TestCompletionCallback callback;
   ProxyInfo proxy_info;
 
-  int rv = resolver.GetProxyForURL(
-      GURL("http://foopy/req1"),
-      &proxy_info,
-      callback.callback(),
-      NULL,
-      request_log.bound());
+  int rv =
+      resolver->GetProxyForURL(GURL("http://foopy/req1"), &proxy_info,
+                               callback.callback(), NULL, request_log.bound());
 
   EXPECT_EQ(ERR_IO_PENDING, rv);
   EXPECT_EQ(OK, callback.WaitForResult());
@@ -1007,39 +1059,39 @@
   host_resolver0.rules()->AddRuleForAddressFamily(
       "*", ADDRESS_FAMILY_IPV4, "122.133.144.155");
   host_resolver0.rules()->AddRule("*", "133.122.100.200");
-  ProxyResolverV8Tracing resolver0(
-      &host_resolver0, new MockErrorObserver, NULL);
-  InitResolver(&resolver0, "dns.js");
+  scoped_ptr<ProxyResolver> resolver0 =
+      CreateResolver(nullptr, &host_resolver0,
+                     make_scoped_ptr(new MockErrorObserver), "dns.js");
 
   // ------------------------
   // Setup resolver1
   // ------------------------
-  ProxyResolverV8Tracing resolver1(
-      &host_resolver0, new MockErrorObserver, NULL);
-  InitResolver(&resolver1, "dns.js");
+  scoped_ptr<ProxyResolver> resolver1 =
+      CreateResolver(nullptr, &host_resolver0,
+                     make_scoped_ptr(new MockErrorObserver), "dns.js");
 
   // ------------------------
   // Setup resolver2
   // ------------------------
-  ProxyResolverV8Tracing resolver2(
-      &host_resolver0, new MockErrorObserver, NULL);
-  InitResolver(&resolver2, "simple.js");
+  scoped_ptr<ProxyResolver> resolver2 =
+      CreateResolver(nullptr, &host_resolver0,
+                     make_scoped_ptr(new MockErrorObserver), "simple.js");
 
   // ------------------------
   // Setup resolver3
   // ------------------------
   MockHostResolver host_resolver3;
   host_resolver3.rules()->AddRule("foo", "166.155.144.33");
-  ProxyResolverV8Tracing resolver3(
-      &host_resolver3, new MockErrorObserver, NULL);
-  InitResolver(&resolver3, "simple_dns.js");
+  scoped_ptr<ProxyResolver> resolver3 =
+      CreateResolver(nullptr, &host_resolver3,
+                     make_scoped_ptr(new MockErrorObserver), "simple_dns.js");
 
   // ------------------------
   // Queue up work for each resolver (which will be running in parallel).
   // ------------------------
 
-  ProxyResolverV8Tracing* resolver[] = {
-    &resolver0, &resolver1, &resolver2, &resolver3,
+  ProxyResolver* resolver[] = {
+      resolver0.get(), resolver1.get(), resolver2.get(), resolver3.get(),
   };
 
   const size_t kNumResolvers = arraysize(resolver);
diff --git a/net/proxy/proxy_service_mojo.cc b/net/proxy/proxy_service_mojo.cc
index 86da99a..fe818532 100644
--- a/net/proxy/proxy_service_mojo.cc
+++ b/net/proxy/proxy_service_mojo.cc
@@ -5,11 +5,13 @@
 #include "net/proxy/proxy_service_mojo.h"
 
 #include "base/logging.h"
+#include "base/message_loop/message_loop_proxy.h"
 #include "net/dns/mojo_host_resolver_impl.h"
 #include "net/interfaces/proxy_resolver_service.mojom.h"
 #include "net/proxy/in_process_mojo_proxy_resolver_factory.h"
 #include "net/proxy/mojo_proxy_resolver_factory.h"
 #include "net/proxy/mojo_proxy_resolver_impl.h"
+#include "net/proxy/network_delegate_error_observer.h"
 #include "net/proxy/proxy_resolver_factory.h"
 #include "net/proxy/proxy_resolver_mojo.h"
 #include "net/proxy/proxy_resolver_v8_tracing.h"
@@ -31,8 +33,11 @@
   DCHECK(host_resolver);
 
   ProxyService* proxy_service = new ProxyService(
-      proxy_config_service, make_scoped_ptr(new ProxyResolverFactoryMojo(
-                                mojo_proxy_factory, host_resolver)),
+      proxy_config_service,
+      make_scoped_ptr(new ProxyResolverFactoryMojo(
+          mojo_proxy_factory, host_resolver,
+          base::Bind(&NetworkDelegateErrorObserver::Create, network_delegate,
+                     base::MessageLoopProxy::current()))),
       net_log);
 
   // Configure fetchers to use for PAC script downloads and auto-detect.
diff --git a/net/proxy/proxy_service_mojo_unittest.cc b/net/proxy/proxy_service_mojo_unittest.cc
index 5caf2a5..334bafa 100644
--- a/net/proxy/proxy_service_mojo_unittest.cc
+++ b/net/proxy/proxy_service_mojo_unittest.cc
@@ -8,7 +8,9 @@
 
 #include "base/callback_helpers.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/strings/utf_string_conversions.h"
 #include "net/base/load_flags.h"
+#include "net/base/network_delegate_impl.h"
 #include "net/base/test_completion_callback.h"
 #include "net/dns/mock_host_resolver.h"
 #include "net/log/net_log.h"
@@ -18,6 +20,7 @@
 #include "net/proxy/mojo_proxy_resolver_factory.h"
 #include "net/proxy/proxy_config_service_fixed.h"
 #include "net/proxy/proxy_service.h"
+#include "net/test/event_waiter.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
 
@@ -36,6 +39,31 @@
     "    return 'DIRECT';\n"
     "  return 'QUIC bar:4321';\n"
     "}";
+const char kErrorPacScript[] =
+    "function FindProxyForURL(url, host) {\n"
+    "  throw new Error('test error');\n"
+    "}";
+
+class TestNetworkDelegate : public NetworkDelegateImpl {
+ public:
+  enum Event {
+    PAC_SCRIPT_ERROR,
+  };
+
+  EventWaiter<Event>& event_waiter() { return event_waiter_; }
+
+  void OnPACScriptError(int line_number, const base::string16& error) override;
+
+ private:
+  EventWaiter<Event> event_waiter_;
+};
+
+void TestNetworkDelegate::OnPACScriptError(int line_number,
+                                           const base::string16& error) {
+  event_waiter_.NotifyEvent(PAC_SCRIPT_ERROR);
+  EXPECT_EQ(2, line_number);
+  EXPECT_TRUE(base::UTF16ToUTF8(error).find("test error") != std::string::npos);
+}
 
 }  // namespace
 
@@ -50,20 +78,23 @@
         this, new ProxyConfigServiceFixed(
                   ProxyConfig::CreateFromCustomPacURL(GURL(kPacUrl))),
         fetcher_, new DoNothingDhcpProxyScriptFetcher(), &mock_host_resolver_,
-        nullptr /* NetLog* */, nullptr /* NetworkDelegate* */));
+        nullptr /* NetLog* */, &network_delegate_));
   }
 
   scoped_ptr<base::ScopedClosureRunner> CreateResolver(
       const mojo::String& pac_script,
       mojo::InterfaceRequest<interfaces::ProxyResolver> req,
       interfaces::HostResolverPtr host_resolver,
+      interfaces::ProxyResolverErrorObserverPtr error_observer,
       interfaces::ProxyResolverFactoryRequestClientPtr client) override {
     InProcessMojoProxyResolverFactory::GetInstance()->CreateResolver(
-        pac_script, req.Pass(), host_resolver.Pass(), client.Pass());
+        pac_script, req.Pass(), host_resolver.Pass(), error_observer.Pass(),
+        client.Pass());
     return make_scoped_ptr(
         new base::ScopedClosureRunner(on_delete_closure_.closure()));
   }
 
+  TestNetworkDelegate network_delegate_;
   MockHostResolver mock_host_resolver_;
   MockProxyScriptFetcher* fetcher_;  // Owned by |proxy_service_|.
   scoped_ptr<ProxyService> proxy_service_;
@@ -112,4 +143,22 @@
   on_delete_closure_.WaitForResult();
 }
 
+TEST_F(ProxyServiceMojoTest, Error) {
+  ProxyInfo info;
+  TestCompletionCallback callback;
+  EXPECT_EQ(ERR_IO_PENDING,
+            proxy_service_->ResolveProxy(GURL("http://foo"), LOAD_NORMAL, &info,
+                                         callback.callback(), nullptr, nullptr,
+                                         BoundNetLog()));
+
+  // Proxy script fetcher should have a fetch triggered by the first
+  // |ResolveProxy()| request.
+  EXPECT_TRUE(fetcher_->has_pending_request());
+  EXPECT_EQ(GURL(kPacUrl), fetcher_->pending_request_url());
+  fetcher_->NotifyFetchCompletion(OK, kErrorPacScript);
+
+  network_delegate_.event_waiter().WaitForEvent(
+      TestNetworkDelegate::PAC_SCRIPT_ERROR);
+}
+
 }  // namespace net
diff --git a/net/proxy/proxy_service_v8.cc b/net/proxy/proxy_service_v8.cc
index 60916771..3634613 100644
--- a/net/proxy/proxy_service_v8.cc
+++ b/net/proxy/proxy_service_v8.cc
@@ -14,38 +14,6 @@
 #include "net/proxy/proxy_service.h"
 
 namespace net {
-namespace {
-
-class ProxyResolverFactoryForV8Resolver : public LegacyProxyResolverFactory {
- public:
-  explicit ProxyResolverFactoryForV8Resolver(HostResolver* host_resolver,
-                                             NetLog* net_log,
-                                             NetworkDelegate* network_delegate)
-      : LegacyProxyResolverFactory(true),
-        host_resolver_(host_resolver),
-        net_log_(net_log),
-        network_delegate_(network_delegate) {}
-
-  // LegacyProxyResolverFactory override.
-  scoped_ptr<ProxyResolver> CreateProxyResolver() override {
-    DCHECK(thread_checker_.CalledOnValidThread());
-    ProxyResolverErrorObserver* error_observer =
-        new NetworkDelegateErrorObserver(
-            network_delegate_, base::ThreadTaskRunnerHandle::Get().get());
-    return make_scoped_ptr(
-        new ProxyResolverV8Tracing(host_resolver_, error_observer, net_log_));
-  }
-
- private:
-  HostResolver* const host_resolver_;
-  NetLog* const net_log_;
-  NetworkDelegate* const network_delegate_;
-
-  base::ThreadChecker thread_checker_;
-
-  DISALLOW_COPY_AND_ASSIGN(ProxyResolverFactoryForV8Resolver);
-};
-}  // namespace
 
 // static
 ProxyService* CreateProxyServiceUsingV8ProxyResolver(
@@ -60,11 +28,13 @@
   DCHECK(dhcp_proxy_script_fetcher);
   DCHECK(host_resolver);
 
-  ProxyService* proxy_service =
-      new ProxyService(proxy_config_service,
-                       make_scoped_ptr(new ProxyResolverFactoryForV8Resolver(
-                           host_resolver, net_log, network_delegate)),
-                       net_log);
+  ProxyService* proxy_service = new ProxyService(
+      proxy_config_service,
+      make_scoped_ptr(new ProxyResolverFactoryV8Tracing(
+          host_resolver, net_log, ProxyResolver::LoadStateChangedCallback(),
+          base::Bind(&NetworkDelegateErrorObserver::Create, network_delegate,
+                     base::ThreadTaskRunnerHandle::Get()))),
+      net_log);
 
   // Configure fetchers to use for PAC script downloads and auto-detect.
   proxy_service->SetProxyScriptFetchers(proxy_script_fetcher,
diff --git a/net/quic/congestion_control/send_algorithm_interface.cc b/net/quic/congestion_control/send_algorithm_interface.cc
index bc3ee8f..77d8900 100644
--- a/net/quic/congestion_control/send_algorithm_interface.cc
+++ b/net/quic/congestion_control/send_algorithm_interface.cc
@@ -21,10 +21,8 @@
     QuicConnectionStats* stats,
     QuicPacketCount initial_congestion_window) {
   const QuicPacketCount max_congestion_window =
-      FLAGS_quic_limit_max_cwnd_to_receive_buffer
-          ? (kDefaultSocketReceiveBuffer * kUsableRecieveBufferFraction) /
-                kDefaultTCPMSS
-          : kMaxTcpCongestionWindow;
+      (kDefaultSocketReceiveBuffer * kUsableRecieveBufferFraction) /
+      kDefaultTCPMSS;
   switch (congestion_control_type) {
     case kCubic:
       return new TcpCubicSender(clock, rtt_stats, false /* don't use Reno */,
diff --git a/net/quic/crypto/crypto_protocol.h b/net/quic/crypto/crypto_protocol.h
index 2f1cb37..1f881ea 100644
--- a/net/quic/crypto/crypto_protocol.h
+++ b/net/quic/crypto/crypto_protocol.h
@@ -57,7 +57,6 @@
 const QuicTag kRENO = TAG('R', 'E', 'N', 'O');   // Reno Congestion Control
 const QuicTag kBYTE = TAG('B', 'Y', 'T', 'E');   // TCP cubic or reno in bytes
 const QuicTag kIW10 = TAG('I', 'W', '1', '0');   // Force ICWND to 10
-const QuicTag kPACE = TAG('P', 'A', 'C', 'E');   // Enable pacing
 const QuicTag k1CON = TAG('1', 'C', 'O', 'N');   // Emulate a single connection
 const QuicTag kNTLP = TAG('N', 'T', 'L', 'P');   // No tail loss probe
 const QuicTag kNCON = TAG('N', 'C', 'O', 'N');   // N Connection Congestion Ctrl
diff --git a/net/quic/crypto/quic_crypto_client_config.cc b/net/quic/crypto/quic_crypto_client_config.cc
index eef97433..a95c0f0 100644
--- a/net/quic/crypto/quic_crypto_client_config.cc
+++ b/net/quic/crypto/quic_crypto_client_config.cc
@@ -727,7 +727,7 @@
       return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
     }
     cached->add_server_designated_connection_id(connection_id);
-    return QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT;
+    return QUIC_NO_ERROR;
   }
 
   return QUIC_NO_ERROR;
diff --git a/net/quic/crypto/quic_crypto_client_config.h b/net/quic/crypto/quic_crypto_client_config.h
index 1fddafa..a65f007 100644
--- a/net/quic/crypto/quic_crypto_client_config.h
+++ b/net/quic/crypto/quic_crypto_client_config.h
@@ -221,9 +221,7 @@
   // about a future handshake (i.e. an nonce value from the server), then it
   // will be saved in |out_params|. |now| is used to judge whether the server
   // config in the rejection message has expired. |is_https| is used to track
-  // reject reason for secure vs insecure QUIC.  If the rejection message
-  // indicates that the reject is a stateless-reject, returns error code
-  // QUIC_CRYPTO_HANDSHAKE_RECEIVED_STATELESS_REJECT.
+  // reject reason for secure vs insecure QUIC.
   QuicErrorCode ProcessRejection(const CryptoHandshakeMessage& rej,
                                  QuicWallTime now,
                                  CachedState* cached,
diff --git a/net/quic/crypto/quic_crypto_client_config_test.cc b/net/quic/crypto/quic_crypto_client_config_test.cc
index bf3a343..348f8f9 100644
--- a/net/quic/crypto/quic_crypto_client_config_test.cc
+++ b/net/quic/crypto/quic_crypto_client_config_test.cc
@@ -370,11 +370,10 @@
   QuicCryptoNegotiatedParameters out_params;
   string error;
   QuicCryptoClientConfig config;
-  EXPECT_EQ(
-      QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT,
-      config.ProcessRejection(rej, QuicWallTime::FromUNIXSeconds(0), &cached,
-                              true,  // is_https
-                              &out_params, &error));
+  EXPECT_EQ(QUIC_NO_ERROR, config.ProcessRejection(
+                               rej, QuicWallTime::FromUNIXSeconds(0), &cached,
+                               true,  // is_https
+                               &out_params, &error));
   EXPECT_TRUE(cached.has_server_designated_connection_id());
   EXPECT_EQ(kConnectionId, cached.GetNextServerDesignatedConnectionId());
 }
diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc
index 08fc9026..12f9290 100644
--- a/net/quic/quic_connection.cc
+++ b/net/quic/quic_connection.cc
@@ -907,36 +907,59 @@
 
   if (!last_stream_frames_.empty()) {
     visitor_->OnStreamFrames(last_stream_frames_);
+    if (!connected_ && !FLAGS_quic_stop_early) {
+      return;
+    }
   }
 
   for (size_t i = 0; i < last_stream_frames_.size(); ++i) {
     stats_.stream_bytes_received +=
         last_stream_frames_[i].data.TotalBufferSize();
   }
-
   // Process window updates, blocked, stream resets, acks, then congestion
   // feedback.
   if (!last_window_update_frames_.empty()) {
     visitor_->OnWindowUpdateFrames(last_window_update_frames_);
+    if (!connected_ && !FLAGS_quic_stop_early) {
+      return;
+    }
   }
   if (!last_blocked_frames_.empty()) {
     visitor_->OnBlockedFrames(last_blocked_frames_);
+    if (!connected_ && !FLAGS_quic_stop_early) {
+      return;
+    }
   }
   for (size_t i = 0; i < last_goaway_frames_.size(); ++i) {
     visitor_->OnGoAway(last_goaway_frames_[i]);
+    if (!connected_ && !FLAGS_quic_stop_early) {
+      return;
+    }
   }
   for (size_t i = 0; i < last_rst_frames_.size(); ++i) {
     visitor_->OnRstStream(last_rst_frames_[i]);
+    if (!connected_ && !FLAGS_quic_stop_early) {
+      return;
+    }
   }
   for (size_t i = 0; i < last_ack_frames_.size(); ++i) {
     ProcessAckFrame(last_ack_frames_[i]);
+    if (!connected_ && !FLAGS_quic_stop_early) {
+      return;
+    }
   }
   for (size_t i = 0; i < last_stop_waiting_frames_.size(); ++i) {
     ProcessStopWaitingFrame(last_stop_waiting_frames_[i]);
+    if (!connected_ && !FLAGS_quic_stop_early) {
+      return;
+    }
   }
   if (!last_close_frames_.empty()) {
     CloseConnection(last_close_frames_[0].error_code, true);
     DCHECK(!connected_);
+    if (!FLAGS_quic_stop_early) {
+      return;
+    }
   }
 
   // If there are new missing packets to report, send an ack immediately.
@@ -959,9 +982,8 @@
     if (ack_alarm_->IsSet()) {
       ack_queued_ = true;
     } else {
-      // Send an ack much more quickly for crypto handshake packets.
-      QuicTime::Delta delayed_ack_time = sent_packet_manager_.DelayedAckTime();
-      ack_alarm_->Set(clock_->ApproximateNow().Add(delayed_ack_time));
+      ack_alarm_->Set(
+          clock_->ApproximateNow().Add(sent_packet_manager_.DelayedAckTime()));
       DVLOG(1) << "Ack timer set; next packet or timer will trigger ACK.";
     }
   }
diff --git a/net/quic/quic_crypto_client_stream.cc b/net/quic/quic_crypto_client_stream.cc
index 28a6db8..f1f0909 100644
--- a/net/quic/quic_crypto_client_stream.cc
+++ b/net/quic/quic_crypto_client_stream.cc
@@ -87,7 +87,8 @@
       channel_id_source_callback_run_(false),
       channel_id_source_callback_(nullptr),
       verify_context_(verify_context),
-      proof_verify_callback_(nullptr) {
+      proof_verify_callback_(nullptr),
+      stateless_reject_received_(false) {
   DCHECK_EQ(Perspective::IS_CLIENT, session->connection()->perspective());
 }
 
@@ -246,6 +247,19 @@
 void QuicCryptoClientStream::DoSendCHLO(
     const CryptoHandshakeMessage* in,
     QuicCryptoClientConfig::CachedState* cached) {
+  if (stateless_reject_received_) {
+    // If we've gotten to this point, we've sent at least one hello
+    // and received a stateless reject in response.  We cannot
+    // continue to send hellos because the server has abandoned state
+    // for this connection.  Abandon further handshakes.
+    next_state_ = STATE_NONE;
+    if (session()->connection()->connected()) {
+      session()->connection()->CloseConnection(
+          QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT, false);
+    }
+    return;
+  }
+
   // Send the client hello in plaintext.
   session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_NONE);
   if (num_client_hellos_ > kMaxClientHellos) {
@@ -255,6 +269,11 @@
   num_client_hellos_++;
 
   CryptoHandshakeMessage out;
+  DCHECK(session() != nullptr);
+  DCHECK(session()->config() != nullptr);
+  // Send all the options, regardless of whether we're sending an
+  // inchoate or subsequent hello.
+  session()->config()->ToHandshakeMessage(&out);
   if (!cached->IsComplete(session()->connection()->clock()->WallNow())) {
     crypto_config_->FillInchoateClientHello(
         server_id_,
@@ -282,7 +301,6 @@
     return;
   }
 
-  session()->config()->ToHandshakeMessage(&out);
   string error_details;
   QuicErrorCode error = crypto_config_->FillClientHello(
       server_id_,
@@ -344,16 +362,18 @@
   // perform a handshake, or we sent a full hello that the server
   // rejected. Here we hope to have a REJ that contains the information
   // that we need.
-  if (in->tag() != kREJ) {
+  if ((in->tag() != kREJ) && (in->tag() != kSREJ)) {
     next_state_ = STATE_NONE;
     CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE,
                                "Expected REJ");
     return;
   }
+  stateless_reject_received_ = in->tag() == kSREJ;
   string error_details;
   QuicErrorCode error = crypto_config_->ProcessRejection(
       *in, session()->connection()->clock()->WallNow(), cached,
       server_id_.is_https(), &crypto_negotiated_params_, &error_details);
+
   if (error != QUIC_NO_ERROR) {
     next_state_ = STATE_NONE;
     CloseConnectionWithDetails(error, error_details);
@@ -491,9 +511,11 @@
     const CryptoHandshakeMessage* in,
     QuicCryptoClientConfig::CachedState* cached) {
   next_state_ = STATE_NONE;
-  // We sent a CHLO that we expected to be accepted and now we're hoping
-  // for a SHLO from the server to confirm that.
-  if (in->tag() == kREJ) {
+  // We sent a CHLO that we expected to be accepted and now we're
+  // hoping for a SHLO from the server to confirm that.  First check
+  // to see whether the response was a reject, and if so, move on to
+  // the reject-processing state.
+  if ((in->tag() == kREJ) || (in->tag() == kSREJ)) {
     // alternative_decrypter will be nullptr if the original alternative
     // decrypter latched and became the primary decrypter. That happens
     // if we received a message encrypted with the INITIAL key.
diff --git a/net/quic/quic_crypto_client_stream.h b/net/quic/quic_crypto_client_stream.h
index 230cb94..a60ce780 100644
--- a/net/quic/quic_crypto_client_stream.h
+++ b/net/quic/quic_crypto_client_stream.h
@@ -209,6 +209,11 @@
   std::string verify_error_details_;
   scoped_ptr<ProofVerifyDetails> verify_details_;
 
+  // True if the server responded to a previous CHLO with a stateless
+  // reject.  Used for book-keeping between the STATE_RECV_REJ,
+  // STATE_VERIFY_PROOF*, and subsequent STATE_SEND_CHLO state.
+  bool stateless_reject_received_;
+
   DISALLOW_COPY_AND_ASSIGN(QuicCryptoClientStream);
 };
 
diff --git a/net/quic/quic_crypto_client_stream_test.cc b/net/quic/quic_crypto_client_stream_test.cc
index 417652d0..de3d68e25 100644
--- a/net/quic/quic_crypto_client_stream_test.cc
+++ b/net/quic/quic_crypto_client_stream_test.cc
@@ -200,6 +200,92 @@
   stream_->ProcessRawData(data->data(), data->length());
 }
 
+class QuicCryptoClientStreamStatelessTest : public ::testing::Test {
+ public:
+  QuicCryptoClientStreamStatelessTest()
+      : server_crypto_config_(QuicCryptoServerConfig::TESTING,
+                              QuicRandom::GetInstance()),
+        server_id_(kServerHostname, kServerPort, false, PRIVACY_MODE_DISABLED) {
+    TestClientSession* client_session = nullptr;
+    QuicCryptoClientStream* client_stream = nullptr;
+    SetupCryptoClientStreamForTest(server_id_,
+                                   /* supports_stateless_rejects= */ true,
+                                   QuicTime::Delta::FromSeconds(100000),
+                                   &client_crypto_config_, &client_connection_,
+                                   &client_session, &client_stream);
+    CHECK(client_session);
+    CHECK(client_stream);
+    client_session_.reset(client_session);
+    client_stream_.reset(client_stream);
+  }
+
+  void AdvanceHandshakeWithFakeServer() {
+    client_stream_->CryptoConnect();
+    CryptoTestUtils::AdvanceHandshake(client_connection_, client_stream_.get(),
+                                      0, server_connection_,
+                                      server_stream_.get(), 0);
+  }
+
+  // Initializes the server_stream_ for stateless rejects.
+  void InitializeFakeStatelessRejectServer() {
+    TestServerSession* server_session = nullptr;
+    QuicCryptoServerStream* server_stream = nullptr;
+    SetupCryptoServerStreamForTest(server_id_,
+                                   QuicTime::Delta::FromSeconds(100000),
+                                   &server_crypto_config_, &server_connection_,
+                                   &server_session, &server_stream);
+    CHECK(server_session);
+    CHECK(server_stream);
+    server_session_.reset(server_session);
+    server_stream_.reset(server_stream);
+    CryptoTestUtils::SetupCryptoServerConfigForTest(
+        server_connection_->clock(), server_connection_->random_generator(),
+        server_session_->config(), &server_crypto_config_);
+    server_stream_->set_use_stateless_rejects_if_peer_supported(true);
+  }
+
+  // Client crypto stream state
+  PacketSavingConnection* client_connection_;
+  scoped_ptr<TestClientSession> client_session_;
+  scoped_ptr<QuicCryptoClientStream> client_stream_;
+  QuicCryptoClientConfig client_crypto_config_;
+
+  // Server crypto stream state
+  PacketSavingConnection* server_connection_;
+  scoped_ptr<TestServerSession> server_session_;
+  QuicCryptoServerConfig server_crypto_config_;
+  scoped_ptr<QuicCryptoServerStream> server_stream_;
+  QuicServerId server_id_;
+};
+
+TEST_F(QuicCryptoClientStreamStatelessTest, StatelessReject) {
+  ValueRestore<bool> old_flag(&FLAGS_enable_quic_stateless_reject_support,
+                              true);
+
+  QuicCryptoClientConfig::CachedState* client_state =
+      client_crypto_config_.LookupOrCreate(server_id_);
+
+  EXPECT_FALSE(client_state->has_server_designated_connection_id());
+  EXPECT_CALL(*client_session_, OnProofValid(testing::_));
+
+  InitializeFakeStatelessRejectServer();
+  AdvanceHandshakeWithFakeServer();
+
+  EXPECT_FALSE(client_stream_->encryption_established());
+  EXPECT_FALSE(client_stream_->handshake_confirmed());
+  // Even though the handshake was not complete, the cached client_state is
+  // complete, and can be used for a subsequent successful handshake.
+  EXPECT_TRUE(client_state->IsComplete(QuicWallTime::FromUNIXSeconds(0)));
+
+  ASSERT_TRUE(client_state->has_server_designated_connection_id());
+  QuicConnectionId server_designated_id =
+      client_state->GetNextServerDesignatedConnectionId();
+  QuicConnectionId expected_id =
+      server_session_->connection()->random_generator()->RandUint64();
+  EXPECT_EQ(expected_id, server_designated_id);
+  EXPECT_FALSE(client_state->has_server_designated_connection_id());
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace net
diff --git a/net/quic/quic_crypto_server_stream.cc b/net/quic/quic_crypto_server_stream.cc
index 173001d..ec243c6f 100644
--- a/net/quic/quic_crypto_server_stream.cc
+++ b/net/quic/quic_crypto_server_stream.cc
@@ -9,8 +9,10 @@
 #include "net/quic/crypto/crypto_protocol.h"
 #include "net/quic/crypto/crypto_utils.h"
 #include "net/quic/crypto/quic_crypto_server_config.h"
+#include "net/quic/crypto/quic_random.h"
 #include "net/quic/proto/cached_network_parameters.pb.h"
 #include "net/quic/quic_config.h"
+#include "net/quic/quic_flags.h"
 #include "net/quic/quic_protocol.h"
 #include "net/quic/quic_session.h"
 
@@ -32,7 +34,9 @@
       crypto_config_(crypto_config),
       validate_client_hello_cb_(nullptr),
       num_handshake_messages_(0),
-      num_server_config_update_messages_sent_(0) {
+      num_server_config_update_messages_sent_(0),
+      use_stateless_rejects_if_peer_supported_(false),
+      peer_supports_stateless_rejects_(false) {
   DCHECK_EQ(Perspective::IS_SERVER, session->connection()->perspective());
 }
 
@@ -84,10 +88,14 @@
   DCHECK(validate_client_hello_cb_ != nullptr);
   validate_client_hello_cb_ = nullptr;
 
-  string error_details;
+  if (FLAGS_enable_quic_stateless_reject_support) {
+    peer_supports_stateless_rejects_ = DoesPeerSupportStatelessRejects(message);
+  }
+
   CryptoHandshakeMessage reply;
-  QuicErrorCode error = ProcessClientHello(
-      message, result, &reply, &error_details);
+  string error_details;
+  QuicErrorCode error =
+      ProcessClientHello(message, result, &reply, &error_details);
 
   if (error != QUIC_NO_ERROR) {
     CloseConnectionWithDetails(error, error_details);
@@ -99,7 +107,9 @@
     return;
   }
 
-  // If we are returning a SHLO then we accepted the handshake.
+  // If we are returning a SHLO then we accepted the handshake.  Now
+  // process the negotiated configuration options as part of the
+  // session config.
   QuicConfig* config = session()->config();
   OverrideQuicConfigDefaults(config);
   error = config->ProcessPeerHello(message, CLIENT, &error_details);
@@ -107,6 +117,7 @@
     CloseConnectionWithDetails(error, error_details);
     return;
   }
+
   session()->OnConfigNegotiated();
 
   config->ToHandshakeMessage(&reply);
@@ -223,14 +234,21 @@
   }
   previous_source_address_tokens_ = result.info.source_address_tokens;
 
+  const bool use_stateless_rejects_in_crypto_config =
+      FLAGS_enable_quic_stateless_reject_support &&
+      use_stateless_rejects_if_peer_supported_ &&
+      peer_supports_stateless_rejects_;
   QuicConnection* connection = session()->connection();
+  const QuicConnectionId server_designated_connection_id =
+      use_stateless_rejects_in_crypto_config
+          ? GenerateConnectionIdForReject(connection->connection_id())
+          : 0;
   return crypto_config_->ProcessClientHello(
       result, connection->connection_id(), connection->self_address().address(),
       connection->peer_address(), version(), connection->supported_versions(),
-      /* use_stateless_rejects= */ false,
-      /* server_designated_connection_id= */ 0, connection->clock(),
-      connection->random_generator(), &crypto_negotiated_params_, reply,
-      error_details);
+      use_stateless_rejects_in_crypto_config, server_designated_connection_id,
+      connection->clock(), connection->random_generator(),
+      &crypto_negotiated_params_, reply, error_details);
 }
 
 void QuicCryptoServerStream::OverrideQuicConfigDefaults(QuicConfig* config) {
@@ -255,4 +273,29 @@
   }
 }
 
+QuicConnectionId QuicCryptoServerStream::GenerateConnectionIdForReject(
+    QuicConnectionId connection_id) {
+  return session()->connection()->random_generator()->RandUint64();
+}
+
+// TODO(jokulik): Once stateless rejects support is inherent in the version
+// number, this function will likely go away entirely.
+// static
+bool QuicCryptoServerStream::DoesPeerSupportStatelessRejects(
+    const CryptoHandshakeMessage& message) {
+  const QuicTag* received_tags;
+  size_t received_tags_length;
+  QuicErrorCode error =
+      message.GetTaglist(kCOPT, &received_tags, &received_tags_length);
+  if (error != QUIC_NO_ERROR) {
+    return false;
+  }
+  for (size_t i = 0; i < received_tags_length; ++i) {
+    if (received_tags[i] == kSREJ) {
+      return true;
+    }
+  }
+  return false;
+}
+
 }  // namespace net
diff --git a/net/quic/quic_crypto_server_stream.h b/net/quic/quic_crypto_server_stream.h
index 7b842ae..27f6f95 100644
--- a/net/quic/quic_crypto_server_stream.h
+++ b/net/quic/quic_crypto_server_stream.h
@@ -23,6 +23,7 @@
 
 namespace test {
 class CryptoTestUtils;
+class QuicCryptoServerStreamPeer;
 }  // namespace test
 
 // Receives a notification when the server hello (SHLO) has been ACKed by the
@@ -84,6 +85,28 @@
 
   const CachedNetworkParameters* previous_cached_network_params() const;
 
+  bool use_stateless_rejects_if_peer_supported() const {
+    return use_stateless_rejects_if_peer_supported_;
+  }
+
+  // Used by the quic dispatcher to indicate that this crypto server
+  // stream should use stateless rejects, so long as stateless rejects
+  // are supported by the client.
+  void set_use_stateless_rejects_if_peer_supported(
+      bool use_stateless_rejects_if_peer_supported) {
+    use_stateless_rejects_if_peer_supported_ =
+        use_stateless_rejects_if_peer_supported;
+  }
+
+  bool peer_supports_stateless_rejects() const {
+    return peer_supports_stateless_rejects_;
+  }
+
+  void set_peer_supports_stateless_rejects(
+      bool peer_supports_stateless_rejects) {
+    peer_supports_stateless_rejects_ = peer_supports_stateless_rejects;
+  }
+
  protected:
   virtual QuicErrorCode ProcessClientHello(
       const CryptoHandshakeMessage& message,
@@ -95,8 +118,14 @@
   // before going through the parameter negotiation step.
   virtual void OverrideQuicConfigDefaults(QuicConfig* config);
 
+  // Given the current connection_id, generates a new ConnectionId to
+  // be returned with a stateless reject.
+  virtual QuicConnectionId GenerateConnectionIdForReject(
+      QuicConnectionId connection_id);
+
  private:
   friend class test::CryptoTestUtils;
+  friend class test::QuicCryptoServerStreamPeer;
 
   class ValidateCallback : public ValidateClientHelloResultCallback {
    public:
@@ -121,6 +150,11 @@
       const CryptoHandshakeMessage& message,
       const ValidateClientHelloResultCallback::Result& result);
 
+  // Checks the options on the handshake-message to see whether the
+  // peer supports stateless-rejects.
+  static bool DoesPeerSupportStatelessRejects(
+      const CryptoHandshakeMessage& message);
+
   // crypto_config_ contains crypto parameters for the handshake.
   const QuicCryptoServerConfig* crypto_config_;
 
@@ -144,6 +178,17 @@
   // Contains any source address tokens which were present in the CHLO.
   SourceAddressTokens previous_source_address_tokens_;
 
+  // If true, the server should use stateless rejects, so long as the
+  // client supports them, as indicated by
+  // peer_supports_stateless_rejects_.
+  bool use_stateless_rejects_if_peer_supported_;
+
+  // Set to true, once the server has received information from the
+  // client that it supports stateless reject.
+  //  TODO(jokulik): Remove once client stateless reject support
+  // becomes the default.
+  bool peer_supports_stateless_rejects_;
+
   DISALLOW_COPY_AND_ASSIGN(QuicCryptoServerStream);
 };
 
diff --git a/net/quic/quic_crypto_server_stream_test.cc b/net/quic/quic_crypto_server_stream_test.cc
index 2cc8e293..6874612d 100644
--- a/net/quic/quic_crypto_server_stream_test.cc
+++ b/net/quic/quic_crypto_server_stream_test.cc
@@ -18,6 +18,7 @@
 #include "net/quic/crypto/quic_encrypter.h"
 #include "net/quic/crypto/quic_random.h"
 #include "net/quic/quic_crypto_client_stream.h"
+#include "net/quic/quic_flags.h"
 #include "net/quic/quic_protocol.h"
 #include "net/quic/quic_session.h"
 #include "net/quic/test_tools/crypto_test_utils.h"
@@ -48,6 +49,15 @@
   }
 };
 
+class QuicCryptoServerStreamPeer {
+ public:
+  static bool DoesPeerSupportStatelessRejects(
+      const CryptoHandshakeMessage& message) {
+    return net::QuicCryptoServerStream::DoesPeerSupportStatelessRejects(
+        message);
+  }
+};
+
 namespace {
 
 const char kServerHostname[] = "test.example.com";
@@ -56,39 +66,65 @@
 class QuicCryptoServerStreamTest : public ::testing::TestWithParam<bool> {
  public:
   QuicCryptoServerStreamTest()
-      : connection_(new PacketSavingConnection(Perspective::IS_SERVER)),
-        session_(connection_, DefaultQuicConfig()),
-        crypto_config_(QuicCryptoServerConfig::TESTING,
-                       QuicRandom::GetInstance()),
-        stream_(&crypto_config_, &session_),
-        strike_register_client_(nullptr) {
-    session_.SetCryptoStream(&stream_);
-    // We advance the clock initially because the default time is zero and the
-    // strike register worries that we've just overflowed a uint32 time.
-    connection_->AdvanceTime(QuicTime::Delta::FromSeconds(100000));
+      : server_crypto_config_(QuicCryptoServerConfig::TESTING,
+                              QuicRandom::GetInstance()),
+        server_id_(kServerHostname, kServerPort, false, PRIVACY_MODE_DISABLED) {
     // TODO(wtc): replace this with ProofSourceForTesting() when Chromium has
     // a working ProofSourceForTesting().
-    crypto_config_.SetProofSource(CryptoTestUtils::FakeProofSourceForTesting());
-    crypto_config_.set_strike_register_no_startup_period();
+    server_crypto_config_.SetProofSource(
+        CryptoTestUtils::FakeProofSourceForTesting());
+    server_crypto_config_.set_strike_register_no_startup_period();
 
-    CryptoTestUtils::SetupCryptoServerConfigForTest(
-        connection_->clock(), connection_->random_generator(),
-        session_.config(), &crypto_config_);
+    InitializeServer();
 
     if (AsyncStrikeRegisterVerification()) {
       string orbit =
-          QuicCryptoServerConfigPeer::GetPrimaryOrbit(crypto_config_);
+          QuicCryptoServerConfigPeer::GetPrimaryOrbit(server_crypto_config_);
       strike_register_client_ = new DelayedVerifyStrikeRegisterClient(
           10000,  // strike_register_max_entries
-          static_cast<uint32>(connection_->clock()->WallNow().ToUNIXSeconds()),
+          static_cast<uint32>(
+              server_connection_->clock()->WallNow().ToUNIXSeconds()),
           60,  // strike_register_window_secs
-          reinterpret_cast<const uint8 *>(orbit.data()),
+          reinterpret_cast<const uint8*>(orbit.data()),
           StrikeRegister::NO_STARTUP_PERIOD_NEEDED);
       strike_register_client_->StartDelayingVerification();
-      crypto_config_.SetStrikeRegisterClient(strike_register_client_);
+      server_crypto_config_.SetStrikeRegisterClient(strike_register_client_);
     }
   }
 
+  // Initializes the crypto server stream state for testing.  May be
+  // called multiple times.
+  void InitializeServer() {
+    TestServerSession* server_session = nullptr;
+    QuicCryptoServerStream* server_stream = nullptr;
+    SetupCryptoServerStreamForTest(server_id_,
+                                   QuicTime::Delta::FromSeconds(100000),
+                                   &server_crypto_config_, &server_connection_,
+                                   &server_session, &server_stream);
+    CHECK(server_session);
+    CHECK(server_stream);
+    server_session_.reset(server_session);
+    server_stream_.reset(server_stream);
+    CryptoTestUtils::SetupCryptoServerConfigForTest(
+        server_connection_->clock(), server_connection_->random_generator(),
+        server_session_->config(), &server_crypto_config_);
+  }
+
+  // Initializes a fake client, and all its associated state, for
+  // testing.  May be called multiple times.
+  void InitializeFakeClient(bool supports_stateless_rejects) {
+    TestClientSession* client_session = nullptr;
+    QuicCryptoClientStream* client_stream = nullptr;
+    SetupCryptoClientStreamForTest(server_id_, supports_stateless_rejects,
+                                   QuicTime::Delta::FromSeconds(100000),
+                                   &client_crypto_config_, &client_connection_,
+                                   &client_session, &client_stream);
+    CHECK(client_session);
+    CHECK(client_stream);
+    client_session_.reset(client_session);
+    client_stream_.reset(client_stream);
+  }
+
   bool AsyncStrikeRegisterVerification() {
     return GetParam();
   }
@@ -99,16 +135,41 @@
   }
 
   int CompleteCryptoHandshake() {
-    return CryptoTestUtils::HandshakeWithFakeClient(connection_, &stream_,
-                                                    client_options_);
+    CHECK(server_connection_);
+    CHECK(server_stream_ != nullptr);
+    return CryptoTestUtils::HandshakeWithFakeClient(
+        server_connection_, server_stream_.get(), client_options_);
+  }
+
+  // Performs a single round of handshake message-exchange between the
+  // client and server.
+  void AdvanceHandshakeWithFakeClient() {
+    CHECK(server_connection_);
+    CHECK(server_stream_ != nullptr);
+    CHECK(client_session_ != nullptr);
+    CHECK(client_stream_ != nullptr);
+
+    EXPECT_CALL(*client_session_, OnProofValid(_)).Times(testing::AnyNumber());
+    client_stream_->CryptoConnect();
+    CryptoTestUtils::AdvanceHandshake(client_connection_, client_stream_.get(),
+                                      0, server_connection_,
+                                      server_stream_.get(), 0);
   }
 
  protected:
-  PacketSavingConnection* connection_;
-  TestClientSession session_;
-  QuicConfig config_;
-  QuicCryptoServerConfig crypto_config_;
-  QuicCryptoServerStream stream_;
+  // Server state
+  PacketSavingConnection* server_connection_;
+  scoped_ptr<TestServerSession> server_session_;
+  QuicCryptoServerConfig server_crypto_config_;
+  scoped_ptr<QuicCryptoServerStream> server_stream_;
+  QuicServerId server_id_;
+
+  // Client state
+  PacketSavingConnection* client_connection_;
+  QuicCryptoClientConfig client_crypto_config_;
+  scoped_ptr<TestClientSession> client_session_;
+  scoped_ptr<QuicCryptoClientStream> client_stream_;
+
   CryptoHandshakeMessage message_;
   scoped_ptr<QuicData> message_data_;
   CryptoTestUtils::FakeClientOptions client_options_;
@@ -118,8 +179,13 @@
 INSTANTIATE_TEST_CASE_P(Tests, QuicCryptoServerStreamTest, testing::Bool());
 
 TEST_P(QuicCryptoServerStreamTest, NotInitiallyConected) {
-  EXPECT_FALSE(stream_.encryption_established());
-  EXPECT_FALSE(stream_.handshake_confirmed());
+  EXPECT_FALSE(server_stream_->encryption_established());
+  EXPECT_FALSE(server_stream_->handshake_confirmed());
+}
+
+TEST_P(QuicCryptoServerStreamTest, NotInitiallySendingStatelessRejects) {
+  EXPECT_FALSE(server_stream_->use_stateless_rejects_if_peer_supported());
+  EXPECT_FALSE(server_stream_->peer_supports_stateless_rejects());
 }
 
 TEST_P(QuicCryptoServerStreamTest, ConnectedAfterCHLO) {
@@ -128,154 +194,248 @@
   //   * One to get a source-address token and certificates.
   //   * One to complete the handshake.
   EXPECT_EQ(2, CompleteCryptoHandshake());
-  EXPECT_TRUE(stream_.encryption_established());
-  EXPECT_TRUE(stream_.handshake_confirmed());
+  EXPECT_TRUE(server_stream_->encryption_established());
+  EXPECT_TRUE(server_stream_->handshake_confirmed());
 }
 
-TEST_P(QuicCryptoServerStreamTest, ZeroRTT) {
-  PacketSavingConnection* client_conn =
-      new PacketSavingConnection(Perspective::IS_CLIENT);
-  PacketSavingConnection* server_conn =
-      new PacketSavingConnection(Perspective::IS_SERVER);
-  client_conn->AdvanceTime(QuicTime::Delta::FromSeconds(100000));
-  server_conn->AdvanceTime(QuicTime::Delta::FromSeconds(100000));
+TEST_P(QuicCryptoServerStreamTest, StatelessRejectAfterCHLO) {
+  ValueRestore<bool> old_flag(&FLAGS_enable_quic_stateless_reject_support,
+                              true);
+  server_stream_->set_use_stateless_rejects_if_peer_supported(true);
 
-  QuicConfig client_config;
-  scoped_ptr<TestClientSession> client_session(
-      new TestClientSession(client_conn, client_config));
-  QuicCryptoClientConfig client_crypto_config;
+  InitializeFakeClient(/* supports_stateless_rejects= */ true);
+  AdvanceHandshakeWithFakeClient();
 
-  QuicServerId server_id(kServerHostname, kServerPort, false,
-                         PRIVACY_MODE_DISABLED);
-  scoped_ptr<QuicCryptoClientStream> client(new QuicCryptoClientStream(
-      server_id, client_session.get(), nullptr, &client_crypto_config));
-  client_session->SetCryptoStream(client.get());
+  // Check the server to make the sure the handshake did not succeed.
+  EXPECT_FALSE(server_stream_->encryption_established());
+  EXPECT_FALSE(server_stream_->handshake_confirmed());
 
-  // Do a first handshake in order to prime the client config with the server's
-  // information.
-  client->CryptoConnect();
-  CHECK_EQ(1u, client_conn->encrypted_packets_.size());
+  // Check the client state to make sure that it received a
+  // server-designated connection id.
+  QuicCryptoClientConfig::CachedState* client_state =
+      client_crypto_config_.LookupOrCreate(server_id_);
 
-  scoped_ptr<TestSession> server_session(new TestSession(server_conn, config_));
-  scoped_ptr<QuicCryptoServerStream> server(
-      new QuicCryptoServerStream(&crypto_config_, server_session.get()));
-  server_session->SetCryptoStream(server.get());
+  ASSERT_TRUE(client_state->has_server_designated_connection_id());
+  const QuicConnectionId server_designated_connection_id =
+      client_state->GetNextServerDesignatedConnectionId();
+  const QuicConnectionId expected_id =
+      reinterpret_cast<MockRandom*>(server_connection_->random_generator())
+          ->RandUint64();
+  EXPECT_EQ(expected_id, server_designated_connection_id);
+  EXPECT_FALSE(client_state->has_server_designated_connection_id());
+  ASSERT_TRUE(client_state->IsComplete(QuicWallTime::FromUNIXSeconds(0)));
+}
 
-  CryptoTestUtils::CommunicateHandshakeMessages(
-      client_conn, client.get(), server_conn, server.get());
-  EXPECT_EQ(2, client->num_sent_client_hellos());
+TEST_P(QuicCryptoServerStreamTest, ConnectedAfterStatelessHandshake) {
+  ValueRestore<bool> old_flag(&FLAGS_enable_quic_stateless_reject_support,
+                              true);
+  server_stream_->set_use_stateless_rejects_if_peer_supported(true);
 
-  // Now do another handshake, hopefully in 0-RTT.
-  LOG(INFO) << "Resetting for 0-RTT handshake attempt";
+  InitializeFakeClient(/* supports_stateless_rejects= */ true);
+  AdvanceHandshakeWithFakeClient();
 
-  client_conn = new PacketSavingConnection(Perspective::IS_CLIENT);
-  server_conn = new PacketSavingConnection(Perspective::IS_SERVER);
-  // We need to advance time past the strike-server window so that it's
-  // authoritative in this time span.
-  client_conn->AdvanceTime(QuicTime::Delta::FromSeconds(102000));
-  server_conn->AdvanceTime(QuicTime::Delta::FromSeconds(102000));
+  // On the first round, encryption will not be established.
+  EXPECT_FALSE(server_stream_->encryption_established());
+  EXPECT_FALSE(server_stream_->handshake_confirmed());
 
-  // This causes the client's nonce to be different and thus stops the
-  // strike-register from rejecting the repeated nonce.
-  reinterpret_cast<MockRandom*>(client_conn->random_generator())->ChangeValue();
-  client_session.reset(new TestClientSession(client_conn, client_config));
-  server_session.reset(new TestSession(server_conn, config_));
-  client.reset(new QuicCryptoClientStream(server_id, client_session.get(),
-                                          nullptr, &client_crypto_config));
-  client_session->SetCryptoStream(client.get());
+  // Now check the client state.
+  QuicCryptoClientConfig::CachedState* client_state =
+      client_crypto_config_.LookupOrCreate(server_id_);
 
-  server.reset(new QuicCryptoServerStream(&crypto_config_,
-                                          server_session.get()));
-  server_session->SetCryptoStream(server.get());
+  ASSERT_TRUE(client_state->has_server_designated_connection_id());
+  const QuicConnectionId server_designated_connection_id =
+      client_state->GetNextServerDesignatedConnectionId();
+  const QuicConnectionId expected_id =
+      reinterpret_cast<MockRandom*>(server_connection_->random_generator())
+          ->RandUint64();
+  EXPECT_EQ(expected_id, server_designated_connection_id);
+  EXPECT_FALSE(client_state->has_server_designated_connection_id());
+  ASSERT_TRUE(client_state->IsComplete(QuicWallTime::FromUNIXSeconds(0)));
 
-  client->CryptoConnect();
+  // Now create new client and server streams with the existing config
+  // and try the handshake again (0-RTT handshake).
+  InitializeServer();
+  server_stream_->set_use_stateless_rejects_if_peer_supported(true);
 
+  InitializeFakeClient(/* supports_stateless_rejects= */ true);
+
+  client_stream_->CryptoConnect();
   if (AsyncStrikeRegisterVerification()) {
-    EXPECT_FALSE(client->handshake_confirmed());
-    EXPECT_FALSE(server->handshake_confirmed());
+    EXPECT_FALSE(client_stream_->handshake_confirmed());
+    EXPECT_FALSE(server_stream_->handshake_confirmed());
 
     // Advance the handshake.  Expect that the server will be stuck
     // waiting for client nonce verification to complete.
     pair<size_t, size_t> messages_moved = CryptoTestUtils::AdvanceHandshake(
-        client_conn, client.get(), 0, server_conn, server.get(), 0);
+        client_connection_, client_stream_.get(), 0, server_connection_,
+        server_stream_.get(), 0);
     EXPECT_EQ(1u, messages_moved.first);
     EXPECT_EQ(0u, messages_moved.second);
     EXPECT_EQ(1, strike_register_client_->PendingVerifications());
-    EXPECT_FALSE(client->handshake_confirmed());
-    EXPECT_FALSE(server->handshake_confirmed());
+    EXPECT_FALSE(client_stream_->handshake_confirmed());
+    EXPECT_FALSE(server_stream_->handshake_confirmed());
 
     // The server handshake completes once the nonce verification completes.
     strike_register_client_->RunPendingVerifications();
-    EXPECT_FALSE(client->handshake_confirmed());
-    EXPECT_TRUE(server->handshake_confirmed());
+    EXPECT_FALSE(client_stream_->handshake_confirmed());
+    EXPECT_TRUE(server_stream_->handshake_confirmed());
 
     messages_moved = CryptoTestUtils::AdvanceHandshake(
-        client_conn, client.get(), messages_moved.first,
-        server_conn, server.get(), messages_moved.second);
+        client_connection_, client_stream_.get(), messages_moved.first,
+        server_connection_, server_stream_.get(), messages_moved.second);
     EXPECT_EQ(1u, messages_moved.first);
     EXPECT_EQ(1u, messages_moved.second);
-    EXPECT_TRUE(client->handshake_confirmed());
-    EXPECT_TRUE(server->handshake_confirmed());
   } else {
-    CryptoTestUtils::CommunicateHandshakeMessages(
-        client_conn, client.get(), server_conn, server.get());
+    AdvanceHandshakeWithFakeClient();
   }
 
-  EXPECT_EQ(1, client->num_sent_client_hellos());
+  // On the second round, encryption will be established.
+  EXPECT_TRUE(server_stream_->encryption_established());
+  EXPECT_TRUE(server_stream_->handshake_confirmed());
+}
+
+TEST_P(QuicCryptoServerStreamTest, NoStatelessRejectIfNoClientSupport) {
+  ValueRestore<bool> old_flag(&FLAGS_enable_quic_stateless_reject_support,
+                              true);
+  server_stream_->set_use_stateless_rejects_if_peer_supported(true);
+
+  // The server is configured to use stateless rejects, but the client
+  // does not support it.
+  InitializeFakeClient(/* supports_stateless_rejects= */ false);
+  AdvanceHandshakeWithFakeClient();
+
+  // Check the server to make the sure the handshake did not succeed.
+  EXPECT_FALSE(server_stream_->encryption_established());
+  EXPECT_FALSE(server_stream_->handshake_confirmed());
+
+  // Check the client state to make sure that it did not receive a
+  // server-designated connection id.
+  QuicCryptoClientConfig::CachedState* client_state =
+      client_crypto_config_.LookupOrCreate(server_id_);
+
+  ASSERT_FALSE(client_state->has_server_designated_connection_id());
+  ASSERT_TRUE(client_state->IsComplete(QuicWallTime::FromUNIXSeconds(0)));
+}
+
+TEST_P(QuicCryptoServerStreamTest, ZeroRTT) {
+  InitializeFakeClient(/* supports_stateless_rejects= */ false);
+
+  // Do a first handshake in order to prime the client config with the server's
+  // information.
+  AdvanceHandshakeWithFakeClient();
+
+  // Now do another handshake, hopefully in 0-RTT.
+  DVLOG(1) << "Resetting for 0-RTT handshake attempt";
+  InitializeFakeClient(/* supports_stateless_rejects= */ false);
+  InitializeServer();
+
+  client_stream_->CryptoConnect();
+
+  if (AsyncStrikeRegisterVerification()) {
+    EXPECT_FALSE(client_stream_->handshake_confirmed());
+    EXPECT_FALSE(server_stream_->handshake_confirmed());
+
+    // Advance the handshake.  Expect that the server will be stuck
+    // waiting for client nonce verification to complete.
+    pair<size_t, size_t> messages_moved = CryptoTestUtils::AdvanceHandshake(
+        client_connection_, client_stream_.get(), 0, server_connection_,
+        server_stream_.get(), 0);
+    EXPECT_EQ(1u, messages_moved.first);
+    EXPECT_EQ(0u, messages_moved.second);
+    EXPECT_EQ(1, strike_register_client_->PendingVerifications());
+    EXPECT_FALSE(client_stream_->handshake_confirmed());
+    EXPECT_FALSE(server_stream_->handshake_confirmed());
+
+    // The server handshake completes once the nonce verification completes.
+    strike_register_client_->RunPendingVerifications();
+    EXPECT_FALSE(client_stream_->handshake_confirmed());
+    EXPECT_TRUE(server_stream_->handshake_confirmed());
+
+    messages_moved = CryptoTestUtils::AdvanceHandshake(
+        client_connection_, client_stream_.get(), messages_moved.first,
+        server_connection_, server_stream_.get(), messages_moved.second);
+    EXPECT_EQ(1u, messages_moved.first);
+    EXPECT_EQ(1u, messages_moved.second);
+    EXPECT_TRUE(client_stream_->handshake_confirmed());
+    EXPECT_TRUE(server_stream_->handshake_confirmed());
+  } else {
+    CryptoTestUtils::CommunicateHandshakeMessages(
+        client_connection_, client_stream_.get(), server_connection_,
+        server_stream_.get());
+  }
+
+  EXPECT_EQ(1, client_stream_->num_sent_client_hellos());
 }
 
 TEST_P(QuicCryptoServerStreamTest, MessageAfterHandshake) {
   CompleteCryptoHandshake();
-  EXPECT_CALL(*connection_, SendConnectionClose(
-      QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE));
+  EXPECT_CALL(
+      *server_connection_,
+      SendConnectionClose(QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE));
   message_.set_tag(kCHLO);
   ConstructHandshakeMessage();
-  stream_.ProcessRawData(message_data_->data(), message_data_->length());
+  server_stream_->ProcessRawData(message_data_->data(),
+                                 message_data_->length());
 }
 
 TEST_P(QuicCryptoServerStreamTest, BadMessageType) {
   message_.set_tag(kSHLO);
   ConstructHandshakeMessage();
-  EXPECT_CALL(*connection_, SendConnectionClose(
-      QUIC_INVALID_CRYPTO_MESSAGE_TYPE));
-  stream_.ProcessRawData(message_data_->data(), message_data_->length());
+  EXPECT_CALL(*server_connection_,
+              SendConnectionClose(QUIC_INVALID_CRYPTO_MESSAGE_TYPE));
+  server_stream_->ProcessRawData(message_data_->data(),
+                                 message_data_->length());
 }
 
 TEST_P(QuicCryptoServerStreamTest, WithoutCertificates) {
-  crypto_config_.SetProofSource(nullptr);
+  server_crypto_config_.SetProofSource(nullptr);
   client_options_.dont_verify_certs = true;
 
   // Only 2 client hellos need to be sent in the no-certs case: one to get the
   // source-address token and the second to finish.
   EXPECT_EQ(2, CompleteCryptoHandshake());
-  EXPECT_TRUE(stream_.encryption_established());
-  EXPECT_TRUE(stream_.handshake_confirmed());
+  EXPECT_TRUE(server_stream_->encryption_established());
+  EXPECT_TRUE(server_stream_->handshake_confirmed());
 }
 
 TEST_P(QuicCryptoServerStreamTest, ChannelID) {
   client_options_.channel_id_enabled = true;
   client_options_.channel_id_source_async = false;
   // CompleteCryptoHandshake verifies
-  // stream_.crypto_negotiated_params().channel_id is correct.
+  // server_stream_->crypto_negotiated_params().channel_id is correct.
   EXPECT_EQ(2, CompleteCryptoHandshake());
-  EXPECT_TRUE(stream_.encryption_established());
-  EXPECT_TRUE(stream_.handshake_confirmed());
+  EXPECT_TRUE(server_stream_->encryption_established());
+  EXPECT_TRUE(server_stream_->handshake_confirmed());
 }
 
 TEST_P(QuicCryptoServerStreamTest, ChannelIDAsync) {
   client_options_.channel_id_enabled = true;
   client_options_.channel_id_source_async = true;
   // CompleteCryptoHandshake verifies
-  // stream_.crypto_negotiated_params().channel_id is correct.
+  // server_stream_->crypto_negotiated_params().channel_id is correct.
   EXPECT_EQ(2, CompleteCryptoHandshake());
-  EXPECT_TRUE(stream_.encryption_established());
-  EXPECT_TRUE(stream_.handshake_confirmed());
+  EXPECT_TRUE(server_stream_->encryption_established());
+  EXPECT_TRUE(server_stream_->handshake_confirmed());
 }
 
 TEST_P(QuicCryptoServerStreamTest, OnlySendSCUPAfterHandshakeComplete) {
   // An attempt to send a SCUP before completing handshake should fail.
-  stream_.SendServerConfigUpdate(nullptr);
-  EXPECT_EQ(0, stream_.num_server_config_update_messages_sent());
+  server_stream_->SendServerConfigUpdate(nullptr);
+  EXPECT_EQ(0, server_stream_->num_server_config_update_messages_sent());
+}
+
+TEST_P(QuicCryptoServerStreamTest, DoesPeerSupportStatelessRejects) {
+  ConstructHandshakeMessage();
+  QuicConfig stateless_reject_config = DefaultQuicConfigStatelessRejects();
+  stateless_reject_config.ToHandshakeMessage(&message_);
+  EXPECT_TRUE(
+      QuicCryptoServerStreamPeer::DoesPeerSupportStatelessRejects(message_));
+
+  message_.Clear();
+  QuicConfig stateful_reject_config = DefaultQuicConfig();
+  stateful_reject_config.ToHandshakeMessage(&message_);
+  EXPECT_FALSE(
+      QuicCryptoServerStreamPeer::DoesPeerSupportStatelessRejects(message_));
 }
 
 }  // namespace
diff --git a/net/quic/quic_flags.cc b/net/quic/quic_flags.cc
index b1c53b9..cf3b262 100644
--- a/net/quic/quic_flags.cc
+++ b/net/quic/quic_flags.cc
@@ -39,9 +39,9 @@
 // no configured limit.
 int64 FLAGS_quic_time_wait_list_max_connections = 50000;
 
-// If true, use the peer's receive buffer size to set the max CWND used by the
-// send algorithms.
-bool FLAGS_quic_limit_max_cwnd_to_receive_buffer = true;
-
 // Enables server-side support for QUIC stateless rejects.
 bool FLAGS_enable_quic_stateless_reject_support = false;
+
+// If true, stop processing quic data as soon as the connection is closed rather
+// than processing a full packet.
+bool FLAGS_quic_stop_early = true;
diff --git a/net/quic/quic_flags.h b/net/quic/quic_flags.h
index 2ad52e6..30bf0ae8 100644
--- a/net/quic/quic_flags.h
+++ b/net/quic/quic_flags.h
@@ -17,7 +17,7 @@
 NET_EXPORT_PRIVATE extern bool FLAGS_quic_too_many_outstanding_packets;
 NET_EXPORT_PRIVATE extern int64 FLAGS_quic_time_wait_list_seconds;
 NET_EXPORT_PRIVATE extern int64 FLAGS_quic_time_wait_list_max_connections;
-NET_EXPORT_PRIVATE extern bool FLAGS_quic_limit_max_cwnd_to_receive_buffer;
 NET_EXPORT_PRIVATE extern bool FLAGS_enable_quic_stateless_reject_support;
+NET_EXPORT_PRIVATE extern bool FLAGS_quic_stop_early;
 
 #endif  // NET_QUIC_QUIC_FLAGS_H_
diff --git a/net/quic/quic_flow_controller.cc b/net/quic/quic_flow_controller.cc
index d95541e..af79b956 100644
--- a/net/quic/quic_flow_controller.cc
+++ b/net/quic/quic_flow_controller.cc
@@ -92,16 +92,16 @@
   // (receive window offset - consumed bytes) < (max window / 2).
   // This is behaviour copied from SPDY.
   DCHECK_LT(bytes_consumed_, receive_window_offset_);
-  QuicStreamOffset consumed_window = receive_window_offset_ - bytes_consumed_;
+  QuicStreamOffset available_window = receive_window_offset_ - bytes_consumed_;
   QuicByteCount threshold = (max_receive_window_ / 2);
 
-  if (consumed_window < threshold) {
+  if (available_window < threshold) {
     // Update our receive window.
-    receive_window_offset_ += (max_receive_window_ - consumed_window);
+    receive_window_offset_ += (max_receive_window_ - available_window);
 
     DVLOG(1) << ENDPOINT << "Sending WindowUpdate frame for stream " << id_
              << ", consumed bytes: " << bytes_consumed_
-             << ", consumed window: " << consumed_window
+             << ", available window: " << available_window
              << ", and threshold: " << threshold
              << ", and max recvw: " << max_receive_window_
              << ". New receive window offset is: " << receive_window_offset_;
diff --git a/net/quic/quic_network_transaction_unittest.cc b/net/quic/quic_network_transaction_unittest.cc
index ed0d740..b78bde6 100644
--- a/net/quic/quic_network_transaction_unittest.cc
+++ b/net/quic/quic_network_transaction_unittest.cc
@@ -242,7 +242,7 @@
     params_.proxy_service = proxy_service_.get();
     params_.ssl_config_service = ssl_config_service_.get();
     params_.http_auth_handler_factory = auth_handler_factory_.get();
-    params_.http_server_properties = http_server_properties.GetWeakPtr();
+    params_.http_server_properties = http_server_properties_.GetWeakPtr();
     params_.quic_supported_versions = SupportedVersions(GetParam());
 
     if (use_next_protos) {
@@ -325,22 +325,22 @@
     crypto_client_stream_factory_.set_handshake_mode(handshake_mode);
     HostPortPair host_port_pair = HostPortPair::FromURL(request_.url);
     AlternativeService alternative_service(QUIC, host_port_pair.host(), 80);
-    session_->http_server_properties()->SetAlternativeService(
-        host_port_pair, alternative_service, 1.0);
+    http_server_properties_.SetAlternativeService(host_port_pair,
+                                                  alternative_service, 1.0);
   }
 
   void ExpectBrokenAlternateProtocolMapping() {
     const HostPortPair origin = HostPortPair::FromURL(request_.url);
     const AlternativeService alternative_service =
-        session_->http_server_properties()->GetAlternativeService(origin);
+        http_server_properties_.GetAlternativeService(origin);
     EXPECT_NE(UNINITIALIZED_ALTERNATE_PROTOCOL, alternative_service.protocol);
-    EXPECT_TRUE(session_->http_server_properties()->IsAlternativeServiceBroken(
+    EXPECT_TRUE(http_server_properties_.IsAlternativeServiceBroken(
         alternative_service));
   }
 
   void ExpectQuicAlternateProtocolMapping() {
     const AlternativeService alternative_service =
-        session_->http_server_properties()->GetAlternativeService(
+        http_server_properties_.GetAlternativeService(
             HostPortPair::FromURL(request_.url));
     EXPECT_EQ(QUIC, alternative_service.protocol);
   }
@@ -363,7 +363,7 @@
   scoped_ptr<ProxyService> proxy_service_;
   scoped_ptr<HttpAuthHandlerFactory> auth_handler_factory_;
   MockRandom random_generator_;
-  HttpServerPropertiesImpl http_server_properties;
+  HttpServerPropertiesImpl http_server_properties_;
   HttpNetworkSession::Params params_;
   HttpRequestInfo request_;
   BoundTestNetLog net_log_;
@@ -623,18 +623,16 @@
 
   AlternativeService alternative_service(QUIC,
                                          HostPortPair::FromURL(request_.url));
-  session_->http_server_properties()->MarkAlternativeServiceRecentlyBroken(
+  http_server_properties_.MarkAlternativeServiceRecentlyBroken(
       alternative_service);
-  EXPECT_TRUE(
-      session_->http_server_properties()->WasAlternativeServiceRecentlyBroken(
-          alternative_service));
+  EXPECT_TRUE(http_server_properties_.WasAlternativeServiceRecentlyBroken(
+      alternative_service));
 
   SendRequestAndExpectHttpResponse("hello world");
   SendRequestAndExpectQuicResponse("hello!");
 
-  EXPECT_FALSE(
-      session_->http_server_properties()->WasAlternativeServiceRecentlyBroken(
-          alternative_service));
+  EXPECT_FALSE(http_server_properties_.WasAlternativeServiceRecentlyBroken(
+      alternative_service));
 }
 
 TEST_P(QuicNetworkTransactionTest, UseAlternateProtocolProbabilityForQuic) {
@@ -1256,7 +1254,7 @@
       cert->VerifyNameMatch("www.example.org", &common_name_fallback_used));
   ProofVerifyDetailsChromium verify_details;
   verify_details.cert_verify_result.verified_cert = cert;
-  crypto_client_stream_factory_.set_proof_verify_details(&verify_details);
+  crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
 
   request_.url = GURL("https://www.example.org:443");
   AddHangingNonAlternateProtocolSocketData();
diff --git a/net/quic/quic_sent_packet_manager.cc b/net/quic/quic_sent_packet_manager.cc
index 2beef66b..c81c93df 100644
--- a/net/quic/quic_sent_packet_manager.cc
+++ b/net/quic/quic_sent_packet_manager.cc
@@ -166,10 +166,8 @@
     receive_buffer_bytes_ =
         max(kMinSocketReceiveBuffer,
             static_cast<QuicByteCount>(config.ReceivedSocketReceiveBuffer()));
-    if (FLAGS_quic_limit_max_cwnd_to_receive_buffer) {
-      send_algorithm_->SetMaxCongestionWindow(receive_buffer_bytes_ *
-                                              kUsableRecieveBufferFraction);
-    }
+    send_algorithm_->SetMaxCongestionWindow(receive_buffer_bytes_ *
+                                            kUsableRecieveBufferFraction);
   }
   send_algorithm_->SetFromConfig(config, perspective_);
 
@@ -783,11 +781,6 @@
   if (pending_timer_transmission_count_ > 0) {
     return QuicTime::Delta::Zero();
   }
-  if (!FLAGS_quic_limit_max_cwnd_to_receive_buffer &&
-      unacked_packets_.bytes_in_flight() >=
-          kUsableRecieveBufferFraction * receive_buffer_bytes_) {
-    return QuicTime::Delta::Infinite();
-  }
   return send_algorithm_->TimeUntilSend(
       now, unacked_packets_.bytes_in_flight(), retransmittable);
 }
diff --git a/net/quic/quic_sent_packet_manager_test.cc b/net/quic/quic_sent_packet_manager_test.cc
index 7887c67..2b55382 100644
--- a/net/quic/quic_sent_packet_manager_test.cc
+++ b/net/quic/quic_sent_packet_manager_test.cc
@@ -1584,10 +1584,8 @@
   QuicConfig client_config;
   QuicConfigPeer::SetReceivedSocketReceiveBuffer(&client_config, 1024);
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
-  if (FLAGS_quic_limit_max_cwnd_to_receive_buffer) {
-    EXPECT_CALL(*send_algorithm_,
-                SetMaxCongestionWindow(kMinSocketReceiveBuffer * 0.95));
-  }
+  EXPECT_CALL(*send_algorithm_,
+              SetMaxCongestionWindow(kMinSocketReceiveBuffer * 0.95));
   EXPECT_CALL(*send_algorithm_, PacingRate())
       .WillRepeatedly(Return(QuicBandwidth::Zero()));
   EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange());
@@ -1610,10 +1608,8 @@
     manager_.OnPacketSent(&packet, 0, clock_.Now(), 1024,
                           NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA);
   }
-  if (FLAGS_quic_limit_max_cwnd_to_receive_buffer) {
-    EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _, _))
-        .WillOnce(Return(QuicTime::Delta::Infinite()));
-  }
+  EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _, _))
+      .WillOnce(Return(QuicTime::Delta::Infinite()));
   EXPECT_EQ(QuicTime::Delta::Infinite(),
             manager_.TimeUntilSend(clock_.Now(), HAS_RETRANSMITTABLE_DATA));
 }
@@ -1635,10 +1631,8 @@
     manager_.OnPacketSent(&packet, 0, clock_.Now(), 1024,
                           NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA);
   }
-  if (FLAGS_quic_limit_max_cwnd_to_receive_buffer) {
-    EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _, _))
-        .WillOnce(Return(QuicTime::Delta::Infinite()));
-  }
+  EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _, _))
+      .WillOnce(Return(QuicTime::Delta::Infinite()));
   EXPECT_EQ(QuicTime::Delta::Infinite(),
             manager_.TimeUntilSend(clock_.Now(), HAS_RETRANSMITTABLE_DATA));
 }
diff --git a/net/quic/quic_session.cc b/net/quic/quic_session.cc
index 0be72eba..570eab7 100644
--- a/net/quic/quic_session.cc
+++ b/net/quic/quic_session.cc
@@ -103,7 +103,6 @@
       config_(config),
       max_open_streams_(config_.MaxStreamsPerConnection()),
       next_stream_id_(perspective() == Perspective::IS_SERVER ? 2 : 5),
-      write_blocked_streams_(true),
       largest_peer_created_stream_id_(0),
       error_(QUIC_NO_ERROR),
       flow_controller_(connection_.get(),
@@ -134,7 +133,7 @@
 }
 
 void QuicSession::OnStreamFrames(const vector<QuicStreamFrame>& frames) {
-  for (size_t i = 0; i < frames.size(); ++i) {
+  for (size_t i = 0; i < frames.size() && connection_->connected(); ++i) {
     // TODO(rch) deal with the error case of stream id 0.
     const QuicStreamFrame& frame = frames[i];
     QuicStreamId stream_id = frame.stream_id;
@@ -153,6 +152,9 @@
       continue;
     }
     stream->OnStreamFrame(frames[i]);
+    if (!connection_->connected()) {
+      return;
+    }
   }
 }
 
diff --git a/net/quic/quic_stream_factory_test.cc b/net/quic/quic_stream_factory_test.cc
index b5a1b5b1..fc07174 100644
--- a/net/quic/quic_stream_factory_test.cc
+++ b/net/quic/quic_stream_factory_test.cc
@@ -682,7 +682,7 @@
   ProofVerifyDetailsChromium verify_details;
   verify_details.cert_verify_result.verified_cert = test_cert;
   verify_details.cert_verify_result.is_issued_by_known_root = true;
-  crypto_client_stream_factory_.set_proof_verify_details(&verify_details);
+  crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
 
   host_resolver_.set_synchronous_mode(true);
   host_resolver_.rules()->AddIPLiteralRule(server1.host(), "192.168.0.1", "");
@@ -746,7 +746,7 @@
   ProofVerifyDetailsChromium verify_details;
   verify_details.cert_verify_result.verified_cert = test_cert;
   verify_details.cert_verify_result.is_issued_by_known_root = true;
-  crypto_client_stream_factory_.set_proof_verify_details(&verify_details);
+  crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
 
   host_resolver_.set_synchronous_mode(true);
   host_resolver_.rules()->AddIPLiteralRule(server1.host(), "192.168.0.1", "");
@@ -815,8 +815,7 @@
   ASSERT_NE(static_cast<X509Certificate*>(nullptr), test_cert.get());
   ProofVerifyDetailsChromium verify_details;
   verify_details.cert_verify_result.verified_cert = test_cert;
-  crypto_client_stream_factory_.set_proof_verify_details(&verify_details);
-
+  crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
 
   host_resolver_.set_synchronous_mode(true);
   host_resolver_.rules()->AddIPLiteralRule(server1.host(), "192.168.0.1", "");
@@ -884,8 +883,7 @@
   verify_details.cert_verify_result.is_issued_by_known_root = true;
   verify_details.cert_verify_result.public_key_hashes.push_back(
       test::GetTestHashValue(primary_pin));
-  crypto_client_stream_factory_.set_proof_verify_details(&verify_details);
-
+  crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
 
   host_resolver_.set_synchronous_mode(true);
   host_resolver_.rules()->AddIPLiteralRule(server1.host(), "192.168.0.1", "");
@@ -954,8 +952,7 @@
   verify_details.cert_verify_result.is_issued_by_known_root = true;
   verify_details.cert_verify_result.public_key_hashes.push_back(
       test::GetTestHashValue(primary_pin));
-  crypto_client_stream_factory_.set_proof_verify_details(&verify_details);
-
+  crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
 
   host_resolver_.set_synchronous_mode(true);
   host_resolver_.rules()->AddIPLiteralRule(server1.host(), "192.168.0.1", "");
@@ -1025,13 +1022,20 @@
   scoped_refptr<X509Certificate> test_cert(
       ImportCertFromFile(certs_dir, "spdy_pooling.pem"));
   ASSERT_NE(static_cast<X509Certificate*>(nullptr), test_cert.get());
-  ProofVerifyDetailsChromium verify_details;
-  verify_details.cert_verify_result.verified_cert = test_cert;
-  verify_details.cert_verify_result.is_issued_by_known_root = true;
-  verify_details.cert_verify_result.public_key_hashes.push_back(
-      test::GetTestHashValue(bad_pin));
-  crypto_client_stream_factory_.set_proof_verify_details(&verify_details);
 
+  ProofVerifyDetailsChromium verify_details1;
+  verify_details1.cert_verify_result.verified_cert = test_cert;
+  verify_details1.cert_verify_result.is_issued_by_known_root = true;
+  verify_details1.cert_verify_result.public_key_hashes.push_back(
+      test::GetTestHashValue(bad_pin));
+  crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details1);
+
+  ProofVerifyDetailsChromium verify_details2;
+  verify_details2.cert_verify_result.verified_cert = test_cert;
+  verify_details2.cert_verify_result.is_issued_by_known_root = true;
+  verify_details2.cert_verify_result.public_key_hashes.push_back(
+      test::GetTestHashValue(primary_pin));
+  crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details2);
 
   host_resolver_.set_synchronous_mode(true);
   host_resolver_.rules()->AddIPLiteralRule(server1.host(), "192.168.0.1", "");
diff --git a/net/quic/quic_utils_test.cc b/net/quic/quic_utils_test.cc
index d741abb..1a3a1e5 100644
--- a/net/quic/quic_utils_test.cc
+++ b/net/quic/quic_utils_test.cc
@@ -88,10 +88,9 @@
   QuicTagVector empty_options = QuicUtils::ParseQuicConnectionOptions("");
   EXPECT_EQ(0ul, empty_options.size());
 
-  QuicTagVector parsed_options = QuicUtils::ParseQuicConnectionOptions(
-      "PACE,TIMER,TBBR,REJ");
+  QuicTagVector parsed_options =
+      QuicUtils::ParseQuicConnectionOptions("TIMER,TBBR,REJ");
   QuicTagVector expected_options;
-  expected_options.push_back(kPACE);
   expected_options.push_back(kTIME);
   expected_options.push_back(kTBBR);
   expected_options.push_back(kREJ);
diff --git a/net/quic/quic_write_blocked_list.cc b/net/quic/quic_write_blocked_list.cc
index 36854e5..e763d17 100644
--- a/net/quic/quic_write_blocked_list.cc
+++ b/net/quic/quic_write_blocked_list.cc
@@ -11,10 +11,8 @@
 const QuicPriority QuicWriteBlockedList::kLowestPriority =
     static_cast<QuicPriority>(net::kLowestPriority);
 
-QuicWriteBlockedList::QuicWriteBlockedList(bool avoid_duplicate_streams)
-    : base_write_blocked_list_(avoid_duplicate_streams),
-      crypto_stream_blocked_(false),
-      headers_stream_blocked_(false) {
+QuicWriteBlockedList::QuicWriteBlockedList()
+    : crypto_stream_blocked_(false), headers_stream_blocked_(false) {
 }
 
 QuicWriteBlockedList::~QuicWriteBlockedList() {}
diff --git a/net/quic/quic_write_blocked_list.h b/net/quic/quic_write_blocked_list.h
index cb6a89a..3c08badd 100644
--- a/net/quic/quic_write_blocked_list.h
+++ b/net/quic/quic_write_blocked_list.h
@@ -24,7 +24,7 @@
   static const QuicPriority kHighestPriority;
   static const QuicPriority kLowestPriority;
 
-  explicit QuicWriteBlockedList(bool avoid_duplicate_streams);
+  QuicWriteBlockedList();
   ~QuicWriteBlockedList();
 
   bool HasWriteBlockedDataStreams() const {
@@ -61,7 +61,6 @@
     SpdyPriority priority =
         base_write_blocked_list_.GetHighestPriorityWriteBlockedList();
     QuicStreamId id = base_write_blocked_list_.PopFront(priority);
-    blocked_streams_.erase(id);
     return id;
   }
 
@@ -80,15 +79,8 @@
       return;
     }
 
-    if (!base_write_blocked_list_.avoids_inserting_duplicates() &&
-        blocked_streams_.find(stream_id) != blocked_streams_.end()) {
-      DVLOG(1) << "Stream " << stream_id << " already in write blocked list.";
-      return;
-    }
-
     base_write_blocked_list_.PushBack(
         stream_id, static_cast<SpdyPriority>(priority));
-    blocked_streams_.insert(stream_id);
     return;
   }
 
@@ -100,11 +92,6 @@
   bool crypto_stream_blocked_;
   bool headers_stream_blocked_;
 
-  // Keep track of write blocked streams in a set for faster membership checking
-  // than iterating over the base_write_blocked_list_. The contents of this set
-  // should mirror the contents of base_write_blocked_list_.
-  std::set<QuicStreamId> blocked_streams_;
-
   DISALLOW_COPY_AND_ASSIGN(QuicWriteBlockedList);
 };
 
diff --git a/net/quic/quic_write_blocked_list_test.cc b/net/quic/quic_write_blocked_list_test.cc
index ec59268..0633f63 100644
--- a/net/quic/quic_write_blocked_list_test.cc
+++ b/net/quic/quic_write_blocked_list_test.cc
@@ -12,7 +12,7 @@
 namespace {
 
 TEST(QuicWriteBlockedListTest, PriorityOrder) {
-  QuicWriteBlockedList write_blocked_list(true);
+  QuicWriteBlockedList write_blocked_list;
 
   // Mark streams blocked in roughly reverse priority order, and
   // verify that streams are sorted.
@@ -46,7 +46,7 @@
 }
 
 TEST(QuicWriteBlockedListTest, CryptoStream) {
-  QuicWriteBlockedList write_blocked_list(true);
+  QuicWriteBlockedList write_blocked_list;
   write_blocked_list.PushBack(kCryptoStreamId,
                               QuicWriteBlockedList::kHighestPriority);
 
@@ -58,7 +58,7 @@
 }
 
 TEST(QuicWriteBlockedListTest, HeadersStream) {
-  QuicWriteBlockedList write_blocked_list(true);
+  QuicWriteBlockedList write_blocked_list;
   write_blocked_list.PushBack(kHeadersStreamId,
                               QuicWriteBlockedList::kHighestPriority);
 
@@ -70,7 +70,7 @@
 }
 
 TEST(QuicWriteBlockedListTest, VerifyHeadersStream) {
-  QuicWriteBlockedList write_blocked_list(true);
+  QuicWriteBlockedList write_blocked_list;
   write_blocked_list.PushBack(5,
                               QuicWriteBlockedList::kHighestPriority);
   write_blocked_list.PushBack(kHeadersStreamId,
@@ -90,7 +90,7 @@
 
 TEST(QuicWriteBlockedListTest, NoDuplicateEntries) {
   // Test that QuicWriteBlockedList doesn't allow duplicate entries.
-  QuicWriteBlockedList write_blocked_list(true);
+  QuicWriteBlockedList write_blocked_list;
 
   // Try to add a stream to the write blocked list multiple times at the same
   // priority.
diff --git a/net/quic/test_tools/mock_crypto_client_stream_factory.cc b/net/quic/test_tools/mock_crypto_client_stream_factory.cc
index 5088c43..ebb5611 100644
--- a/net/quic/test_tools/mock_crypto_client_stream_factory.cc
+++ b/net/quic/test_tools/mock_crypto_client_stream_factory.cc
@@ -13,10 +13,12 @@
 
 namespace net {
 
+MockCryptoClientStreamFactory::~MockCryptoClientStreamFactory() {
+}
+
 MockCryptoClientStreamFactory::MockCryptoClientStreamFactory()
     : handshake_mode_(MockCryptoClientStream::CONFIRM_HANDSHAKE),
-      last_stream_(nullptr),
-      proof_verify_details_(nullptr) {
+      last_stream_(nullptr) {
 }
 
 QuicCryptoClientStream*
@@ -24,9 +26,14 @@
     const QuicServerId& server_id,
     QuicClientSession* session,
     QuicCryptoClientConfig* crypto_config) {
-  last_stream_ = new MockCryptoClientStream(
-      server_id, session, nullptr, crypto_config, handshake_mode_,
-      proof_verify_details_);
+  const ProofVerifyDetails* proof_verify_details = nullptr;
+  if (!proof_verify_details_queue_.empty()) {
+    proof_verify_details = proof_verify_details_queue_.front();
+    proof_verify_details_queue_.pop();
+  }
+  last_stream_ =
+      new MockCryptoClientStream(server_id, session, nullptr, crypto_config,
+                                 handshake_mode_, proof_verify_details);
   return last_stream_;
 }
 
diff --git a/net/quic/test_tools/mock_crypto_client_stream_factory.h b/net/quic/test_tools/mock_crypto_client_stream_factory.h
index b138c70e..c96db26a 100644
--- a/net/quic/test_tools/mock_crypto_client_stream_factory.h
+++ b/net/quic/test_tools/mock_crypto_client_stream_factory.h
@@ -5,6 +5,7 @@
 #ifndef NET_QUIC_TEST_TOOLS_MOCK_CRYPTO_CLIENT_STREAM_FACTORY_H_
 #define NET_QUIC_TEST_TOOLS_MOCK_CRYPTO_CLIENT_STREAM_FACTORY_H_
 
+#include <queue>
 #include <string>
 
 #include "net/quic/quic_crypto_client_stream.h"
@@ -18,7 +19,7 @@
 class MockCryptoClientStreamFactory : public QuicCryptoClientStreamFactory  {
  public:
   MockCryptoClientStreamFactory();
-  ~MockCryptoClientStreamFactory() override {}
+  ~MockCryptoClientStreamFactory() override;
 
   QuicCryptoClientStream* CreateQuicCryptoClientStream(
       const QuicServerId& server_id,
@@ -30,9 +31,9 @@
     handshake_mode_ = handshake_mode;
   }
 
-  void set_proof_verify_details(
-      const ProofVerifyDetails* proof_verify_details) {
-    proof_verify_details_ = proof_verify_details;
+  // The caller keeps ownership of |proof_verify_details|.
+  void AddProofVerifyDetails(const ProofVerifyDetails* proof_verify_details) {
+    proof_verify_details_queue_.push(proof_verify_details);
   }
 
   MockCryptoClientStream* last_stream() const {
@@ -42,7 +43,7 @@
  private:
   MockCryptoClientStream::HandshakeMode handshake_mode_;
   MockCryptoClientStream* last_stream_;
-  const ProofVerifyDetails* proof_verify_details_;
+  std::queue<const ProofVerifyDetails*> proof_verify_details_queue_;
 
   DISALLOW_COPY_AND_ASSIGN(MockCryptoClientStreamFactory);
 };
diff --git a/net/quic/test_tools/quic_test_utils.cc b/net/quic/test_tools/quic_test_utils.cc
index 2b426e8b..676a37d 100644
--- a/net/quic/test_tools/quic_test_utils.cc
+++ b/net/quic/test_tools/quic_test_utils.cc
@@ -381,6 +381,14 @@
   return crypto_stream_;
 }
 
+TestServerSession::TestServerSession(const QuicConfig& config,
+                                     QuicConnection* connection)
+    : QuicServerSession(config, connection, nullptr) {
+}
+
+TestServerSession::~TestServerSession() {
+}
+
 MockPacketWriter::MockPacketWriter() {
 }
 
@@ -711,6 +719,14 @@
   return config;
 }
 
+QuicConfig DefaultQuicConfigStatelessRejects() {
+  QuicConfig config = DefaultQuicConfig();
+  QuicTagVector copt;
+  copt.push_back(kSREJ);
+  config.SetConnectionOptionsToSend(copt);
+  return config;
+}
+
 QuicVersionVector SupportedVersions(QuicVersion version) {
   QuicVersionVector versions;
   versions.push_back(version);
@@ -760,10 +776,8 @@
   // in a different way, so TestWriterFactory::OnPacketSent might never be
   // called.
   factory_->current_writer_ = this;
-  return tools::QuicPerConnectionPacketWriter::WritePacket(buffer,
-                                                    buf_len,
-                                                    self_address,
-                                                    peer_address);
+  return tools::QuicPerConnectionPacketWriter::WritePacket(
+      buffer, buf_len, self_address, peer_address);
 }
 
 MockQuicConnectionDebugVisitor::MockQuicConnectionDebugVisitor() {
@@ -772,5 +786,60 @@
 MockQuicConnectionDebugVisitor::~MockQuicConnectionDebugVisitor() {
 }
 
+void SetupCryptoClientStreamForTest(
+    QuicServerId server_id,
+    bool supports_stateless_rejects,
+    QuicTime::Delta connection_start_time,
+    QuicCryptoClientConfig* crypto_client_config,
+    PacketSavingConnection** client_connection,
+    TestClientSession** client_session,
+    QuicCryptoClientStream** client_stream) {
+  CHECK(crypto_client_config);
+  CHECK(client_connection);
+  CHECK(client_session);
+  CHECK(client_stream);
+  CHECK(!connection_start_time.IsZero())
+      << "Connections must start at non-zero times, otherwise the "
+      << "strike-register will be unhappy.";
+
+  QuicConfig config = supports_stateless_rejects
+                          ? DefaultQuicConfigStatelessRejects()
+                          : DefaultQuicConfig();
+  *client_connection = new PacketSavingConnection(Perspective::IS_CLIENT);
+  *client_session = new TestClientSession(*client_connection, config);
+  *client_stream = new QuicCryptoClientStream(server_id, *client_session,
+                                              nullptr, crypto_client_config);
+  (*client_session)->SetCryptoStream(*client_stream);
+  (*client_connection)->AdvanceTime(connection_start_time);
+}
+
+// Setup or create?
+void SetupCryptoServerStreamForTest(
+    QuicServerId server_id,
+    QuicTime::Delta connection_start_time,
+    QuicCryptoServerConfig* server_crypto_config,
+    PacketSavingConnection** server_connection,
+    TestServerSession** server_session,
+    QuicCryptoServerStream** server_stream) {
+  CHECK(server_crypto_config);
+  CHECK(server_connection);
+  CHECK(server_session);
+  CHECK(server_stream);
+  CHECK(!connection_start_time.IsZero())
+      << "Connections must start at non-zero times, otherwise the "
+      << "strike-register will be unhappy.";
+
+  *server_connection = new PacketSavingConnection(Perspective::IS_SERVER);
+  *server_session =
+      new TestServerSession(DefaultQuicConfig(), *server_connection);
+  *server_stream =
+      new QuicCryptoServerStream(server_crypto_config, *server_session);
+  (*server_session)->InitializeSession(server_crypto_config);
+
+  // We advance the clock initially because the default time is zero and the
+  // strike register worries that we've just overflowed a uint32 time.
+  (*server_connection)->AdvanceTime(connection_start_time);
+}
+
 }  // namespace test
 }  // namespace net
diff --git a/net/quic/test_tools/quic_test_utils.h b/net/quic/test_tools/quic_test_utils.h
index 9755778..facdcbf6 100644
--- a/net/quic/test_tools/quic_test_utils.h
+++ b/net/quic/test_tools/quic_test_utils.h
@@ -26,6 +26,7 @@
 #include "net/spdy/spdy_framer.h"
 #include "net/tools/quic/quic_dispatcher.h"
 #include "net/tools/quic/quic_per_connection_packet_writer.h"
+#include "net/tools/quic/quic_server_session.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
 namespace net {
@@ -129,6 +130,9 @@
 // Returns QuicConfig set to default values.
 QuicConfig DefaultQuicConfig();
 
+// Returns a QuicConfig set to default values that supports stateless rejects.
+QuicConfig DefaultQuicConfigStatelessRejects();
+
 // Returns a version vector consisting of |version|.
 QuicVersionVector SupportedVersions(QuicVersion version);
 
@@ -706,6 +710,65 @@
                void(const QuicPacketHeader&, StringPiece payload));
 };
 
+class TestServerSession : public tools::QuicServerSession {
+ public:
+  TestServerSession(const QuicConfig& config, QuicConnection* connection);
+  ~TestServerSession() override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TestServerSession);
+};
+
+// Creates and sets up a QuicCryptoClientStream for testing, and all
+// its associated state.
+//
+// server_id: The server id associated with this stream.
+// supports_stateless_rejects:  Does this client support stateless rejects.
+// connection_start_time: The time to set for the connection clock.
+//   Needed for strike-register nonce verification.  The client
+//   connection_start_time should be synchronized witht the server
+//   start time, otherwise nonce verification will fail.
+// crypto_client_config: Pointer to the crypto client config.
+// client_connection: Pointer reference for newly created
+//   connection.  This object will be owned by the
+//   client_session.
+// client_session: Pointer reference for the newly created client
+//   session.  The new object will be owned by the caller.
+// client_stream: Pointer reference for the newly created crypto
+//   client stream.  The new object will be owned by the caller.
+void SetupCryptoClientStreamForTest(
+    QuicServerId server_id,
+    bool supports_stateless_rejects,
+    QuicTime::Delta connection_start_time,
+    QuicCryptoClientConfig* crypto_client_config,
+    PacketSavingConnection** client_connection,
+    TestClientSession** client_session,
+    QuicCryptoClientStream** client_stream);
+
+// Creates and sets up a QuicCryptoServerStream for testing, and all
+// its associated state.
+//
+// server_id: The server id associated with this stream.
+// connection_start_time: The time to set for the connection clock.
+//   Needed for strike-register nonce verification.  The server
+//   connection_start_time should be synchronized witht the client
+//   start time, otherwise nonce verification will fail.
+// crypto_server_config: Pointer to the crypto server config.
+// server_connection: Pointer reference for newly created
+//   connection.  This object will be owned by the
+//   server_session.
+// server_session: Pointer reference for the newly created server
+//   session.  The new object will be owned by the caller.
+// server_stream: Pointer reference for the newly created crypto
+//   server stream.  The new object will be owned by the caller.
+void SetupCryptoServerStreamForTest(
+    QuicServerId server_id,
+    QuicTime::Delta connection_start_time,
+    QuicCryptoServerConfig* crypto_server_config,
+    PacketSavingConnection** server_connection,
+    TestServerSession** server_session,
+    QuicCryptoServerStream** server_stream);
+
 }  // namespace test
 }  // namespace net
 
diff --git a/net/socket/client_socket_handle.cc b/net/socket/client_socket_handle.cc
index 734e58a..d5c17005 100644
--- a/net/socket/client_socket_handle.cc
+++ b/net/socket/client_socket_handle.cc
@@ -21,7 +21,9 @@
       reuse_type_(ClientSocketHandle::UNUSED),
       callback_(base::Bind(&ClientSocketHandle::OnIOComplete,
                            base::Unretained(this))),
-      is_ssl_error_(false) {}
+      is_ssl_error_(false),
+      ssl_failure_state_(SSL_FAILURE_NONE) {
+}
 
 ClientSocketHandle::~ClientSocketHandle() {
   Reset();
@@ -72,6 +74,7 @@
 void ClientSocketHandle::ResetErrorState() {
   is_ssl_error_ = false;
   ssl_error_response_info_ = HttpResponseInfo();
+  ssl_failure_state_ = SSL_FAILURE_NONE;
   pending_http_proxy_connection_.reset();
 }
 
diff --git a/net/socket/client_socket_handle.h b/net/socket/client_socket_handle.h
index 2f8bed2..a4f7befb 100644
--- a/net/socket/client_socket_handle.h
+++ b/net/socket/client_socket_handle.h
@@ -23,6 +23,7 @@
 #include "net/socket/client_socket_pool.h"
 #include "net/socket/connection_attempts.h"
 #include "net/socket/stream_socket.h"
+#include "net/ssl/ssl_failure_state.h"
 
 namespace net {
 
@@ -135,6 +136,9 @@
   void set_ssl_error_response_info(const HttpResponseInfo& ssl_error_state) {
     ssl_error_response_info_ = ssl_error_state;
   }
+  void set_ssl_failure_state(SSLFailureState ssl_failure_state) {
+    ssl_failure_state_ = ssl_failure_state;
+  }
   void set_pending_http_proxy_connection(ClientSocketHandle* connection) {
     pending_http_proxy_connection_.reset(connection);
   }
@@ -153,6 +157,7 @@
   const HttpResponseInfo& ssl_error_response_info() const {
     return ssl_error_response_info_;
   }
+  SSLFailureState ssl_failure_state() const { return ssl_failure_state_; }
   ClientSocketHandle* release_pending_http_proxy_connection() {
     return pending_http_proxy_connection_.release();
   }
@@ -210,6 +215,7 @@
   int pool_id_;  // See ClientSocketPool::ReleaseSocket() for an explanation.
   bool is_ssl_error_;
   HttpResponseInfo ssl_error_response_info_;
+  SSLFailureState ssl_failure_state_;
   scoped_ptr<ClientSocketHandle> pending_http_proxy_connection_;
   std::vector<ConnectionAttempt> connection_attempts_;
   base::TimeTicks init_time_;
diff --git a/net/socket/sequenced_socket_data_unittest.cc b/net/socket/sequenced_socket_data_unittest.cc
index e0ed320..920666e7 100644
--- a/net/socket/sequenced_socket_data_unittest.cc
+++ b/net/socket/sequenced_socket_data_unittest.cc
@@ -194,6 +194,7 @@
   void AssertSyncWriteEquals(const char* data, int len);
   void AssertAsyncWriteEquals(const char* data, int len);
   void AssertWriteReturns(const char* data, int len, int rv);
+  void CompleteRead();
 
   // When a given test completes, data_.at_eof() is expected to
   // match the value specified here. Most test should consume all
@@ -313,6 +314,10 @@
   ASSERT_EQ(len, write_callback_.WaitForResult());
 }
 
+void SequencedSocketDataTest::CompleteRead() {
+  data_->CompleteRead();
+}
+
 void SequencedSocketDataTest::AssertWriteReturns(const char* data,
                                                  int len,
                                                  int rv) {
@@ -603,6 +608,28 @@
   ASSERT_FALSE(read_callback_.have_result());
 }
 
+TEST_F(SequencedSocketDataTest, CompleteRead) {
+  MockRead reads[] = {
+      MockRead(ASYNC, ERR_IO_PENDING, 0), MockRead(ASYNC, kMsg1, kLen1, 1),
+  };
+
+  Initialize(reads, arraysize(reads), nullptr, 0);
+
+  AssertReadReturns(kLen1, ERR_IO_PENDING);
+  ASSERT_FALSE(read_callback_.have_result());
+
+  // Even though the read is scheduled to complete at sequence number 0,
+  // verify that the read callback in not called, until CompleteRead() is.
+  base::MessageLoop::current()->RunUntilIdle();
+  ASSERT_FALSE(read_callback_.have_result());
+
+  CompleteRead();
+
+  ASSERT_TRUE(read_callback_.have_result());
+  ASSERT_EQ(kLen1, read_callback_.WaitForResult());
+  AssertReadBufferEquals(kMsg1, kLen1);
+}
+
 // ----------- Write
 
 TEST_F(SequencedSocketDataTest, SingleSyncWriteTooEarly) {
diff --git a/net/socket/socket_test_util.cc b/net/socket/socket_test_util.cc
index c5861faa..8d4b2039 100644
--- a/net/socket/socket_test_util.cc
+++ b/net/socket/socket_test_util.cc
@@ -26,6 +26,7 @@
 #include "net/socket/websocket_endpoint_lock_manager.h"
 #include "net/ssl/ssl_cert_request_info.h"
 #include "net/ssl/ssl_connection_status_flags.h"
+#include "net/ssl/ssl_failure_state.h"
 #include "net/ssl/ssl_info.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -248,6 +249,14 @@
   helper_.Reset();
 }
 
+bool StaticSocketDataProvider::AllReadDataConsumed() const {
+  return helper_.at_read_eof();
+}
+
+bool StaticSocketDataProvider::AllWriteDataConsumed() const {
+  return helper_.at_write_eof();
+}
+
 DynamicSocketDataProvider::DynamicSocketDataProvider()
     : short_read_limit_(0),
       allow_unconsumed_reads_(false) {
@@ -364,103 +373,6 @@
     socket()->OnReadComplete(OnRead());
 }
 
-OrderedSocketData::OrderedSocketData(
-    MockRead* reads, size_t reads_count, MockWrite* writes, size_t writes_count)
-    : StaticSocketDataProvider(reads, reads_count, writes, writes_count),
-      sequence_number_(0), loop_stop_stage_(0),
-      blocked_(false), weak_factory_(this) {
-}
-
-OrderedSocketData::OrderedSocketData(
-    const MockConnect& connect,
-    MockRead* reads, size_t reads_count,
-    MockWrite* writes, size_t writes_count)
-    : StaticSocketDataProvider(reads, reads_count, writes, writes_count),
-      sequence_number_(0), loop_stop_stage_(0),
-      blocked_(false), weak_factory_(this) {
-  set_connect_data(connect);
-}
-
-void OrderedSocketData::EndLoop() {
-  // If we've already stopped the loop, don't do it again until we've advanced
-  // to the next sequence_number.
-  NET_TRACE(1, "  *** ") << "Stage " << sequence_number_ << ": EndLoop()";
-  if (loop_stop_stage_ > 0) {
-    const MockRead& next_read = helper()->PeekRead();
-    if ((next_read.sequence_number & ~MockRead::STOPLOOP) >
-        loop_stop_stage_) {
-      NET_TRACE(1, "  *** ") << "Stage " << sequence_number_
-                             << ": Clearing stop index";
-      loop_stop_stage_ = 0;
-    } else {
-      return;
-    }
-  }
-  // Record the sequence_number at which we stopped the loop.
-  NET_TRACE(1, "  *** ") << "Stage " << sequence_number_
-                         << ": Posting Quit at read " << read_index();
-  loop_stop_stage_ = sequence_number_;
-}
-
-MockRead OrderedSocketData::OnRead() {
-  weak_factory_.InvalidateWeakPtrs();
-  blocked_ = false;
-  const MockRead& next_read = helper()->PeekRead();
-  if (next_read.sequence_number & MockRead::STOPLOOP)
-    EndLoop();
-  if ((next_read.sequence_number & ~MockRead::STOPLOOP) <=
-      sequence_number_++) {
-    NET_TRACE(1, "  *** ") << "Stage " << sequence_number_ - 1 << ": Read "
-                           << read_index();
-    DumpMockReadWrite(next_read);
-    blocked_ = (next_read.result == ERR_IO_PENDING);
-    return StaticSocketDataProvider::OnRead();
-  }
-  NET_TRACE(1, "  *** ") << "Stage " << sequence_number_ - 1 << ": I/O Pending";
-  MockRead result = MockRead(ASYNC, ERR_IO_PENDING);
-  DumpMockReadWrite(result);
-  blocked_ = true;
-  return result;
-}
-
-MockWriteResult OrderedSocketData::OnWrite(const std::string& data) {
-  NET_TRACE(1, "  *** ") << "Stage " << sequence_number_ << ": Write "
-                         << write_index();
-  DumpMockReadWrite(helper()->PeekWrite());
-  ++sequence_number_;
-  if (blocked_) {
-    // TODO(willchan): This 100ms delay seems to work around some weirdness.  We
-    // should probably fix the weirdness.  One example is in SpdyStream,
-    // DoSendRequest() will return ERR_IO_PENDING, and there's a race.  If the
-    // SYN_REPLY causes OnResponseReceived() to get called before
-    // SpdyStream::ReadResponseHeaders() is called, we hit a NOTREACHED().
-    base::MessageLoop::current()->PostDelayedTask(
-        FROM_HERE,
-        base::Bind(&OrderedSocketData::CompleteRead,
-                   weak_factory_.GetWeakPtr()),
-        base::TimeDelta::FromMilliseconds(100));
-  }
-  return StaticSocketDataProvider::OnWrite(data);
-}
-
-void OrderedSocketData::Reset() {
-  NET_TRACE(1, "  *** ") << "Stage " << sequence_number_ << ": Reset()";
-  sequence_number_ = 0;
-  loop_stop_stage_ = 0;
-  set_socket(NULL);
-  weak_factory_.InvalidateWeakPtrs();
-  StaticSocketDataProvider::Reset();
-}
-
-void OrderedSocketData::CompleteRead() {
-  if (socket() && blocked_) {
-    NET_TRACE(1, "  *** ") << "Stage " << sequence_number_;
-    socket()->OnReadComplete(OnRead());
-  }
-}
-
-OrderedSocketData::~OrderedSocketData() {}
-
 SequencedSocketData::SequencedSocketData(MockRead* reads,
                                          size_t reads_count,
                                          MockWrite* writes,
@@ -515,15 +427,6 @@
   NET_TRACE(1, " *** ") << "next_read: " << next_read.sequence_number;
   CHECK_GE(next_read.sequence_number, sequence_number_);
 
-  // Special case handling for hanging reads.
-  if (next_read.mode == ASYNC && next_read.result == ERR_IO_PENDING) {
-    NET_TRACE(1, " *** ") << "Hanging read";
-    helper_.AdvanceRead();
-    ++sequence_number_;
-    CHECK(helper_.at_read_eof());
-    return MockRead(SYNCHRONOUS, ERR_IO_PENDING);
-  }
-
   if (next_read.sequence_number <= sequence_number_) {
     if (next_read.mode == SYNCHRONOUS) {
       NET_TRACE(1, " *** ") << "Returning synchronously";
@@ -534,6 +437,15 @@
       return next_read;
     }
 
+    // If the result is ERR_IO_PENDING, then advance to the next state
+    // and pause reads.
+    if (next_read.result == ERR_IO_PENDING) {
+      NET_TRACE(1, " *** ") << "Pausing at: " << sequence_number_;
+      ++sequence_number_;
+      helper_.AdvanceRead();
+      read_state_ = PAUSED;
+      return MockRead(SYNCHRONOUS, ERR_IO_PENDING);
+    }
     base::MessageLoop::current()->PostTask(
         FROM_HERE, base::Bind(&SequencedSocketData::OnReadComplete,
                               weak_factory_.GetWeakPtr()));
@@ -600,6 +512,14 @@
   weak_factory_.InvalidateWeakPtrs();
 }
 
+bool SequencedSocketData::AllReadDataConsumed() const {
+  return helper_.at_read_eof();
+}
+
+bool SequencedSocketData::AllWriteDataConsumed() const {
+  return helper_.at_write_eof();
+}
+
 bool SequencedSocketData::at_read_eof() const {
   return helper_.at_read_eof();
 }
@@ -608,6 +528,19 @@
   return helper_.at_read_eof();
 }
 
+bool SequencedSocketData::IsReadPaused() {
+  return read_state_ == PAUSED;
+}
+
+void SequencedSocketData::CompleteRead() {
+  if (read_state_ != PAUSED) {
+    ADD_FAILURE() << "Unable to CompleteRead when not paused.";
+    return;
+  }
+  read_state_ = COMPLETING;
+  OnReadComplete();
+}
+
 void SequencedSocketData::MaybePostReadCompleteTask() {
   NET_TRACE(1, " ****** ") << " current: " << sequence_number_;
   // Only trigger the next read to complete if there is already a read pending
@@ -617,6 +550,16 @@
     return;
   }
 
+  // If the result is ERR_IO_PENDING, then advance to the next state
+  // and pause reads.
+  if (helper_.PeekRead().result == ERR_IO_PENDING) {
+    NET_TRACE(1, " *** ") << "Pausing read at: " << sequence_number_;
+    ++sequence_number_;
+    helper_.AdvanceRead();
+    read_state_ = PAUSED;
+    return;
+  }
+
   NET_TRACE(1, " ****** ") << "Posting task to complete read: "
                            << sequence_number_;
   base::MessageLoop::current()->PostTask(
@@ -647,10 +590,6 @@
 void SequencedSocketData::OnReadComplete() {
   CHECK_EQ(COMPLETING, read_state_);
   NET_TRACE(1, " *** ") << "Completing read for: " << sequence_number_;
-  if (!socket()) {
-    NET_TRACE(1, " *** ") << "No socket available to complete read";
-    return;
-  }
 
   MockRead data = helper_.AdvanceRead();
   DCHECK_EQ(sequence_number_, data.sequence_number);
@@ -664,7 +603,13 @@
   // before calling that.
   MaybePostWriteCompleteTask();
 
-  NET_TRACE(1, " *** ") << "Completing socket read for: " << sequence_number_;
+  if (!socket()) {
+    NET_TRACE(1, " *** ") << "No socket available to complete read";
+    return;
+  }
+
+  NET_TRACE(1, " *** ") << "Completing socket read for: "
+                        << data.sequence_number;
   DumpMockReadWrite(data);
   socket()->OnReadComplete(data);
   NET_TRACE(1, " *** ") << "Done";
@@ -673,10 +618,6 @@
 void SequencedSocketData::OnWriteComplete() {
   CHECK_EQ(COMPLETING, write_state_);
   NET_TRACE(1, " *** ") << " Completing write for: " << sequence_number_;
-  if (!socket()) {
-    NET_TRACE(1, " *** ") << "No socket available to complete write.";
-    return;
-  }
 
   const MockWrite& data = helper_.AdvanceWrite();
   DCHECK_EQ(sequence_number_, data.sequence_number);
@@ -691,7 +632,13 @@
   // before calling that.
   MaybePostReadCompleteTask();
 
-  NET_TRACE(1, " *** ") << " Completing socket write for: " << sequence_number_;
+  if (!socket()) {
+    NET_TRACE(1, " *** ") << "No socket available to complete write";
+    return;
+  }
+
+  NET_TRACE(1, " *** ") << " Completing socket write for: "
+                        << data.sequence_number;
   socket()->OnWriteComplete(rv);
   NET_TRACE(1, " *** ") << "Done";
 }
@@ -1033,6 +980,10 @@
   return NULL;
 }
 
+SSLFailureState MockClientSocket::GetSSLFailureState() const {
+  return IsConnected() ? SSL_FAILURE_NONE : SSL_FAILURE_UNKNOWN;
+}
+
 SSLClientSocket::NextProtoStatus MockClientSocket::GetNextProto(
     std::string* proto) const {
   proto->clear();
diff --git a/net/socket/socket_test_util.h b/net/socket/socket_test_util.h
index b7d090e..7d9a53b 100644
--- a/net/socket/socket_test_util.h
+++ b/net/socket/socket_test_util.h
@@ -166,7 +166,7 @@
   const char* data;
   int data_len;
 
-  // For OrderedSocketData, which only allows reads to occur in a particular
+  // For data providers that only allows reads to occur in a particular
   // sequence.  If a read occurs before the given |sequence_number| is reached,
   // an ERR_IO_PENDING is returned.
   int sequence_number;    // The sequence number at which a read is allowed
@@ -198,6 +198,8 @@
   virtual MockRead OnRead() = 0;
   virtual MockWriteResult OnWrite(const std::string& data) = 0;
   virtual void Reset() = 0;
+  virtual bool AllReadDataConsumed() const = 0;
+  virtual bool AllWriteDataConsumed() const = 0;
 
   // Accessor for the socket which is using the SocketDataProvider.
   AsyncSocket* socket() { return socket_; }
@@ -294,6 +296,8 @@
   MockRead OnRead() override;
   MockWriteResult OnWrite(const std::string& data) override;
   void Reset() override;
+  bool AllReadDataConsumed() const override;
+  bool AllWriteDataConsumed() const override;
 
   size_t read_index() const { return helper_.read_index(); }
   size_t write_index() const { return helper_.write_index(); }
@@ -418,61 +422,6 @@
   DISALLOW_COPY_AND_ASSIGN(DelayedSocketData);
 };
 
-// A DataProvider where the reads are ordered.
-// If a read is requested before its sequence number is reached, we return an
-// ERR_IO_PENDING (that way we don't have to explicitly add a MockRead just to
-// wait).
-// The sequence number is incremented on every read and write operation.
-// The message loop may be interrupted by setting the high bit of the sequence
-// number in the MockRead's sequence number.  When that MockRead is reached,
-// we post a Quit message to the loop.  This allows us to interrupt the reading
-// of data before a complete message has arrived, and provides support for
-// testing server push when the request is issued while the response is in the
-// middle of being received.
-class OrderedSocketData : public StaticSocketDataProvider {
- public:
-  // |reads| the list of MockRead completions.
-  // |writes| the list of MockWrite completions.
-  // Note: All MockReads and MockWrites must be async.
-  // Note: For stream sockets, the MockRead list must end with a EOF, e.g., a
-  //       MockRead(true, 0, 0);
-  OrderedSocketData(MockRead* reads,
-                    size_t reads_count,
-                    MockWrite* writes,
-                    size_t writes_count);
-  ~OrderedSocketData() override;
-
-  // |connect| the result for the connect phase.
-  // |reads| the list of MockRead completions.
-  // |writes| the list of MockWrite completions.
-  // Note: All MockReads and MockWrites must be async.
-  // Note: For stream sockets, the MockRead list must end with a EOF, e.g., a
-  //       MockRead(true, 0, 0);
-  OrderedSocketData(const MockConnect& connect,
-                    MockRead* reads,
-                    size_t reads_count,
-                    MockWrite* writes,
-                    size_t writes_count);
-
-  // Posts a quit message to the current message loop, if one is running.
-  void EndLoop();
-
-  // StaticSocketDataProvider:
-  MockRead OnRead() override;
-  MockWriteResult OnWrite(const std::string& data) override;
-  void Reset() override;
-  void CompleteRead() override;
-
- private:
-  int sequence_number_;
-  int loop_stop_stage_;
-  bool blocked_;
-
-  base::WeakPtrFactory<OrderedSocketData> weak_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(OrderedSocketData);
-};
-
 // Uses the sequence_number field in the mock reads and writes to
 // complete the operations in a specified order.
 class SequencedSocketData : public SocketDataProvider {
@@ -499,6 +448,8 @@
   MockRead OnRead() override;
   MockWriteResult OnWrite(const std::string& data) override;
   void Reset() override;
+  bool AllReadDataConsumed() const override;
+  bool AllWriteDataConsumed() const override;
 
   // Returns true if all data has been read.
   bool at_read_eof() const;
@@ -506,6 +457,9 @@
   // Returns true if all data has been written.
   bool at_write_eof() const;
 
+  bool IsReadPaused();
+  void CompleteRead();
+
  private:
   // Defines the state for the read or write path.
   enum IoState {
@@ -513,7 +467,9 @@
     PENDING,     // An async operation in waiting for another opteration to
                  // complete.
     COMPLETING,  // A task has been posted to complet an async operation.
+    PAUSED,      // IO is paused until CompleteRead() is called.
   };
+
   void OnReadComplete();
   void OnWriteComplete();
 
@@ -793,6 +749,7 @@
   int GetTLSUniqueChannelBinding(std::string* out) override;
   NextProtoStatus GetNextProto(std::string* proto) const override;
   ChannelIDService* GetChannelIDService() const override;
+  SSLFailureState GetSSLFailureState() const override;
 
  protected:
   ~MockClientSocket() override;
diff --git a/net/socket/ssl_client_socket.h b/net/socket/ssl_client_socket.h
index cb5e5fbe..6774f15 100644
--- a/net/socket/ssl_client_socket.h
+++ b/net/socket/ssl_client_socket.h
@@ -13,6 +13,7 @@
 #include "net/base/net_errors.h"
 #include "net/socket/ssl_socket.h"
 #include "net/socket/stream_socket.h"
+#include "net/ssl/ssl_failure_state.h"
 
 namespace net {
 
@@ -129,6 +130,11 @@
   // channel ids are not supported.
   virtual ChannelIDService* GetChannelIDService() const = 0;
 
+  // Returns the state of the handshake when it failed, or |SSL_FAILURE_NONE| if
+  // the handshake succeeded. This is used to classify causes of the TLS version
+  // fallback.
+  virtual SSLFailureState GetSSLFailureState() const = 0;
+
  protected:
   void set_negotiation_extension(
       SSLNegotiationExtension negotiation_extension) {
diff --git a/net/socket/ssl_client_socket_nss.cc b/net/socket/ssl_client_socket_nss.cc
index 229735b..7c5264db 100644
--- a/net/socket/ssl_client_socket_nss.cc
+++ b/net/socket/ssl_client_socket_nss.cc
@@ -106,6 +106,7 @@
 #include "net/ssl/ssl_cert_request_info.h"
 #include "net/ssl/ssl_cipher_suite_names.h"
 #include "net/ssl/ssl_connection_status_flags.h"
+#include "net/ssl/ssl_failure_state.h"
 #include "net/ssl/ssl_info.h"
 
 #if defined(USE_NSS_CERTS)
@@ -3208,4 +3209,10 @@
   return channel_id_service_;
 }
 
+SSLFailureState SSLClientSocketNSS::GetSSLFailureState() const {
+  if (completed_handshake_)
+    return SSL_FAILURE_NONE;
+  return SSL_FAILURE_UNKNOWN;
+}
+
 }  // namespace net
diff --git a/net/socket/ssl_client_socket_nss.h b/net/socket/ssl_client_socket_nss.h
index 72fa9d2..75b47af 100644
--- a/net/socket/ssl_client_socket_nss.h
+++ b/net/socket/ssl_client_socket_nss.h
@@ -105,7 +105,10 @@
             const CompletionCallback& callback) override;
   int SetReceiveBufferSize(int32 size) override;
   int SetSendBufferSize(int32 size) override;
+
+  // SSLClientSocket implementation.
   ChannelIDService* GetChannelIDService() const override;
+  SSLFailureState GetSSLFailureState() const override;
 
  protected:
   // SSLClientSocket implementation.
diff --git a/net/socket/ssl_client_socket_openssl.cc b/net/socket/ssl_client_socket_openssl.cc
index 9b1ce38..89d29528 100644
--- a/net/socket/ssl_client_socket_openssl.cc
+++ b/net/socket/ssl_client_socket_openssl.cc
@@ -38,6 +38,7 @@
 #include "net/ssl/ssl_cert_request_info.h"
 #include "net/ssl/ssl_client_session_cache_openssl.h"
 #include "net/ssl/ssl_connection_status_flags.h"
+#include "net/ssl/ssl_failure_state.h"
 #include "net/ssl/ssl_info.h"
 
 #if defined(OS_WIN)
@@ -368,6 +369,7 @@
       channel_id_sent_(false),
       handshake_completed_(false),
       certificate_verified_(false),
+      ssl_failure_state_(SSL_FAILURE_NONE),
       transport_security_state_(context.transport_security_state),
       policy_enforcer_(context.cert_policy_enforcer),
       net_log_(transport_->socket()->NetLog()),
@@ -397,6 +399,10 @@
   return channel_id_service_;
 }
 
+SSLFailureState SSLClientSocketOpenSSL::GetSSLFailureState() const {
+  return ssl_failure_state_;
+}
+
 int SSLClientSocketOpenSSL::ExportKeyingMaterial(
     const base::StringPiece& label,
     bool has_context, const base::StringPiece& context,
@@ -504,7 +510,10 @@
   npn_proto_.clear();
 
   channel_id_sent_ = false;
+  handshake_completed_ = false;
+  certificate_verified_ = false;
   channel_id_request_handle_.Cancel();
+  ssl_failure_state_ = SSL_FAILURE_NONE;
 }
 
 bool SSLClientSocketOpenSSL::IsConnected() const {
@@ -932,6 +941,31 @@
     net_log_.AddEvent(
         NetLog::TYPE_SSL_HANDSHAKE_ERROR,
         CreateNetLogOpenSSLErrorCallback(net_error, ssl_error, error_info));
+
+    // Classify the handshake failure. This is used to determine causes of the
+    // TLS version fallback.
+
+    // |cipher| is the current outgoing cipher suite, so it is non-null iff
+    // ChangeCipherSpec was sent.
+    const SSL_CIPHER* cipher = SSL_get_current_cipher(ssl_);
+    if (SSL_get_state(ssl_) == SSL3_ST_CR_SRVR_HELLO_A) {
+      ssl_failure_state_ = SSL_FAILURE_CLIENT_HELLO;
+    } else if (cipher && (SSL_CIPHER_get_id(cipher) ==
+                              TLS1_CK_DHE_RSA_WITH_AES_128_GCM_SHA256 ||
+                          SSL_CIPHER_get_id(cipher) ==
+                              TLS1_CK_RSA_WITH_AES_128_GCM_SHA256)) {
+      ssl_failure_state_ = SSL_FAILURE_BUGGY_GCM;
+    } else if (cipher && ssl_config_.send_client_cert) {
+      ssl_failure_state_ = SSL_FAILURE_CLIENT_AUTH;
+    } else if (ERR_GET_LIB(error_info.error_code) == ERR_LIB_SSL &&
+               ERR_GET_REASON(error_info.error_code) ==
+                   SSL_R_OLD_SESSION_VERSION_NOT_RETURNED) {
+      ssl_failure_state_ = SSL_FAILURE_SESSION_MISMATCH;
+    } else if (cipher && npn_status_ != kNextProtoUnsupported) {
+      ssl_failure_state_ = SSL_FAILURE_NEXT_PROTO;
+    } else {
+      ssl_failure_state_ = SSL_FAILURE_UNKNOWN;
+    }
   }
 
   GotoState(STATE_HANDSHAKE_COMPLETE);
diff --git a/net/socket/ssl_client_socket_openssl.h b/net/socket/ssl_client_socket_openssl.h
index c78a815..452936a 100644
--- a/net/socket/ssl_client_socket_openssl.h
+++ b/net/socket/ssl_client_socket_openssl.h
@@ -21,6 +21,7 @@
 #include "net/ssl/openssl_ssl_util.h"
 #include "net/ssl/ssl_client_cert_type.h"
 #include "net/ssl/ssl_config_service.h"
+#include "net/ssl/ssl_failure_state.h"
 
 // Avoid including misc OpenSSL headers, i.e.:
 // <openssl/bio.h>
@@ -63,6 +64,7 @@
   void GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info) override;
   NextProtoStatus GetNextProto(std::string* proto) const override;
   ChannelIDService* GetChannelIDService() const override;
+  SSLFailureState GetSSLFailureState() const override;
 
   // SSLSocket implementation.
   int ExportKeyingMaterial(const base::StringPiece& label,
@@ -303,6 +305,7 @@
   bool certificate_verified_;
   // The request handle for |channel_id_service_|.
   ChannelIDService::RequestHandle channel_id_request_handle_;
+  SSLFailureState ssl_failure_state_;
 
   TransportSecurityState* transport_security_state_;
 
diff --git a/net/socket/ssl_client_socket_pool.cc b/net/socket/ssl_client_socket_pool.cc
index 11de9193..f8db1d0 100644
--- a/net/socket/ssl_client_socket_pool.cc
+++ b/net/socket/ssl_client_socket_pool.cc
@@ -163,6 +163,8 @@
   handle->set_ssl_error_response_info(error_response_info_);
   if (!connect_timing_.ssl_start.is_null())
     handle->set_is_ssl_error(true);
+  if (ssl_socket_)
+    handle->set_ssl_failure_state(ssl_socket_->GetSSLFailureState());
 
   handle->set_connection_attempts(connection_attempts_);
 }
diff --git a/net/spdy/spdy_framer.cc b/net/spdy/spdy_framer.cc
index ea5eaa5..eebddf6 100644
--- a/net/spdy/spdy_framer.cc
+++ b/net/spdy/spdy_framer.cc
@@ -161,7 +161,8 @@
       enable_compression_(true),
       syn_frame_processed_(false),
       probable_http_response_(false),
-      end_stream_when_done_(false) {
+      end_stream_when_done_(false),
+      header_table_size_bound_(4096) {
   DCHECK_GE(protocol_version_, SPDY_MIN_VERSION);
   DCHECK_LE(protocol_version_, SPDY_MAX_VERSION);
   DCHECK_LE(kMaxControlFrameSize,
@@ -2056,8 +2057,9 @@
                           reader.ReadUInt8(&altsvc_scratch_.pid_len);
         DCHECK(successful_read);
         // Sanity check length value.
-        if (GetAltSvcMinimumSize() + altsvc_scratch_.pid_len >=
-            current_frame_length_) {
+        if (altsvc_scratch_.pid_len == 0 ||
+            GetAltSvcMinimumSize() + altsvc_scratch_.pid_len >=
+                current_frame_length_) {
           set_error(SPDY_INVALID_CONTROL_FRAME);
           return 0;
         }
@@ -3201,6 +3203,17 @@
   return read_successfully;
 }
 
+void SpdyFramer::UpdateHeaderTableSizeSetting(uint32 value) {
+  header_table_size_bound_ = value;
+  GetHpackEncoder()->ApplyHeaderTableSizeSetting(value);
+  GetHpackDecoder()->ApplyHeaderTableSizeSetting(value);
+}
+
+// Return size bound of the header compression table.
+size_t SpdyFramer::header_table_size_bound() const {
+  return header_table_size_bound_;
+}
+
 void SpdyFramer::SerializeNameValueBlockWithoutCompression(
     SpdyFrameBuilder* builder,
     const SpdyNameValueBlock& name_value_block) const {
diff --git a/net/spdy/spdy_framer.h b/net/spdy/spdy_framer.h
index 55c3fa7..f1f4908 100644
--- a/net/spdy/spdy_framer.h
+++ b/net/spdy/spdy_framer.h
@@ -590,6 +590,12 @@
       const char* data,
       size_t len);
 
+  // Updates the maximum size of header compression table.
+  void UpdateHeaderTableSizeSetting(uint32 value);
+
+  // Returns bound of header compression table size.
+  size_t header_table_size_bound() const;
+
  protected:
   // TODO(jgraettinger): Switch to test peer pattern.
   FRIEND_TEST_ALL_PREFIXES(SpdyFramerTest, BasicCompression);
@@ -805,6 +811,9 @@
   // we know to terminate the stream when the entire header block has been
   // processed.
   bool end_stream_when_done_;
+
+  // Last acknowledged value for SETTINGS_HEADER_TABLE_SIZE.
+  size_t header_table_size_bound_;
 };
 
 }  // namespace net
diff --git a/net/spdy/spdy_framer_test.cc b/net/spdy/spdy_framer_test.cc
index fe7d4b8..4e69b207 100644
--- a/net/spdy/spdy_framer_test.cc
+++ b/net/spdy/spdy_framer_test.cc
@@ -5755,6 +5755,32 @@
       << SpdyFramer::ErrorCodeToString(framer.error_code());
 }
 
+TEST_P(SpdyFramerTest, OnAltSvcEmptyProtocolId) {
+  if (spdy_version_ <= SPDY3) {
+    return;
+  }
+
+  testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
+  SpdyFramer framer(spdy_version_);
+  framer.set_visitor(&visitor);
+
+  EXPECT_CALL(visitor, OnError(testing::Eq(&framer)));
+
+  SpdyAltSvcIR altsvc_ir(1);
+  altsvc_ir.set_max_age(10);
+  altsvc_ir.set_port(443);
+  altsvc_ir.set_host("h1");
+  altsvc_ir.set_origin("o1");
+  scoped_ptr<SpdySerializedFrame> frame(framer.SerializeFrame(altsvc_ir));
+  framer.ProcessInput(frame->data(), framer.GetAltSvcMinimumSize() +
+                      altsvc_ir.protocol_id().length() +
+                      altsvc_ir.host().length());
+
+  EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state());
+  EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME, framer.error_code())
+      << SpdyFramer::ErrorCodeToString(framer.error_code());
+}
+
 TEST_P(SpdyFramerTest, OnAltSvcBadLengths) {
   if (spdy_version_ <= SPDY3) {
     return;
diff --git a/net/spdy/spdy_network_transaction_unittest.cc b/net/spdy/spdy_network_transaction_unittest.cc
index b75405b..78242df 100644
--- a/net/spdy/spdy_network_transaction_unittest.cc
+++ b/net/spdy/spdy_network_transaction_unittest.cc
@@ -268,16 +268,9 @@
     // should end with an empty read, and that read needs to be processed to
     // ensure proper deletion of the spdy_session_pool.
     void VerifyDataConsumed() {
-      for (DataVector::iterator it = data_vector_.begin();
-          it != data_vector_.end(); ++it) {
-        EXPECT_TRUE((*it)->at_read_eof()) << "Read count: "
-                                          << (*it)->read_count()
-                                          << " Read index: "
-                                          << (*it)->read_index();
-        EXPECT_TRUE((*it)->at_write_eof()) << "Write count: "
-                                           << (*it)->write_count()
-                                           << " Write index: "
-                                           << (*it)->write_index();
+      for (const SocketDataProvider* provider : data_vector_) {
+        EXPECT_TRUE(provider->AllReadDataConsumed());
+        EXPECT_TRUE(provider->AllWriteDataConsumed());
       }
     }
 
@@ -285,20 +278,13 @@
     // processed. In that case we want to explicitly ensure that the reads were
     // not processed.
     void VerifyDataNotConsumed() {
-      for (DataVector::iterator it = data_vector_.begin();
-          it != data_vector_.end(); ++it) {
-        EXPECT_TRUE(!(*it)->at_read_eof()) << "Read count: "
-                                           << (*it)->read_count()
-                                           << " Read index: "
-                                           << (*it)->read_index();
-        EXPECT_TRUE(!(*it)->at_write_eof()) << "Write count: "
-                                            << (*it)->write_count()
-                                            << " Write index: "
-                                            << (*it)->write_index();
+      for (const SocketDataProvider* provider : data_vector_) {
+        EXPECT_FALSE(provider->AllReadDataConsumed());
+        EXPECT_FALSE(provider->AllWriteDataConsumed());
       }
     }
 
-    void RunToCompletion(StaticSocketDataProvider* data) {
+    void RunToCompletion(SocketDataProvider* data) {
       RunPreTestSetup();
       AddData(data);
       RunDefaultTest();
@@ -306,7 +292,7 @@
     }
 
     void RunToCompletionWithSSLData(
-        StaticSocketDataProvider* data,
+        SocketDataProvider* data,
         scoped_ptr<SSLSocketDataProvider> ssl_provider) {
       RunPreTestSetup();
       AddDataWithSSLSocketDataProvider(data, ssl_provider.Pass());
@@ -314,7 +300,7 @@
       VerifyDataConsumed();
     }
 
-    void AddData(StaticSocketDataProvider* data) {
+    void AddData(SocketDataProvider* data) {
       scoped_ptr<SSLSocketDataProvider> ssl_provider(
           new SSLSocketDataProvider(ASYNC, OK));
       ssl_provider->cert =
@@ -323,7 +309,7 @@
     }
 
     void AddDataWithSSLSocketDataProvider(
-        StaticSocketDataProvider* data,
+        SocketDataProvider* data,
         scoped_ptr<SSLSocketDataProvider> ssl_provider) {
       DCHECK(!deterministic_);
       data_vector_.push_back(data);
@@ -391,16 +377,16 @@
     }
 
    private:
-    typedef std::vector<StaticSocketDataProvider*> DataVector;
+    typedef std::vector<SocketDataProvider*> DataVector;
     typedef ScopedVector<SSLSocketDataProvider> SSLVector;
-    typedef ScopedVector<StaticSocketDataProvider> AlternateVector;
+    typedef ScopedVector<SocketDataProvider> AlternateVector;
     typedef ScopedVector<DeterministicSocketData> AlternateDeterministicVector;
     HttpRequestInfo request_;
     RequestPriority priority_;
     scoped_ptr<SpdySessionDependencies> session_deps_;
     scoped_refptr<HttpNetworkSession> session_;
     TransactionHelperResult output_;
-    scoped_ptr<StaticSocketDataProvider> first_transaction_;
+    scoped_ptr<SocketDataProvider> first_transaction_;
     SSLVector ssl_vector_;
     TestCompletionCallback callback_;
     scoped_ptr<HttpNetworkTransaction> trans_;
@@ -567,7 +553,7 @@
   // to skip over data destined for other transactions while we consume
   // the data for |trans|.
   int ReadResult(HttpNetworkTransaction* trans,
-                 StaticSocketDataProvider* data,
+                 SocketDataProvider* data,
                  std::string* result) {
     const int kSize = 3000;
 
@@ -577,12 +563,6 @@
     while (true) {
       int rv = trans->Read(buf.get(), kSize, callback.callback());
       if (rv == ERR_IO_PENDING) {
-        // Multiple transactions may be in the data set.  Keep pulling off
-        // reads until we complete our callback.
-        while (!callback.have_result()) {
-          data->CompleteRead();
-          base::RunLoop().RunUntilIdle();
-        }
         rv = callback.WaitForResult();
       } else if (rv <= 0) {
         break;
@@ -610,7 +590,7 @@
     EXPECT_EQ(0u, spdy_session->num_unclaimed_pushed_streams());
   }
 
-  void RunServerPushTest(OrderedSocketData* data,
+  void RunServerPushTest(SequencedSocketData* data,
                          HttpResponseInfo* response,
                          HttpResponseInfo* push_response,
                          const std::string& expected) {
@@ -751,18 +731,17 @@
   // Construct the request.
   scoped_ptr<SpdyFrame> req(
       spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
-  MockWrite writes[] = { CreateMockWrite(*req) };
+  MockWrite writes[] = {CreateMockWrite(*req, 0)};
 
   scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
   scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
   MockRead reads[] = {
-    CreateMockRead(*resp),
-    CreateMockRead(*body),
-    MockRead(ASYNC, 0, 0)  // EOF
+      CreateMockRead(*resp, 1),
+      CreateMockRead(*body, 2),
+      MockRead(ASYNC, 0, 3)  // EOF
   };
 
-  DelayedSocketData data(1, reads, arraysize(reads),
-                         writes, arraysize(writes));
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
   NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
                                      BoundNetLog(), GetParam(), NULL);
   helper.RunToCompletion(&data);
@@ -778,7 +757,7 @@
     // Construct the request.
     scoped_ptr<SpdyFrame> req(
         spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, p, true));
-    MockWrite writes[] = { CreateMockWrite(*req) };
+    MockWrite writes[] = {CreateMockWrite(*req, 0)};
 
     SpdyPriority spdy_prio = 0;
     EXPECT_TRUE(GetSpdyPriority(spdy_util_.spdy_version(), *req, &spdy_prio));
@@ -828,13 +807,13 @@
     scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
     scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
     MockRead reads[] = {
-      CreateMockRead(*resp),
-      CreateMockRead(*body),
-      MockRead(ASYNC, 0, 0)  // EOF
+        CreateMockRead(*resp, 1),
+        CreateMockRead(*body, 2),
+        MockRead(ASYNC, 0, 3)  // EOF
     };
 
-    DelayedSocketData data(1, reads, arraysize(reads),
-                              writes, arraysize(writes));
+    SequencedSocketData data(reads, arraysize(reads), writes,
+                             arraysize(writes));
     HttpRequestInfo http_req = CreateGetRequest();
 
     NormalSpdyTransactionHelper helper(http_req, p, BoundNetLog(),
@@ -877,27 +856,26 @@
   scoped_ptr<SpdyFrame> fbody3(spdy_util_.ConstructSpdyBodyFrame(5, true));
 
   MockWrite writes[] = {
-    CreateMockWrite(*req),
-    CreateMockWrite(*req2),
-    CreateMockWrite(*req3),
+      CreateMockWrite(*req, 0),
+      CreateMockWrite(*req2, 3),
+      CreateMockWrite(*req3, 6),
   };
   MockRead reads[] = {
-    CreateMockRead(*resp, 1),
-    CreateMockRead(*body),
-    CreateMockRead(*resp2, 4),
-    CreateMockRead(*body2),
-    CreateMockRead(*resp3, 7),
-    CreateMockRead(*body3),
+      CreateMockRead(*resp, 1),
+      CreateMockRead(*body, 2),
+      CreateMockRead(*resp2, 4),
+      CreateMockRead(*body2, 5),
+      CreateMockRead(*resp3, 7),
+      CreateMockRead(*body3, 8),
 
-    CreateMockRead(*fbody),
-    CreateMockRead(*fbody2),
-    CreateMockRead(*fbody3),
+      CreateMockRead(*fbody, 9),
+      CreateMockRead(*fbody2, 10),
+      CreateMockRead(*fbody3, 11),
 
-    MockRead(ASYNC, 0, 0),  // EOF
+      MockRead(ASYNC, 0, 12),  // EOF
   };
-  OrderedSocketData data(reads, arraysize(reads),
-                         writes, arraysize(writes));
-  OrderedSocketData data_placeholder(NULL, 0, NULL, 0);
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
+  SequencedSocketData data_placeholder(NULL, 0, NULL, 0);
 
   BoundNetLog log;
   TransactionHelperResult out;
@@ -968,23 +946,21 @@
   scoped_ptr<SpdyFrame> fbody2(spdy_util_.ConstructSpdyBodyFrame(3, true));
 
   MockWrite writes[] = {
-    CreateMockWrite(*req),
-    CreateMockWrite(*req2),
+      CreateMockWrite(*req, 0), CreateMockWrite(*req2, 3),
   };
   MockRead reads[] = {
-    CreateMockRead(*resp, 1),
-    CreateMockRead(*body),
-    CreateMockRead(*resp2, 4),
-    CreateMockRead(*body2),
-    CreateMockRead(*fbody),
-    CreateMockRead(*fbody2),
-    MockRead(ASYNC, 0, 0),  // EOF
+      CreateMockRead(*resp, 1),
+      CreateMockRead(*body, 2),
+      CreateMockRead(*resp2, 4),
+      CreateMockRead(*body2, 5),
+      CreateMockRead(*fbody, 6),
+      CreateMockRead(*fbody2, 7),
+      MockRead(ASYNC, 0, 8),  // EOF
   };
-  OrderedSocketData data(reads, arraysize(reads),
-                         writes, arraysize(writes));
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
 
   MockConnect never_finishing_connect(SYNCHRONOUS, ERR_IO_PENDING);
-  OrderedSocketData data_placeholder(NULL, 0, NULL, 0);
+  SequencedSocketData data_placeholder(NULL, 0, NULL, 0);
   data_placeholder.set_connect_data(never_finishing_connect);
 
   BoundNetLog log;
@@ -1055,24 +1031,23 @@
   scoped_ptr<SpdyFrame> fbody2(spdy_util_.ConstructSpdyBodyFrame(3, true));
 
   MockWrite writes[] = {
-    CreateMockWrite(*req),
-    CreateMockWrite(*req2),
+      CreateMockWrite(*req, 0), CreateMockWrite(*req2, 3),
   };
   MockRead reads[] = {
-    CreateMockRead(*resp, 1),
-    CreateMockRead(*body),
-    CreateMockRead(*resp2, 4),
-    CreateMockRead(*body2),
-    CreateMockRead(*fbody),
-    CreateMockRead(*fbody2),
-    MockRead(ASYNC, 0, 0),  // EOF
+      CreateMockRead(*resp, 1),
+      CreateMockRead(*body, 2),
+      CreateMockRead(*resp2, 4),
+      CreateMockRead(*body2, 5),
+      CreateMockRead(*fbody, 6),
+      CreateMockRead(*fbody2, 7),
+      MockRead(ASYNC, 0, 8),  // EOF
   };
-  OrderedSocketData preconnect_data(reads, arraysize(reads),
-                                    writes, arraysize(writes));
+  SequencedSocketData preconnect_data(reads, arraysize(reads), writes,
+                                      arraysize(writes));
 
   MockConnect never_finishing_connect(ASYNC, ERR_IO_PENDING);
 
-  OrderedSocketData data_placeholder(NULL, 0, NULL, 0);
+  SequencedSocketData data_placeholder(NULL, 0, NULL, 0);
   data_placeholder.set_connect_data(never_finishing_connect);
 
   BoundNetLog log;
@@ -1174,29 +1149,28 @@
   scoped_ptr<SpdyFrame> settings_ack(spdy_util_.ConstructSpdySettingsAck());
 
   MockWrite writes[] = {
-    CreateMockWrite(*req),
-    CreateMockWrite(*settings_ack, 2),
-    CreateMockWrite(*req2),
-    CreateMockWrite(*req3),
+      CreateMockWrite(*req, 0),
+      CreateMockWrite(*settings_ack, 5),
+      CreateMockWrite(*req2, 6),
+      CreateMockWrite(*req3, 10),
   };
 
   MockRead reads[] = {
-    CreateMockRead(*settings_frame, 1),
-    CreateMockRead(*resp),
-    CreateMockRead(*body),
-    CreateMockRead(*fbody),
-    CreateMockRead(*resp2, 8),
-    CreateMockRead(*body2),
-    CreateMockRead(*fbody2),
-    CreateMockRead(*resp3, 13),
-    CreateMockRead(*body3),
-    CreateMockRead(*fbody3),
+      CreateMockRead(*settings_frame, 1),
+      CreateMockRead(*resp, 2),
+      CreateMockRead(*body, 3),
+      CreateMockRead(*fbody, 4),
+      CreateMockRead(*resp2, 7),
+      CreateMockRead(*body2, 8),
+      CreateMockRead(*fbody2, 9),
+      CreateMockRead(*resp3, 11),
+      CreateMockRead(*body3, 12),
+      CreateMockRead(*fbody3, 13),
 
-    MockRead(ASYNC, 0, 0),  // EOF
+      MockRead(ASYNC, 0, 14),  // EOF
   };
 
-  OrderedSocketData data(reads, arraysize(reads),
-                         writes, arraysize(writes));
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
 
   BoundNetLog log;
   TransactionHelperResult out;
@@ -1233,7 +1207,6 @@
     ASSERT_EQ(out.rv, ERR_IO_PENDING);
     out.rv = callback2.WaitForResult();
     ASSERT_EQ(OK, out.rv);
-    EXPECT_EQ(7U, data.read_index());  // i.e. the third trans was queued
 
     out.rv = callback3.WaitForResult();
     ASSERT_EQ(OK, out.rv);
@@ -1307,39 +1280,40 @@
   scoped_ptr<SpdyFrame> settings_frame(
       spdy_util_.ConstructSpdySettings(settings));
   scoped_ptr<SpdyFrame> settings_ack(spdy_util_.ConstructSpdySettingsAck());
-
-  MockWrite writes[] = { CreateMockWrite(*req),
-    CreateMockWrite(*settings_ack, 2),
-    CreateMockWrite(*req2),
-    CreateMockWrite(*req4),
-    CreateMockWrite(*req3),
+  MockWrite writes[] = {
+      CreateMockWrite(*req, 0),
+      CreateMockWrite(*settings_ack, 5),
+      // By making these synchronous, it guarantees that they are not *started*
+      // before their sequence number, which in turn verifies that only a single
+      // request is in-flight at a time.
+      CreateMockWrite(*req2, 6, SYNCHRONOUS),
+      CreateMockWrite(*req4, 10, SYNCHRONOUS),
+      CreateMockWrite(*req3, 13, SYNCHRONOUS),
   };
   MockRead reads[] = {
-    CreateMockRead(*settings_frame, 1),
-    CreateMockRead(*resp),
-    CreateMockRead(*body),
-    CreateMockRead(*fbody),
-    CreateMockRead(*resp2, 8),
-    CreateMockRead(*body2),
-    CreateMockRead(*fbody2),
-    CreateMockRead(*resp4, 14),
-    CreateMockRead(*fbody4),
-    CreateMockRead(*resp3, 17),
-    CreateMockRead(*body3),
-    CreateMockRead(*fbody3),
+      CreateMockRead(*settings_frame, 1),
+      CreateMockRead(*resp, 2),
+      CreateMockRead(*body, 3),
+      CreateMockRead(*fbody, 4),
+      CreateMockRead(*resp2, 7),
+      CreateMockRead(*body2, 8),
+      CreateMockRead(*fbody2, 9),
+      CreateMockRead(*resp4, 11),
+      CreateMockRead(*fbody4, 12),
+      CreateMockRead(*resp3, 14),
+      CreateMockRead(*body3, 15),
+      CreateMockRead(*fbody3, 16),
 
-    MockRead(ASYNC, 0, 0),  // EOF
+      MockRead(ASYNC, 0, 17),  // EOF
   };
-
-  OrderedSocketData data(reads, arraysize(reads),
-                         writes, arraysize(writes));
-
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
   BoundNetLog log;
   TransactionHelperResult out;
   NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
                                      BoundNetLog(), GetParam(), NULL);
   helper.RunPreTestSetup();
   helper.AddData(&data);
+
   scoped_ptr<HttpNetworkTransaction> trans1(
       new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get()));
   scoped_ptr<HttpNetworkTransaction> trans2(
@@ -1374,7 +1348,6 @@
 
   out.rv = callback2.WaitForResult();
   ASSERT_EQ(OK, out.rv);
-  EXPECT_EQ(data.read_index(), 7U);  // i.e. the third & fourth trans queued
 
   out.rv = callback3.WaitForResult();
   ASSERT_EQ(OK, out.rv);
@@ -1421,7 +1394,7 @@
 }
 
 // Similar to ThreeGetsMaxConcurrrent above, however, this test
-// deletes a session in the middle of the transaction to insure
+// deletes a session in the middle of the transaction to ensure
 // that we properly remove pendingcreatestream objects from
 // the spdy_session
 TEST_P(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrentDelete) {
@@ -1447,23 +1420,22 @@
   scoped_ptr<SpdyFrame> settings_ack(spdy_util_.ConstructSpdySettingsAck());
 
   MockWrite writes[] = {
-    CreateMockWrite(*req),
-    CreateMockWrite(*settings_ack, 2),
-    CreateMockWrite(*req2),
+      CreateMockWrite(*req, 0),
+      CreateMockWrite(*settings_ack, 5),
+      CreateMockWrite(*req2, 6),
   };
   MockRead reads[] = {
-    CreateMockRead(*settings_frame, 1),
-    CreateMockRead(*resp),
-    CreateMockRead(*body),
-    CreateMockRead(*fbody),
-    CreateMockRead(*resp2, 8),
-    CreateMockRead(*body2),
-    CreateMockRead(*fbody2),
-    MockRead(ASYNC, 0, 0),  // EOF
+      CreateMockRead(*settings_frame, 1),
+      CreateMockRead(*resp, 2),
+      CreateMockRead(*body, 3),
+      CreateMockRead(*fbody, 4),
+      CreateMockRead(*resp2, 7),
+      CreateMockRead(*body2, 8),
+      CreateMockRead(*fbody2, 9),
+      MockRead(ASYNC, 0, 10),  // EOF
   };
 
-  OrderedSocketData data(reads, arraysize(reads),
-                         writes, arraysize(writes));
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
 
   BoundNetLog log;
   TransactionHelperResult out;
@@ -1500,8 +1472,6 @@
   out.rv = callback2.WaitForResult();
   ASSERT_EQ(OK, out.rv);
 
-  EXPECT_EQ(8U, data.read_index());
-
   const HttpResponseInfo* response1 = trans1->GetResponseInfo();
   ASSERT_TRUE(response1 != NULL);
   EXPECT_TRUE(response1->headers.get() != NULL);
@@ -1579,22 +1549,21 @@
   scoped_ptr<SpdyFrame> settings_ack(spdy_util_.ConstructSpdySettingsAck());
 
   MockWrite writes[] = {
-    CreateMockWrite(*req),
-    CreateMockWrite(*settings_ack, 2),
-    CreateMockWrite(*req2),
+      CreateMockWrite(*req, 0),
+      CreateMockWrite(*settings_ack, 5),
+      CreateMockWrite(*req2, 6),
   };
   MockRead reads[] = {
-    CreateMockRead(*settings_frame, 1),
-    CreateMockRead(*resp),
-    CreateMockRead(*body),
-    CreateMockRead(*fin_body),
-    CreateMockRead(*resp2, 8),
-    MockRead(ASYNC, ERR_CONNECTION_RESET, 0),  // Abort!
+      CreateMockRead(*settings_frame, 1),
+      CreateMockRead(*resp, 2),
+      CreateMockRead(*body, 3),
+      CreateMockRead(*fin_body, 4),
+      CreateMockRead(*resp2, 7),
+      MockRead(ASYNC, ERR_CONNECTION_RESET, 8),  // Abort!
   };
 
-  OrderedSocketData data(reads, arraysize(reads),
-                         writes, arraysize(writes));
-  OrderedSocketData data_placeholder(NULL, 0, NULL, 0);
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
+  SequencedSocketData data_placeholder(NULL, 0, NULL, 0);
 
   BoundNetLog log;
   TransactionHelperResult out;
@@ -1632,8 +1601,6 @@
   out.rv = callback3.WaitForResult();
   ASSERT_EQ(ERR_ABORTED, out.rv);
 
-  EXPECT_EQ(6U, data.read_index());
-
   const HttpResponseInfo* response1 = trans1.GetResponseInfo();
   ASSERT_TRUE(response1 != NULL);
   EXPECT_TRUE(response1->headers.get() != NULL);
@@ -1665,19 +1632,18 @@
   scoped_ptr<SpdyFrame> req(
       spdy_util_.ConstructSpdySyn(1, *put_headers, LOWEST, false, true));
   MockWrite writes[] = {
-    CreateMockWrite(*req),
+      CreateMockWrite(*req, 0),
   };
 
   scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
   scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
   MockRead reads[] = {
-    CreateMockRead(*resp),
-    CreateMockRead(*body),
-    MockRead(ASYNC, 0, 0)  // EOF
+      CreateMockRead(*resp, 1),
+      CreateMockRead(*body, 2),
+      MockRead(ASYNC, 0, 3)  // EOF
   };
 
-  DelayedSocketData data(1, reads, arraysize(reads),
-                         writes, arraysize(writes));
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
   NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY,
                                      BoundNetLog(), GetParam(), NULL);
   helper.RunToCompletion(&data);
@@ -1699,19 +1665,18 @@
   scoped_ptr<SpdyFrame> req(
       spdy_util_.ConstructSpdySyn(1, *head_headers, LOWEST, false, true));
   MockWrite writes[] = {
-    CreateMockWrite(*req),
+      CreateMockWrite(*req, 0),
   };
 
   scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
   scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
   MockRead reads[] = {
-    CreateMockRead(*resp),
-    CreateMockRead(*body),
-    MockRead(ASYNC, 0, 0)  // EOF
+      CreateMockRead(*resp, 1),
+      CreateMockRead(*body, 2),
+      MockRead(ASYNC, 0, 3)  // EOF
   };
 
-  DelayedSocketData data(1, reads, arraysize(reads),
-                         writes, arraysize(writes));
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
   NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY,
                                      BoundNetLog(), GetParam(), NULL);
   helper.RunToCompletion(&data);
@@ -1727,19 +1692,17 @@
       GetDefaultUrl(), 1, kUploadDataSize, LOWEST, NULL, 0));
   scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
   MockWrite writes[] = {
-    CreateMockWrite(*req),
-    CreateMockWrite(*body),  // POST upload frame
+      CreateMockWrite(*req, 0), CreateMockWrite(*body, 1),  // POST upload frame
   };
 
   scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
   MockRead reads[] = {
-    CreateMockRead(*resp),
-    CreateMockRead(*body),
-    MockRead(ASYNC, 0, 0)  // EOF
+      CreateMockRead(*resp, 2),
+      CreateMockRead(*body, 3),
+      MockRead(ASYNC, 0, 4)  // EOF
   };
 
-  DelayedSocketData data(2, reads, arraysize(reads),
-                         writes, arraysize(writes));
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
   NormalSpdyTransactionHelper helper(CreatePostRequest(), DEFAULT_PRIORITY,
                                      BoundNetLog(), GetParam(), NULL);
   helper.RunToCompletion(&data);
@@ -1755,19 +1718,17 @@
       GetDefaultUrl(), 1, kUploadDataSize, LOWEST, NULL, 0));
   scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
   MockWrite writes[] = {
-    CreateMockWrite(*req),
-    CreateMockWrite(*body),  // POST upload frame
+      CreateMockWrite(*req, 0), CreateMockWrite(*body, 1),  // POST upload frame
   };
 
   scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
   MockRead reads[] = {
-    CreateMockRead(*resp),
-    CreateMockRead(*body),
-    MockRead(ASYNC, 0, 0)  // EOF
+      CreateMockRead(*resp, 2),
+      CreateMockRead(*body, 3),
+      MockRead(ASYNC, 0, 4)  // EOF
   };
 
-  DelayedSocketData data(2, reads, arraysize(reads),
-                         writes, arraysize(writes));
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
   NormalSpdyTransactionHelper helper(CreateFilePostRequest(), DEFAULT_PRIORITY,
                                      BoundNetLog(), GetParam(), NULL);
   helper.RunToCompletion(&data);
@@ -1780,13 +1741,13 @@
 // Test that a POST with a unreadable file fails.
 TEST_P(SpdyNetworkTransactionTest, UnreadableFilePost) {
   MockWrite writes[] = {
-    MockWrite(ASYNC, 0, 0)  // EOF
+      MockWrite(ASYNC, 0, 0)  // EOF
   };
   MockRead reads[] = {
-    MockRead(ASYNC, 0, 0)  // EOF
+      MockRead(ASYNC, 0, 1)  // EOF
   };
 
-  DelayedSocketData data(1, reads, arraysize(reads), writes, arraysize(writes));
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
   NormalSpdyTransactionHelper helper(CreateUnreadableFilePostRequest(),
                                      DEFAULT_PRIORITY,
                                      BoundNetLog(), GetParam(), NULL);
@@ -1805,19 +1766,17 @@
       GetDefaultUrl(), 1, kUploadDataSize, LOWEST, NULL, 0));
   scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
   MockWrite writes[] = {
-    CreateMockWrite(*req),
-    CreateMockWrite(*body),  // POST upload frame
+      CreateMockWrite(*req, 0), CreateMockWrite(*body, 1),  // POST upload frame
   };
 
   scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
   MockRead reads[] = {
-    CreateMockRead(*resp),
-    CreateMockRead(*body),
-    MockRead(ASYNC, 0, 0)  // EOF
+      CreateMockRead(*resp, 2),
+      CreateMockRead(*body, 3),
+      MockRead(ASYNC, 0, 4)  // EOF
   };
 
-  DelayedSocketData data(2, reads, arraysize(reads),
-                         writes, arraysize(writes));
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
   NormalSpdyTransactionHelper helper(CreateComplexPostRequest(),
                                      DEFAULT_PRIORITY,
                                      BoundNetLog(), GetParam(), NULL);
@@ -1833,19 +1792,17 @@
   scoped_ptr<SpdyFrame> req(spdy_util_.ConstructChunkedSpdyPost(NULL, 0));
   scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
   MockWrite writes[] = {
-    CreateMockWrite(*req),
-    CreateMockWrite(*body),
+      CreateMockWrite(*req, 0), CreateMockWrite(*body, 1),
   };
 
   scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
   MockRead reads[] = {
-    CreateMockRead(*resp),
-    CreateMockRead(*body),
-    MockRead(ASYNC, 0, 0)  // EOF
+      CreateMockRead(*resp, 2),
+      CreateMockRead(*body, 3),
+      MockRead(ASYNC, 0, 4)  // EOF
   };
 
-  DelayedSocketData data(2, reads, arraysize(reads),
-                         writes, arraysize(writes));
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
   NormalSpdyTransactionHelper helper(CreateChunkedPostRequest(),
                                      DEFAULT_PRIORITY,
                                      BoundNetLog(), GetParam(), NULL);
@@ -1870,23 +1827,22 @@
   scoped_ptr<SpdyFrame> chunk2(spdy_util_.ConstructSpdyBodyFrame(1, false));
   scoped_ptr<SpdyFrame> chunk3(spdy_util_.ConstructSpdyBodyFrame(1, true));
   MockWrite writes[] = {
-    CreateMockWrite(*req),
-    CreateMockWrite(*chunk1),
-    CreateMockWrite(*chunk2),
-    CreateMockWrite(*chunk3),
+      CreateMockWrite(*req, 0),
+      CreateMockWrite(*chunk1, 1),
+      CreateMockWrite(*chunk2, 2),
+      CreateMockWrite(*chunk3, 3),
   };
 
   scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
   MockRead reads[] = {
-    CreateMockRead(*resp),
-    CreateMockRead(*chunk1),
-    CreateMockRead(*chunk2),
-    CreateMockRead(*chunk3),
-    MockRead(ASYNC, 0, 0)  // EOF
+      CreateMockRead(*resp, 4),
+      CreateMockRead(*chunk1, 5),
+      CreateMockRead(*chunk2, 6),
+      CreateMockRead(*chunk3, 7),
+      MockRead(ASYNC, 0, 8)  // EOF
   };
 
-  DelayedSocketData data(4, reads, arraysize(reads),
-                         writes, arraysize(writes));
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
   NormalSpdyTransactionHelper helper(CreateChunkedPostRequest(),
                                      DEFAULT_PRIORITY,
                                      BoundNetLog(), GetParam(), NULL);
@@ -1934,19 +1890,18 @@
       spdy_util_.ConstructSpdySyn(1, *req_block, LOWEST, false, true));
 
   MockWrite writes[] = {
-    CreateMockWrite(*req),
+      CreateMockWrite(*req, 0),
   };
 
   scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
   scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
   MockRead reads[] = {
-    CreateMockRead(*resp),
-    CreateMockRead(*body),
-    MockRead(ASYNC, 0, 0)  // EOF
+      CreateMockRead(*resp, 1),
+      CreateMockRead(*body, 2),
+      MockRead(ASYNC, 0, 3)  // EOF
   };
 
-  DelayedSocketData data(1, reads, arraysize(reads),
-                         writes, arraysize(writes));
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
 
   NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY,
                                      BoundNetLog(), GetParam(), NULL);
@@ -1978,18 +1933,18 @@
       spdy_util_.ConstructSpdySyn(1, *req_block, LOWEST, false, true));
 
   MockWrite writes[] = {
-    CreateMockWrite(*req),
+      CreateMockWrite(*req, 0),
   };
 
   scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
   scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
   MockRead reads[] = {
-    CreateMockRead(*resp),
-    CreateMockRead(*body),
-    MockRead(ASYNC, 0, 0)  // EOF
+      CreateMockRead(*resp, 1),
+      CreateMockRead(*body, 2),
+      MockRead(ASYNC, 0, 3)  // EOF
   };
 
-  DelayedSocketData data(1, reads, arraysize(reads), writes, arraysize(writes));
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
 
   NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY,
                                      BoundNetLog(), GetParam(), NULL);
@@ -2092,11 +2047,17 @@
 TEST_P(SpdyNetworkTransactionTest, ResponseWithoutSynReply) {
   scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
   MockRead reads[] = {
-    CreateMockRead(*body),
-    MockRead(ASYNC, 0, 0)  // EOF
+      CreateMockRead(*body, 1), MockRead(ASYNC, 0, 3)  // EOF
   };
 
-  DelayedSocketData data(1, reads, arraysize(reads), NULL, 0);
+  scoped_ptr<SpdyFrame> req(
+      spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
+  scoped_ptr<SpdyFrame> rst(
+      spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR));
+  MockWrite writes[] = {
+      CreateMockWrite(*req, 0), CreateMockWrite(*rst, 2),
+  };
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
   NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
                                      BoundNetLog(), GetParam(), NULL);
   helper.RunToCompletion(&data);
@@ -2112,21 +2073,19 @@
   scoped_ptr<SpdyFrame> rst(
       spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR));
   MockWrite writes[] = {
-    CreateMockWrite(*req),
-    CreateMockWrite(*rst),
+      CreateMockWrite(*req, 0), CreateMockWrite(*rst, 4),
   };
 
   scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
   scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
   MockRead reads[] = {
-    CreateMockRead(*resp),
-    CreateMockRead(*resp),
-    CreateMockRead(*body),
-    MockRead(ASYNC, 0, 0)  // EOF
+      CreateMockRead(*resp, 1),
+      CreateMockRead(*resp, 2),
+      CreateMockRead(*body, 3),
+      MockRead(ASYNC, 0, 5)  // EOF
   };
 
-  DelayedSocketData data(1, reads, arraysize(reads),
-                         writes, arraysize(writes));
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
 
   NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
                                      BoundNetLog(), GetParam(), NULL);
@@ -2159,8 +2118,7 @@
   scoped_ptr<SpdyFrame> rst(
       spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR));
   MockWrite writes[] = {
-    CreateMockWrite(*req),
-    CreateMockWrite(*rst),
+      CreateMockWrite(*req, 0), CreateMockWrite(*rst, 2),
   };
 
   const char* const headers[] = {
@@ -2171,13 +2129,12 @@
   scoped_ptr<SpdyFrame> body(
       spdy_util_.ConstructSpdyBodyFrame(1, true));
   MockRead reads[] = {
-    CreateMockRead(*resp),
-    CreateMockRead(*body),
-    MockRead(ASYNC, 0, 0)  // EOF
+      CreateMockRead(*resp, 1),
+      CreateMockRead(*body, 3),
+      MockRead(ASYNC, 0, 4)  // EOF
   };
 
-  DelayedSocketData data(1, reads, arraysize(reads),
-                         writes, arraysize(writes));
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
   NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
                                      BoundNetLog(), GetParam(), NULL);
   helper.RunToCompletion(&data);
@@ -2195,8 +2152,7 @@
   scoped_ptr<SpdyFrame> rst(
       spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR));
   MockWrite writes[] = {
-    CreateMockWrite(*req),
-    CreateMockWrite(*rst),
+      CreateMockWrite(*req, 0), CreateMockWrite(*rst, 4),
   };
 
   scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
@@ -2208,14 +2164,13 @@
                                    GetDefaultUrlWithPath("/1").c_str()));
   scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
   MockRead reads[] = {
-    CreateMockRead(*resp),
-    CreateMockRead(*push),
-    CreateMockRead(*body),
-    MockRead(ASYNC, 0, 0)  // EOF
+      CreateMockRead(*resp, 1),
+      CreateMockRead(*push, 2),
+      CreateMockRead(*body, 3),
+      MockRead(ASYNC, 0, 5)  // EOF
   };
 
-  DelayedSocketData data(1, reads, arraysize(reads),
-                         writes, arraysize(writes));
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
   NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
                                      BoundNetLog(), GetParam(), NULL);
   helper.RunToCompletion(&data);
@@ -2316,8 +2271,8 @@
 TEST_P(SpdyNetworkTransactionTest, StartTransactionOnReadCallback) {
   scoped_ptr<SpdyFrame> req(
       spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
-  MockWrite writes[] = { CreateMockWrite(*req) };
-  MockWrite writes2[] = { CreateMockWrite(*req) };
+  MockWrite writes[] = {CreateMockWrite(*req)};
+  MockWrite writes2[] = {CreateMockWrite(*req, 0)};
 
   // The indicated length of this frame is longer than its actual length. When
   // the session receives an empty frame after this one, it shuts down the
@@ -2330,22 +2285,20 @@
 
   scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
   MockRead reads[] = {
-    CreateMockRead(*resp, 2),
-    MockRead(ASYNC, ERR_IO_PENDING, 3),  // Force a pause
-    MockRead(ASYNC, reinterpret_cast<const char*>(kGetBodyFrame2),
-             arraysize(kGetBodyFrame2), 4),
-    MockRead(ASYNC, ERR_IO_PENDING, 5),  // Force a pause
-    MockRead(ASYNC, 0, 0, 6),  // EOF
+      CreateMockRead(*resp, 1),
+      MockRead(ASYNC, ERR_IO_PENDING, 2),  // Force a pause
+      MockRead(ASYNC, reinterpret_cast<const char*>(kGetBodyFrame2),
+               arraysize(kGetBodyFrame2), 3),
+      MockRead(ASYNC, ERR_IO_PENDING, 4),  // Force a pause
+      MockRead(ASYNC, 0, 0, 5),            // EOF
   };
   MockRead reads2[] = {
-    CreateMockRead(*resp, 2),
-    MockRead(ASYNC, 0, 0, 3),  // EOF
+      CreateMockRead(*resp, 1), MockRead(ASYNC, 0, 0, 2),  // EOF
   };
 
-  OrderedSocketData data(reads, arraysize(reads),
-                         writes, arraysize(writes));
-  DelayedSocketData data2(1, reads2, arraysize(reads2),
-                          writes2, arraysize(writes2));
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
+  SequencedSocketData data2(reads2, arraysize(reads2), writes2,
+                            arraysize(writes2));
 
   NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
                                      BoundNetLog(), GetParam(), NULL);
@@ -2366,6 +2319,7 @@
       buf.get(), kSize,
       base::Bind(&SpdyNetworkTransactionTest::StartTransactionCallback,
                  helper.session(), GURL(GetDefaultUrl())));
+  ASSERT_EQ(ERR_IO_PENDING, rv);
   // This forces an err_IO_pending, which sets the callback.
   data.CompleteRead();
   // This finishes the read.
@@ -2379,19 +2333,18 @@
 TEST_P(SpdyNetworkTransactionTest, DeleteSessionOnReadCallback) {
   scoped_ptr<SpdyFrame> req(
       spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
-  MockWrite writes[] = { CreateMockWrite(*req) };
+  MockWrite writes[] = {CreateMockWrite(*req, 0)};
 
   scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
   scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
   MockRead reads[] = {
-    CreateMockRead(*resp.get(), 2),
-    MockRead(ASYNC, ERR_IO_PENDING, 3),  // Force a pause
-    CreateMockRead(*body.get(), 4),
-    MockRead(ASYNC, 0, 0, 5),  // EOF
+      CreateMockRead(*resp.get(), 1),
+      MockRead(ASYNC, ERR_IO_PENDING, 2),  // Force a pause
+      CreateMockRead(*body.get(), 3),
+      MockRead(ASYNC, 0, 0, 4),  // EOF
   };
 
-  OrderedSocketData data(reads, arraysize(reads),
-                         writes, arraysize(writes));
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
 
   NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
                                      BoundNetLog(), GetParam(), NULL);
@@ -2458,10 +2411,9 @@
     CreateMockRead(*body2, 3),
     MockRead(ASYNC, 0, 0, 4)  // EOF
   };
-  OrderedSocketData data(reads, arraysize(reads),
-                         writes, arraysize(writes));
-  OrderedSocketData data2(reads2, arraysize(reads2),
-                          writes2, arraysize(writes2));
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
+  SequencedSocketData data2(reads2, arraysize(reads2), writes2,
+                            arraysize(writes2));
 
   // TODO(erikchen): Make test support SPDYSSL, SPDYNPN
   TestDelegate d;
@@ -2541,10 +2493,9 @@
     CreateMockRead(*body2, 3),
     MockRead(ASYNC, 0, 0, 5)  // EOF
   };
-  OrderedSocketData data(reads, arraysize(reads),
-                         writes, arraysize(writes));
-  OrderedSocketData data2(reads2, arraysize(reads2),
-                          writes2, arraysize(writes2));
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
+  SequencedSocketData data2(reads2, arraysize(reads2), writes2,
+                            arraysize(writes2));
 
   // TODO(erikchen): Make test support SPDYSSL, SPDYNPN
   TestDelegate d;
@@ -2581,12 +2532,10 @@
     std::string contents2("hello!");
     EXPECT_EQ(contents2, d2.data_received());
   }
-  data.CompleteRead();
-  data2.CompleteRead();
-  EXPECT_TRUE(data.at_read_eof());
-  EXPECT_TRUE(data.at_write_eof());
-  EXPECT_TRUE(data2.at_read_eof());
-  EXPECT_TRUE(data2.at_write_eof());
+  EXPECT_TRUE(data.AllReadDataConsumed());
+  EXPECT_TRUE(data.AllWriteDataConsumed());
+  EXPECT_TRUE(data2.AllReadDataConsumed());
+  EXPECT_TRUE(data2.AllWriteDataConsumed());
 }
 
 TEST_P(SpdyNetworkTransactionTest, ServerPushSingleDataFrame) {
@@ -2595,7 +2544,7 @@
   scoped_ptr<SpdyFrame> stream1_body(
       spdy_util_.ConstructSpdyBodyFrame(1, true));
   MockWrite writes[] = {
-    CreateMockWrite(*stream1_syn, 1),
+      CreateMockWrite(*stream1_syn, 0),
   };
 
   scoped_ptr<SpdyFrame>
@@ -2607,18 +2556,17 @@
       spdy_util_.ConstructSpdyBodyFrame(
           2, kPushedData, strlen(kPushedData), true));
   MockRead reads[] = {
-    CreateMockRead(*stream1_reply, 2),
-    CreateMockRead(*stream2_syn, 3),
-    CreateMockRead(*stream1_body, 4, SYNCHRONOUS),
-    CreateMockRead(*stream2_body, 5),
-    MockRead(ASYNC, ERR_IO_PENDING, 6),  // Force a pause
+      CreateMockRead(*stream1_reply, 1),
+      CreateMockRead(*stream2_syn, 2),
+      CreateMockRead(*stream1_body, 3, SYNCHRONOUS),
+      CreateMockRead(*stream2_body, 4),
+      MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5),  // Force a pause
   };
 
   HttpResponseInfo response;
   HttpResponseInfo response2;
   std::string expected_push_result("pushed");
-  OrderedSocketData data(reads, arraysize(reads),
-                         writes, arraysize(writes));
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
   RunServerPushTest(&data,
                     &response,
                     &response2,
@@ -2639,7 +2587,7 @@
   scoped_ptr<SpdyFrame> stream1_body(
       spdy_util_.ConstructSpdyBodyFrame(1, true));
   MockWrite writes[] = {
-    CreateMockWrite(*stream1_syn, 1),
+      CreateMockWrite(*stream1_syn, 0),
   };
 
   scoped_ptr<SpdyFrame>
@@ -2651,18 +2599,17 @@
       spdy_util_.ConstructSpdyBodyFrame(
           2, kPushedData, strlen(kPushedData), true));
   MockRead reads[] = {
-    CreateMockRead(*stream2_syn, 2),
-    CreateMockRead(*stream1_reply, 3),
-    CreateMockRead(*stream1_body, 4, SYNCHRONOUS),
-    CreateMockRead(*stream2_body, 5),
-    MockRead(ASYNC, ERR_IO_PENDING, 6),  // Force a pause
+      CreateMockRead(*stream2_syn, 1),
+      CreateMockRead(*stream1_reply, 2),
+      CreateMockRead(*stream1_body, 3, SYNCHRONOUS),
+      CreateMockRead(*stream2_body, 4),
+      MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5),  // Force a pause
   };
 
   HttpResponseInfo response;
   HttpResponseInfo response2;
   std::string expected_push_result("pushed");
-  OrderedSocketData data(reads, arraysize(reads),
-                         writes, arraysize(writes));
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
   RunServerPushTest(&data,
                     &response,
                     &response2,
@@ -2680,7 +2627,9 @@
 TEST_P(SpdyNetworkTransactionTest, ServerPushSingleDataFrame2) {
   scoped_ptr<SpdyFrame> stream1_syn(
       spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
-  MockWrite writes[] = { CreateMockWrite(*stream1_syn, 1), };
+  MockWrite writes[] = {
+      CreateMockWrite(*stream1_syn, 0),
+  };
 
   scoped_ptr<SpdyFrame>
       stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
@@ -2693,18 +2642,17 @@
   scoped_ptr<SpdyFrame>
       stream1_body(spdy_util_.ConstructSpdyBodyFrame(1, true));
   MockRead reads[] = {
-    CreateMockRead(*stream1_reply, 2),
-    CreateMockRead(*stream2_syn, 3),
-    CreateMockRead(*stream2_body, 4),
-    CreateMockRead(*stream1_body, 5, SYNCHRONOUS),
-    MockRead(ASYNC, ERR_IO_PENDING, 6),  // Force a pause
+      CreateMockRead(*stream1_reply, 1),
+      CreateMockRead(*stream2_syn, 2),
+      CreateMockRead(*stream2_body, 3),
+      CreateMockRead(*stream1_body, 4, SYNCHRONOUS),
+      MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5),  // Force a pause
   };
 
   HttpResponseInfo response;
   HttpResponseInfo response2;
   std::string expected_push_result("pushed");
-  OrderedSocketData data(reads, arraysize(reads),
-                         writes, arraysize(writes));
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
   RunServerPushTest(&data,
                     &response,
                     &response2,
@@ -2725,7 +2673,7 @@
   scoped_ptr<SpdyFrame> stream1_body(
       spdy_util_.ConstructSpdyBodyFrame(1, true));
   MockWrite writes[] = {
-    CreateMockWrite(*stream1_syn, 1),
+      CreateMockWrite(*stream1_syn, 0),
   };
 
   scoped_ptr<SpdyFrame>
@@ -2735,15 +2683,14 @@
   scoped_ptr<SpdyFrame> stream2_rst(
       spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR));
   MockRead reads[] = {
-    CreateMockRead(*stream1_reply, 2),
-    CreateMockRead(*stream2_syn, 3),
-    CreateMockRead(*stream2_rst, 4),
-    CreateMockRead(*stream1_body, 5, SYNCHRONOUS),
-    MockRead(ASYNC, ERR_IO_PENDING, 6),  // Force a pause
+      CreateMockRead(*stream1_reply, 1),
+      CreateMockRead(*stream2_syn, 2),
+      CreateMockRead(*stream2_rst, 3),
+      CreateMockRead(*stream1_body, 4, SYNCHRONOUS),
+      MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5),  // Force a pause
   };
 
-  OrderedSocketData data(reads, arraysize(reads),
-                         writes, arraysize(writes));
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
   NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
                                      BoundNetLog(), GetParam(), NULL);
 
@@ -2761,14 +2708,8 @@
   EXPECT_EQ(OK, rv);
 
   // Verify that we consumed all test data.
-  EXPECT_TRUE(data.at_read_eof()) << "Read count: "
-                                   << data.read_count()
-                                   << " Read index: "
-                                   << data.read_index();
-  EXPECT_TRUE(data.at_write_eof()) << "Write count: "
-                                    << data.write_count()
-                                    << " Write index: "
-                                    << data.write_index();
+  EXPECT_TRUE(data.AllReadDataConsumed());
+  EXPECT_TRUE(data.AllWriteDataConsumed());
 
   // Verify the SYN_REPLY.
   HttpResponseInfo response = *trans->GetResponseInfo();
@@ -2786,8 +2727,7 @@
   scoped_ptr<SpdyFrame> stream3_rst(
       spdy_util_.ConstructSpdyRstStream(4, RST_STREAM_PROTOCOL_ERROR));
   MockWrite writes[] = {
-    CreateMockWrite(*stream1_syn, 1),
-    CreateMockWrite(*stream3_rst, 5),
+      CreateMockWrite(*stream1_syn, 0), CreateMockWrite(*stream3_rst, 4),
   };
 
   scoped_ptr<SpdyFrame>
@@ -2801,19 +2741,18 @@
   scoped_ptr<SpdyFrame> stream3_syn(spdy_util_.ConstructSpdyPush(
       NULL, 0, 4, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
   MockRead reads[] = {
-    CreateMockRead(*stream1_reply, 2),
-    CreateMockRead(*stream2_syn, 3),
-    CreateMockRead(*stream3_syn, 4),
-    CreateMockRead(*stream1_body, 6, SYNCHRONOUS),
-    CreateMockRead(*stream2_body, 7),
-    MockRead(ASYNC, ERR_IO_PENDING, 8),  // Force a pause
+      CreateMockRead(*stream1_reply, 1),
+      CreateMockRead(*stream2_syn, 2),
+      CreateMockRead(*stream3_syn, 3),
+      CreateMockRead(*stream1_body, 5),
+      CreateMockRead(*stream2_body, 6),
+      MockRead(SYNCHRONOUS, ERR_IO_PENDING, 7),  // Force a pause
   };
 
   HttpResponseInfo response;
   HttpResponseInfo response2;
   std::string expected_push_result("pushed");
-  OrderedSocketData data(reads, arraysize(reads),
-                         writes, arraysize(writes));
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
   RunServerPushTest(&data,
                     &response,
                     &response2,
@@ -2834,7 +2773,7 @@
   scoped_ptr<SpdyFrame> stream1_body(
       spdy_util_.ConstructSpdyBodyFrame(1, true));
   MockWrite writes[] = {
-    CreateMockWrite(*stream1_syn, 1),
+      CreateMockWrite(*stream1_syn, 0),
   };
 
   scoped_ptr<SpdyFrame>
@@ -2857,21 +2796,20 @@
       new SpdyFrame(stream2_body_base->data() + 3 * kChunkSize,
                     stream2_body_base->size() - 3 * kChunkSize, false));
   MockRead reads[] = {
-    CreateMockRead(*stream1_reply, 2),
-    CreateMockRead(*stream2_syn, 3),
-    CreateMockRead(*stream2_body1, 4),
-    CreateMockRead(*stream2_body2, 5),
-    CreateMockRead(*stream2_body3, 6),
-    CreateMockRead(*stream2_body4, 7),
-    CreateMockRead(*stream1_body, 8, SYNCHRONOUS),
-    MockRead(ASYNC, ERR_IO_PENDING, 9),  // Force a pause
+      CreateMockRead(*stream1_reply, 1),
+      CreateMockRead(*stream2_syn, 2),
+      CreateMockRead(*stream2_body1, 3),
+      CreateMockRead(*stream2_body2, 4),
+      CreateMockRead(*stream2_body3, 5),
+      CreateMockRead(*stream2_body4, 6),
+      CreateMockRead(*stream1_body, 7, SYNCHRONOUS),
+      MockRead(SYNCHRONOUS, ERR_IO_PENDING, 8),  // Force a pause
   };
 
   HttpResponseInfo response;
   HttpResponseInfo response2;
   std::string expected_push_result("pushed my darling hello my baby");
-  OrderedSocketData data(reads, arraysize(reads),
-                         writes, arraysize(writes));
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
   RunServerPushTest(&data, &response, &response2, kPushedData);
 
   // Verify the SYN_REPLY.
@@ -2889,7 +2827,7 @@
   scoped_ptr<SpdyFrame> stream1_body(
       spdy_util_.ConstructSpdyBodyFrame(1, true));
   MockWrite writes[] = {
-    CreateMockWrite(*stream1_syn, 1),
+      CreateMockWrite(*stream1_syn, 0),
   };
 
   scoped_ptr<SpdyFrame>
@@ -2912,21 +2850,19 @@
       new SpdyFrame(stream2_body_base->data() + 3 * kChunkSize,
                     stream2_body_base->size() - 3 * kChunkSize, false));
   MockRead reads[] = {
-    CreateMockRead(*stream1_reply, 2),
-    CreateMockRead(*stream2_syn, 3),
-    CreateMockRead(*stream2_body1, 4),
-    CreateMockRead(*stream2_body2, 5),
-    MockRead(ASYNC, ERR_IO_PENDING, 6),  // Force a pause
-    CreateMockRead(*stream2_body3, 7),
-    CreateMockRead(*stream2_body4, 8),
-    CreateMockRead(*stream1_body.get(), 9, SYNCHRONOUS),
-    MockRead(ASYNC, ERR_IO_PENDING, 10)  // Force a pause.
+      CreateMockRead(*stream1_reply, 1),
+      CreateMockRead(*stream2_syn, 2),
+      CreateMockRead(*stream2_body1, 3),
+      CreateMockRead(*stream2_body2, 4),
+      CreateMockRead(*stream2_body3, 5),
+      CreateMockRead(*stream2_body4, 6),
+      CreateMockRead(*stream1_body.get(), 7, SYNCHRONOUS),
+      MockRead(SYNCHRONOUS, ERR_IO_PENDING, 8)  // Force a pause.
   };
 
   HttpResponseInfo response;
   HttpResponseInfo response2;
-  OrderedSocketData data(reads, arraysize(reads),
-                         writes, arraysize(writes));
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
   RunServerPushTest(&data, &response, &response2, kPushedData);
 
   // Verify the SYN_REPLY.
@@ -2952,8 +2888,7 @@
   scoped_ptr<SpdyFrame> stream2_rst(
       spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_REFUSED_STREAM));
   MockWrite writes[] = {
-    CreateMockWrite(*stream1_syn, 1),
-    CreateMockWrite(*stream2_rst, 4),
+      CreateMockWrite(*stream1_syn, 0), CreateMockWrite(*stream2_rst, 3),
   };
 
   scoped_ptr<SpdyFrame>
@@ -2961,14 +2896,13 @@
   scoped_ptr<SpdyFrame> stream2_syn(spdy_util_.ConstructSpdyPush(
       NULL, 0, 2, 0, GetDefaultUrlWithPath("/foo.dat").c_str()));
   MockRead reads[] = {
-    CreateMockRead(*stream1_reply, 2),
-    CreateMockRead(*stream2_syn, 3),
-    CreateMockRead(*stream1_body, 4),
-    MockRead(ASYNC, ERR_IO_PENDING, 5)  // Force a pause
+      CreateMockRead(*stream1_reply, 1),
+      CreateMockRead(*stream2_syn, 2),
+      CreateMockRead(*stream1_body, 4),
+      MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5)  // Force a pause
   };
 
-  OrderedSocketData data(reads, arraysize(reads),
-                         writes, arraysize(writes));
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
   NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
                                      BoundNetLog(), GetParam(), NULL);
 
@@ -2986,14 +2920,8 @@
   EXPECT_EQ(OK, rv);
 
   // Verify that we consumed all test data.
-  EXPECT_TRUE(data.at_read_eof()) << "Read count: "
-                                   << data.read_count()
-                                   << " Read index: "
-                                   << data.read_index();
-  EXPECT_TRUE(data.at_write_eof()) << "Write count: "
-                                    << data.write_count()
-                                    << " Write index: "
-                                    << data.write_index();
+  EXPECT_TRUE(data.AllReadDataConsumed());
+  EXPECT_TRUE(data.AllWriteDataConsumed());
 
   // Verify the SYN_REPLY.
   HttpResponseInfo response = *trans->GetResponseInfo();
@@ -3009,8 +2937,7 @@
   scoped_ptr<SpdyFrame> stream2_rst(
       spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_INVALID_STREAM));
   MockWrite writes[] = {
-    CreateMockWrite(*stream1_syn, 1),
-    CreateMockWrite(*stream2_rst, 4),
+      CreateMockWrite(*stream1_syn, 0), CreateMockWrite(*stream2_rst, 3),
   };
 
   scoped_ptr<SpdyFrame>
@@ -3018,14 +2945,13 @@
   scoped_ptr<SpdyFrame> stream2_syn(spdy_util_.ConstructSpdyPush(
       NULL, 0, 2, 9, GetDefaultUrlWithPath("/foo.dat").c_str()));
   MockRead reads[] = {
-    CreateMockRead(*stream1_reply, 2),
-    CreateMockRead(*stream2_syn, 3),
-    CreateMockRead(*stream1_body, 4),
-    MockRead(ASYNC, ERR_IO_PENDING, 5),  // Force a pause
+      CreateMockRead(*stream1_reply, 1),
+      CreateMockRead(*stream2_syn, 2),
+      CreateMockRead(*stream1_body, 4),
+      MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5),  // Force a pause
   };
 
-  OrderedSocketData data(reads, arraysize(reads),
-                         writes, arraysize(writes));
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
   NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
                                      BoundNetLog(), GetParam(), NULL);
 
@@ -3043,14 +2969,8 @@
   EXPECT_EQ(OK, rv);
 
   // Verify that we consumed all test data.
-  EXPECT_TRUE(data.at_read_eof()) << "Read count: "
-                                   << data.read_count()
-                                   << " Read index: "
-                                   << data.read_index();
-  EXPECT_TRUE(data.at_write_eof()) << "Write count: "
-                                    << data.write_count()
-                                    << " Write index: "
-                                    << data.write_index();
+  EXPECT_TRUE(data.AllReadDataConsumed());
+  EXPECT_TRUE(data.AllWriteDataConsumed());
 
   // Verify the SYN_REPLY.
   HttpResponseInfo response = *trans->GetResponseInfo();
@@ -3066,8 +2986,7 @@
   scoped_ptr<SpdyFrame> stream2_rst(
       spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR));
   MockWrite writes[] = {
-    CreateMockWrite(*stream1_syn, 1),
-    CreateMockWrite(*stream2_rst, 4),
+      CreateMockWrite(*stream1_syn, 0), CreateMockWrite(*stream2_rst, 3),
   };
 
   scoped_ptr<SpdyFrame>
@@ -3079,14 +2998,13 @@
   scoped_ptr<SpdyFrame> stream2_syn(spdy_util_.ConstructInitialSpdyPushFrame(
       incomplete_headers.Pass(), 2, 1));
   MockRead reads[] = {
-    CreateMockRead(*stream1_reply, 2),
-    CreateMockRead(*stream2_syn, 3),
-    CreateMockRead(*stream1_body, 4),
-    MockRead(ASYNC, ERR_IO_PENDING, 5)  // Force a pause
+      CreateMockRead(*stream1_reply, 1),
+      CreateMockRead(*stream2_syn, 2),
+      CreateMockRead(*stream1_body, 4),
+      MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5)  // Force a pause
   };
 
-  OrderedSocketData data(reads, arraysize(reads),
-                         writes, arraysize(writes));
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
   NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
                                      BoundNetLog(), GetParam(), NULL);
 
@@ -3102,15 +3020,10 @@
   EXPECT_EQ(ERR_IO_PENDING, rv);
   rv = callback.WaitForResult();
   EXPECT_EQ(OK, rv);
+
   // Verify that we consumed all test data.
-  EXPECT_TRUE(data.at_read_eof()) << "Read count: "
-                                   << data.read_count()
-                                   << " Read index: "
-                                   << data.read_index();
-  EXPECT_TRUE(data.at_write_eof()) << "Write count: "
-                                    << data.write_count()
-                                    << " Write index: "
-                                    << data.write_index();
+  EXPECT_TRUE(data.AllReadDataConsumed());
+  EXPECT_TRUE(data.AllWriteDataConsumed());
 
   // Verify the SYN_REPLY.
   HttpResponseInfo response = *trans->GetResponseInfo();
@@ -3168,7 +3081,7 @@
   for (size_t i = 0; i < arraysize(test_cases); ++i) {
     scoped_ptr<SpdyFrame> req(
         spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
-    MockWrite writes[] = { CreateMockWrite(*req) };
+    MockWrite writes[] = {CreateMockWrite(*req, 0)};
 
     scoped_ptr<SpdyFrame> resp(
         spdy_util_.ConstructSpdyGetSynReply(test_cases[i].extra_headers,
@@ -3176,13 +3089,13 @@
                                  1));
     scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
     MockRead reads[] = {
-      CreateMockRead(*resp),
-      CreateMockRead(*body),
-      MockRead(ASYNC, 0, 0)  // EOF
+        CreateMockRead(*resp, 1),
+        CreateMockRead(*body, 2),
+        MockRead(ASYNC, 0, 3)  // EOF
     };
 
-    DelayedSocketData data(1, reads, arraysize(reads),
-                           writes, arraysize(writes));
+    SequencedSocketData data(reads, arraysize(reads), writes,
+                             arraysize(writes));
     NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
                                        BoundNetLog(), GetParam(), NULL);
     helper.RunToCompletion(&data);
@@ -3286,7 +3199,7 @@
                                     false, 1, LOWEST, true));
 
     MockWrite writes[] = {
-      CreateMockWrite(*frame_req),
+        CreateMockWrite(*frame_req, 0),
     };
 
     // Construct the reply.
@@ -3299,9 +3212,9 @@
 
     scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
     MockRead reads[] = {
-      CreateMockRead(*frame_reply),
-      CreateMockRead(*body),
-      MockRead(ASYNC, 0, 0)  // EOF
+        CreateMockRead(*frame_reply, 1),
+        CreateMockRead(*body, 2),
+        MockRead(ASYNC, 0, 3)  // EOF
     };
 
     // Attach the headers to the request.
@@ -3314,8 +3227,8 @@
       request.extra_headers.SetHeader(header_key, header_value);
     }
 
-    DelayedSocketData data(1, reads, arraysize(reads),
-                           writes, arraysize(writes));
+    SequencedSocketData data(reads, arraysize(reads), writes,
+                             arraysize(writes));
     NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY,
                                        BoundNetLog(), GetParam(), NULL);
     helper.RunToCompletion(&data);
@@ -3380,8 +3293,7 @@
     scoped_ptr<SpdyFrame> rst(
       spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR));
     MockWrite writes[] = {
-      CreateMockWrite(*req),
-      CreateMockWrite(*rst),
+        CreateMockWrite(*req, 0), CreateMockWrite(*rst, 2),
     };
 
     // Construct the reply.
@@ -3390,12 +3302,11 @@
         test_cases[i].headers, test_cases[i].num_headers, &reply_headers);
     scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyReply(1, reply_headers));
     MockRead reads[] = {
-      CreateMockRead(*resp),
-      MockRead(ASYNC, 0, 0)  // EOF
+        CreateMockRead(*resp, 1), MockRead(ASYNC, 0, 3)  // EOF
     };
 
-    DelayedSocketData data(1, reads, arraysize(reads),
-                           writes, arraysize(writes));
+    SequencedSocketData data(reads, arraysize(reads), writes,
+                             arraysize(writes));
     NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
                                        BoundNetLog(), GetParam(), NULL);
     helper.RunToCompletion(&data);
@@ -3436,19 +3347,18 @@
     scoped_ptr<SpdyFrame> rst(
         spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR));
     MockWrite writes[] = {
-      CreateMockWrite(*req),
-      CreateMockWrite(*rst),
+        CreateMockWrite(*req, 0), CreateMockWrite(*rst, 3),
     };
 
     scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
     MockRead reads[] = {
-      MockRead(ASYNC, test_cases[i].syn_reply->data(), wrong_size),
-      CreateMockRead(*body),
-      MockRead(ASYNC, 0, 0)  // EOF
+        MockRead(ASYNC, test_cases[i].syn_reply->data(), wrong_size, 1),
+        CreateMockRead(*body, 2),
+        MockRead(ASYNC, 0, 4)  // EOF
     };
 
-    DelayedSocketData data(1, reads, arraysize(reads),
-                           writes, arraysize(writes));
+    SequencedSocketData data(reads, arraysize(reads), writes,
+                             arraysize(writes));
     NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
                                        BoundNetLog(), GetParam(), NULL);
     helper.RunToCompletion(&data);
@@ -3477,16 +3387,15 @@
       spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
   scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway(
       0, GOAWAY_COMPRESSION_ERROR, "Framer error: 5 (DECOMPRESS_FAILURE)."));
-  MockWrite writes[] = {CreateMockWrite(*req), CreateMockWrite(*goaway)};
+  MockWrite writes[] = {CreateMockWrite(*req, 0), CreateMockWrite(*goaway, 2)};
 
   scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
   MockRead reads[] = {
-    MockRead(ASYNC, syn_reply_wrong_length->data(),
-             syn_reply_wrong_length->size() - 4),
+      MockRead(ASYNC, syn_reply_wrong_length->data(),
+               syn_reply_wrong_length->size() - 4, 1),
   };
 
-  DelayedSocketData data(1, reads, arraysize(reads),
-                         writes, arraysize(writes));
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
   NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
                                      BoundNetLog(), GetParam(), NULL);
   helper.RunToCompletion(&data);
@@ -3503,14 +3412,14 @@
       spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
   scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway(
       0, GOAWAY_COMPRESSION_ERROR, "Framer error: 5 (DECOMPRESS_FAILURE)."));
-  MockWrite writes[] = {CreateMockWrite(*req), CreateMockWrite(*goaway)};
+  MockWrite writes[] = {CreateMockWrite(*req, 0), CreateMockWrite(*goaway, 2)};
 
   // Read HEADERS with corrupted payload.
   scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
   memset(resp->data() + 12, 0xff, resp->size() - 12);
-  MockRead reads[] = {CreateMockRead(*resp)};
+  MockRead reads[] = {CreateMockRead(*resp, 1)};
 
-  DelayedSocketData data(1, reads, arraysize(reads), writes, arraysize(writes));
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
   NormalSpdyTransactionHelper helper(
       CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL);
   helper.RunToCompletion(&data);
@@ -3523,7 +3432,7 @@
       spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
   scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway(
       0, GOAWAY_PROTOCOL_ERROR, "Framer error: 1 (INVALID_CONTROL_FRAME)."));
-  MockWrite writes[] = {CreateMockWrite(*req), CreateMockWrite(*goaway)};
+  MockWrite writes[] = {CreateMockWrite(*req, 0), CreateMockWrite(*goaway, 2)};
 
   // Read WINDOW_UPDATE with incorrectly-sized payload.
   // TODO(jgraettinger): SpdyFramer signals this as an INVALID_CONTROL_FRAME,
@@ -3533,9 +3442,9 @@
   test::SetFrameLength(bad_window_update.get(),
                        bad_window_update->size() - 1,
                        spdy_util_.spdy_version());
-  MockRead reads[] = {CreateMockRead(*bad_window_update)};
+  MockRead reads[] = {CreateMockRead(*bad_window_update, 1)};
 
-  DelayedSocketData data(1, reads, arraysize(reads), writes, arraysize(writes));
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
   NormalSpdyTransactionHelper helper(
       CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL);
   helper.RunToCompletion(&data);
@@ -3584,17 +3493,19 @@
       spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
   const int kChunks = 5;
   scoped_ptr<MockWrite[]> writes(ChopWriteFrame(*req.get(), kChunks));
+  for (int i = 0; i < kChunks; ++i) {
+    writes[i].sequence_number = i;
+  }
 
   scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
   scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
   MockRead reads[] = {
-    CreateMockRead(*resp),
-    CreateMockRead(*body),
-    MockRead(ASYNC, 0, 0)  // EOF
+      CreateMockRead(*resp, kChunks),
+      CreateMockRead(*body, kChunks + 1),
+      MockRead(ASYNC, 0, kChunks + 2)  // EOF
   };
 
-  DelayedSocketData data(kChunks, reads, arraysize(reads),
-                         writes.get(), kChunks);
+  SequencedSocketData data(reads, arraysize(reads), writes.get(), kChunks);
   NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
                                      BoundNetLog(), GetParam(), NULL);
   helper.RunToCompletion(&data);
@@ -3615,16 +3526,16 @@
       spdy_util_.ConstructSpdyGet(NULL, 0, true, 1, LOWEST, true));
   scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway(
       0, GOAWAY_COMPRESSION_ERROR, "Framer error: 5 (DECOMPRESS_FAILURE)."));
-  MockWrite writes[] = {CreateMockWrite(*compressed), CreateMockWrite(*goaway)};
+  MockWrite writes[] = {CreateMockWrite(*compressed, 0),
+                        CreateMockWrite(*goaway, 2)};
 
   scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
   scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
   MockRead reads[] = {
-    CreateMockRead(*resp),
+      CreateMockRead(*resp, 1),
   };
 
-  DelayedSocketData data(1, reads, arraysize(reads),
-                         writes, arraysize(writes));
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
   SpdySessionDependencies* session_deps =
       CreateSpdySessionDependencies(GetParam());
   session_deps->enable_compression = true;
@@ -3643,20 +3554,19 @@
   };
   scoped_ptr<SpdyFrame> req(
       spdy_util_.ConstructSpdyGet(kExtraHeaders, 1, false, 1, LOWEST, true));
-  MockWrite writes[] = { CreateMockWrite(*req) };
+  MockWrite writes[] = {CreateMockWrite(*req, 0)};
 
   scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
   scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
   MockRead reads[] = {
-    CreateMockRead(*resp),
-    CreateMockRead(*body),
-    MockRead(ASYNC, 0, 0)  // EOF
+      CreateMockRead(*resp, 1),
+      CreateMockRead(*body, 2),
+      MockRead(ASYNC, 0, 3)  // EOF
   };
 
   BoundTestNetLog log;
 
-  DelayedSocketData data(1, reads, arraysize(reads),
-                         writes, arraysize(writes));
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
   NormalSpdyTransactionHelper helper(CreateGetRequestWithUserAgent(),
                                      DEFAULT_PRIORITY,
                                      log.bound(), GetParam(), NULL);
@@ -3735,7 +3645,7 @@
 
   scoped_ptr<SpdyFrame> req(
       spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
-  MockWrite writes[] = { CreateMockWrite(*req) };
+  MockWrite writes[] = {CreateMockWrite(*req, 0)};
 
   // 2 data frames in a single read.
   scoped_ptr<SpdyFrame> data_frame_1(
@@ -3755,16 +3665,15 @@
 
   scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
   MockRead reads[] = {
-    CreateMockRead(*resp),
-    MockRead(ASYNC, ERR_IO_PENDING),  // Force a pause
-    MockRead(ASYNC, combined_data_frames, combined_data_frames_len),
-    MockRead(ASYNC, ERR_IO_PENDING),  // Force a pause
-    CreateMockRead(*last_frame),
-    MockRead(ASYNC, 0, 0)  // EOF
+      CreateMockRead(*resp, 1),
+      MockRead(ASYNC, ERR_IO_PENDING, 2),  // Force a pause
+      MockRead(ASYNC, combined_data_frames, combined_data_frames_len, 3),
+      MockRead(ASYNC, ERR_IO_PENDING, 4),  // Force a pause
+      CreateMockRead(*last_frame, 5),
+      MockRead(ASYNC, 0, 6)  // EOF
   };
 
-  DelayedSocketData data(1, reads, arraysize(reads),
-                         writes, arraysize(writes));
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
 
   TestCompletionCallback callback;
 
@@ -3829,7 +3738,7 @@
 
   scoped_ptr<SpdyFrame> req(
       spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
-  MockWrite writes[] = { CreateMockWrite(*req) };
+  MockWrite writes[] = {CreateMockWrite(*req, 0)};
 
   // 4 data frames in a single read.
   scoped_ptr<SpdyFrame> data_frame(
@@ -3849,14 +3758,13 @@
 
   scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
   MockRead reads[] = {
-    CreateMockRead(*resp),
-    MockRead(ASYNC, ERR_IO_PENDING),  // Force a pause
-    MockRead(ASYNC, combined_data_frames, combined_data_frames_len),
-    MockRead(ASYNC, 0, 0)  // EOF
+      CreateMockRead(*resp, 1),
+      MockRead(ASYNC, ERR_IO_PENDING, 2),  // Force a pause
+      MockRead(ASYNC, combined_data_frames, combined_data_frames_len, 3),
+      MockRead(ASYNC, 0, 4)  // EOF
   };
 
-  DelayedSocketData data(1, reads, arraysize(reads),
-                         writes, arraysize(writes));
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
 
   NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
                                      BoundNetLog(), GetParam(), NULL);
@@ -3924,7 +3832,7 @@
 
   scoped_ptr<SpdyFrame> req(
       spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
-  MockWrite writes[] = { CreateMockWrite(*req) };
+  MockWrite writes[] = {CreateMockWrite(*req, 0)};
 
   // 5 data frames in a single read.
   scoped_ptr<SpdyFrame> reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
@@ -3940,12 +3848,11 @@
                     combined_frames, arraysize(combined_frames));
 
   MockRead reads[] = {
-    MockRead(ASYNC, combined_frames, combined_frames_len),
-    MockRead(ASYNC, 0, 0)  // EOF
+      MockRead(ASYNC, combined_frames, combined_frames_len, 1),
+      MockRead(ASYNC, 0, 2)  // EOF
   };
 
-  DelayedSocketData data(1, reads, arraysize(reads),
-                         writes, arraysize(writes));
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
 
   NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
                                      BoundNetLog(), GetParam(), NULL);
@@ -4009,7 +3916,7 @@
 
   scoped_ptr<SpdyFrame> req(
       spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
-  MockWrite writes[] = { CreateMockWrite(*req) };
+  MockWrite writes[] = {CreateMockWrite(*req, 0)};
 
   // All data frames in a single read.
   // NOTE: We don't FIN the stream.
@@ -4027,14 +3934,13 @@
                     combined_data_frames, arraysize(combined_data_frames));
   scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
   MockRead reads[] = {
-    CreateMockRead(*resp),
-    MockRead(ASYNC, ERR_IO_PENDING),  // Force a wait
-    MockRead(ASYNC, combined_data_frames, combined_data_frames_len),
-    MockRead(ASYNC, 0, 0)  // EOF
+      CreateMockRead(*resp, 1),
+      MockRead(ASYNC, ERR_IO_PENDING, 2),  // Force a wait
+      MockRead(ASYNC, combined_data_frames, combined_data_frames_len, 3),
+      MockRead(ASYNC, 0, 4)  // EOF
   };
 
-  DelayedSocketData data(1, reads, arraysize(reads),
-                         writes, arraysize(writes));
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
 
   NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
                                      BoundNetLog(), GetParam(), NULL);
@@ -4102,7 +4008,7 @@
       spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
   scoped_ptr<SpdyFrame> rst(
       spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
-  MockWrite writes[] = {CreateMockWrite(*req), CreateMockWrite(*rst)};
+  MockWrite writes[] = {CreateMockWrite(*req, 0), CreateMockWrite(*rst, 4)};
 
   // NOTE: We don't FIN the stream.
   scoped_ptr<SpdyFrame> data_frame(
@@ -4110,14 +4016,13 @@
 
   scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
   MockRead reads[] = {
-    CreateMockRead(*resp),
-    MockRead(ASYNC, ERR_IO_PENDING),  // Force a wait
-    CreateMockRead(*data_frame),
-    MockRead(ASYNC, 0, 0)  // EOF
+      CreateMockRead(*resp, 1),
+      MockRead(ASYNC, ERR_IO_PENDING, 2),  // Force a wait
+      CreateMockRead(*data_frame, 3),
+      MockRead(ASYNC, 0, 5)  // EOF
   };
 
-  DelayedSocketData data(1, reads, arraysize(reads),
-                         writes, arraysize(writes));
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
 
   NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
                                      BoundNetLog(), GetParam(), NULL);
@@ -4198,7 +4103,7 @@
   // Construct the request.
   scoped_ptr<SpdyFrame> req(
       spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
-  MockWrite writes[] = { CreateMockWrite(*req) };
+  MockWrite writes[] = {CreateMockWrite(*req, 0)};
 
   // Construct the reply.
   scoped_ptr<SpdyHeaderBlock> reply_headers(new SpdyHeaderBlock());
@@ -4231,14 +4136,13 @@
 
   scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
   MockRead reads[] = {
-    CreateMockRead(*reply),
-    CreateMockRead(*body),
-    CreateMockRead(*settings_frame),
-    MockRead(ASYNC, 0, 0)  // EOF
+      CreateMockRead(*reply, 1),
+      CreateMockRead(*body, 2),
+      CreateMockRead(*settings_frame, 3),
+      MockRead(ASYNC, 0, 4)  // EOF
   };
 
-  DelayedSocketData data(1, reads, arraysize(reads),
-                         writes, arraysize(writes));
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
   helper.AddData(&data);
   helper.RunDefaultTest();
   helper.VerifyDataConsumed();
@@ -4347,17 +4251,11 @@
   scoped_ptr<SpdyFrame> req(
       spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
 
-  std::vector<MockWrite> writes;
-  if ((GetParam().protocol >= kProtoSPDY4MinimumVersion) &&
-      (GetParam().protocol <= kProtoSPDY4MaximumVersion)) {
-    writes.push_back(
-        MockWrite(ASYNC,
-                  kHttp2ConnectionHeaderPrefix,
-                  kHttp2ConnectionHeaderPrefixSize));
-  }
-  writes.push_back(CreateMockWrite(*initial_settings_frame));
-  writes.push_back(CreateMockWrite(*settings_frame));
-  writes.push_back(CreateMockWrite(*req));
+  MockWrite writes[] = {
+      CreateMockWrite(*initial_settings_frame, 0),
+      CreateMockWrite(*settings_frame, 1),
+      CreateMockWrite(*req, 2),
+  };
 
   // Construct the reply.
   scoped_ptr<SpdyHeaderBlock> reply_headers(new SpdyHeaderBlock());
@@ -4368,13 +4266,12 @@
 
   scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
   MockRead reads[] = {
-    CreateMockRead(*reply),
-    CreateMockRead(*body),
-    MockRead(ASYNC, 0, 0)  // EOF
+      CreateMockRead(*reply, 3),
+      CreateMockRead(*body, 4),
+      MockRead(ASYNC, 0, 5)  // EOF
   };
 
-  DelayedSocketData data(2, reads, arraysize(reads),
-                         vector_as_array(&writes), writes.size());
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
   helper.AddData(&data);
   helper.RunDefaultTest();
   helper.VerifyDataConsumed();
@@ -4409,15 +4306,14 @@
 TEST_P(SpdyNetworkTransactionTest, GoAwayWithActiveStream) {
   scoped_ptr<SpdyFrame> req(
       spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
-  MockWrite writes[] = { CreateMockWrite(*req) };
+  MockWrite writes[] = {CreateMockWrite(*req, 0)};
 
   scoped_ptr<SpdyFrame> go_away(spdy_util_.ConstructSpdyGoAway());
   MockRead reads[] = {
-    CreateMockRead(*go_away),
+      CreateMockRead(*go_away, 1),
   };
 
-  DelayedSocketData data(1, reads, arraysize(reads),
-                         writes, arraysize(writes));
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
   NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
                                      BoundNetLog(), GetParam(), NULL);
   helper.AddData(&data);
@@ -4429,16 +4325,14 @@
 TEST_P(SpdyNetworkTransactionTest, CloseWithActiveStream) {
   scoped_ptr<SpdyFrame> req(
       spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
-  MockWrite writes[] = { CreateMockWrite(*req) };
+  MockWrite writes[] = {CreateMockWrite(*req, 0)};
 
   scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
   MockRead reads[] = {
-    CreateMockRead(*resp),
-    MockRead(SYNCHRONOUS, 0, 0)  // EOF
+      CreateMockRead(*resp, 1), MockRead(SYNCHRONOUS, 0, 2)  // EOF
   };
 
-  DelayedSocketData data(1, reads, arraysize(reads),
-                         writes, arraysize(writes));
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
   BoundNetLog log;
   NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
                                      log, GetParam(), NULL);
@@ -4476,9 +4370,9 @@
   scoped_ptr<SpdyFrame> go_away(spdy_util_.ConstructSpdyGoAway(
       0, GOAWAY_HTTP_1_1_REQUIRED, "Try again using HTTP/1.1 please."));
   MockRead reads[] = {
-      CreateMockRead(*go_away),
+      CreateMockRead(*go_away, 0),
   };
-  DelayedSocketData data(0, reads, arraysize(reads), nullptr, 0);
+  SequencedSocketData data(reads, arraysize(reads), nullptr, 0);
 
   helper.RunToCompletion(&data);
   TransactionHelperResult out = helper.output();
@@ -4512,12 +4406,12 @@
   scoped_ptr<SpdyHeaderBlock> headers(spdy_util_.ConstructGetHeaderBlock(url));
   scoped_ptr<SpdyFrame> req(
       spdy_util_.ConstructSpdySyn(1, *headers, LOWEST, false, true));
-  MockWrite writes0[] = {CreateMockWrite(*req)};
+  MockWrite writes0[] = {CreateMockWrite(*req, 0)};
   scoped_ptr<SpdyFrame> go_away(spdy_util_.ConstructSpdyGoAway(
       0, GOAWAY_HTTP_1_1_REQUIRED, "Try again using HTTP/1.1 please."));
-  MockRead reads0[] = {CreateMockRead(*go_away)};
-  DelayedSocketData data0(1, reads0, arraysize(reads0), writes0,
-                          arraysize(writes0));
+  MockRead reads0[] = {CreateMockRead(*go_away, 1)};
+  SequencedSocketData data0(reads0, arraysize(reads0), writes0,
+                            arraysize(writes0));
 
   scoped_ptr<SSLSocketDataProvider> ssl_provider0(
       new SSLSocketDataProvider(ASYNC, OK));
@@ -4531,16 +4425,16 @@
   helper.AddDataWithSSLSocketDataProvider(&data0, ssl_provider0.Pass());
 
   // Second socket: falling back to HTTP/1.1.
-  MockWrite writes1[] = {MockWrite(
-      "GET / HTTP/1.1\r\n"
-      "Host: www.example.org\r\n"
-      "Connection: keep-alive\r\n\r\n")};
-  MockRead reads1[] = {MockRead(
-      "HTTP/1.1 200 OK\r\n"
-      "Content-Length: 5\r\n\r\n"
-      "hello")};
-  DelayedSocketData data1(1, reads1, arraysize(reads1), writes1,
-                          arraysize(writes1));
+  MockWrite writes1[] = {MockWrite(ASYNC, 0,
+                                   "GET / HTTP/1.1\r\n"
+                                   "Host: www.example.org\r\n"
+                                   "Connection: keep-alive\r\n\r\n")};
+  MockRead reads1[] = {MockRead(ASYNC, 1,
+                                "HTTP/1.1 200 OK\r\n"
+                                "Content-Length: 5\r\n\r\n"
+                                "hello")};
+  SequencedSocketData data1(reads1, arraysize(reads1), writes1,
+                            arraysize(writes1));
 
   scoped_ptr<SSLSocketDataProvider> ssl_provider1(
       new SSLSocketDataProvider(ASYNC, OK));
@@ -4603,12 +4497,12 @@
   // First socket: HTTP/2 CONNECT rejected with HTTP_1_1_REQUIRED.
   scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyConnect(
       nullptr, 0, 1, LOWEST, HostPortPair("www.example.org", 443)));
-  MockWrite writes0[] = {CreateMockWrite(*req)};
+  MockWrite writes0[] = {CreateMockWrite(*req, 0)};
   scoped_ptr<SpdyFrame> go_away(spdy_util_.ConstructSpdyGoAway(
       0, GOAWAY_HTTP_1_1_REQUIRED, "Try again using HTTP/1.1 please."));
-  MockRead reads0[] = {CreateMockRead(*go_away)};
-  DelayedSocketData data0(1, reads0, arraysize(reads0), writes0,
-                          arraysize(writes0));
+  MockRead reads0[] = {CreateMockRead(*go_away, 1)};
+  SequencedSocketData data0(reads0, arraysize(reads0), writes0,
+                            arraysize(writes0));
 
   scoped_ptr<SSLSocketDataProvider> ssl_provider0(
       new SSLSocketDataProvider(ASYNC, OK));
@@ -4623,25 +4517,25 @@
 
   // Second socket: retry using HTTP/1.1.
   MockWrite writes1[] = {
-      MockWrite(ASYNC, 1,
+      MockWrite(ASYNC, 0,
                 "CONNECT www.example.org:443 HTTP/1.1\r\n"
                 "Host: www.example.org\r\n"
                 "Proxy-Connection: keep-alive\r\n\r\n"),
-      MockWrite(ASYNC, 3,
+      MockWrite(ASYNC, 2,
                 "GET / HTTP/1.1\r\n"
                 "Host: www.example.org\r\n"
                 "Connection: keep-alive\r\n\r\n"),
   };
 
   MockRead reads1[] = {
-      MockRead(ASYNC, 2, "HTTP/1.1 200 OK\r\n\r\n"),
-      MockRead(ASYNC, 4,
+      MockRead(ASYNC, 1, "HTTP/1.1 200 OK\r\n\r\n"),
+      MockRead(ASYNC, 3,
                "HTTP/1.1 200 OK\r\n"
                "Content-Length: 5\r\n\r\n"
                "hello"),
   };
-  DelayedSocketData data1(1, reads1, arraysize(reads1), writes1,
-                          arraysize(writes1));
+  SequencedSocketData data1(reads1, arraysize(reads1), writes1,
+                            arraysize(writes1));
 
   scoped_ptr<SSLSocketDataProvider> ssl_provider1(
       new SSLSocketDataProvider(ASYNC, OK));
@@ -4715,7 +4609,7 @@
       CreateMockRead(*body.get(), 4),
       MockRead(ASYNC, 0, 0, 5),
   };
-  scoped_ptr<OrderedSocketData> data(new OrderedSocketData(
+  scoped_ptr<SequencedSocketData> data(new SequencedSocketData(
       reads, arraysize(reads), writes, arraysize(writes)));
 
   helper.AddData(data.get());
@@ -4765,19 +4659,17 @@
   scoped_ptr<SpdyFrame> req(
       spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
   MockWrite writes[] = {
-    CreateMockWrite(*req, 1),
+      CreateMockWrite(*req, 0),
   };
 
   scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
   scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
   MockRead reads[] = {
-    CreateMockRead(*resp, 2),
-    CreateMockRead(*body, 3),
-    MockRead(ASYNC, ERR_IO_PENDING, 4),  // Force a pause
-    MockRead(ASYNC, 0, 5)  // EOF
+      CreateMockRead(*resp, 1),
+      CreateMockRead(*body, 2),
+      MockRead(SYNCHRONOUS, ERR_IO_PENDING, 3),  // Force a pause
   };
-  OrderedSocketData data(reads, arraysize(reads),
-                         writes, arraysize(writes));
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
   helper.AddData(&data);
   HttpNetworkTransaction* trans = helper.trans();
 
@@ -4832,7 +4724,7 @@
       MockRead(ASYNC, 0, 5)  // EOF
   };
 
-  scoped_ptr<OrderedSocketData> data_proxy(new OrderedSocketData(
+  scoped_ptr<SequencedSocketData> data_proxy(new SequencedSocketData(
       reads2, arraysize(reads2), writes2, arraysize(writes2)));
 
   // Create another request to www.example.org, but this time through a proxy.
@@ -4872,7 +4764,6 @@
   ASSERT_EQ(OK, ReadTransaction(trans_proxy, &response_data));
   EXPECT_EQ("hello!", response_data);
 
-  data.CompleteRead();
   helper_proxy.VerifyDataConsumed();
 }
 
@@ -4884,33 +4775,41 @@
   scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
   scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
   MockRead reads[] = {
-    CreateMockRead(*resp),
-    CreateMockRead(*body),
-    MockRead(ASYNC, ERR_IO_PENDING),
-    MockRead(ASYNC, ERR_CONNECTION_RESET),
+      CreateMockRead(*resp, 1),
+      CreateMockRead(*body, 2),
+      MockRead(ASYNC, ERR_IO_PENDING, 3),
+      MockRead(ASYNC, ERR_CONNECTION_RESET, 4),
   };
 
   MockRead reads2[] = {
-    CreateMockRead(*resp),
-    CreateMockRead(*body),
-    MockRead(ASYNC, 0, 0)  // EOF
+      CreateMockRead(*resp, 1),
+      CreateMockRead(*body, 2),
+      MockRead(ASYNC, 0, 3)  // EOF
   };
 
+  scoped_ptr<SpdyFrame> req(
+      spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
+  scoped_ptr<SpdyFrame> req3(
+      spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, LOWEST, true));
+  MockWrite writes1[] = {CreateMockWrite(*req, 0), CreateMockWrite(*req3, 5)};
+  MockWrite writes2[] = {CreateMockWrite(*req, 0)};
+
   // This test has a couple of variants.
   enum {
     // Induce the RST while waiting for our transaction to send.
-    VARIANT_RST_DURING_SEND_COMPLETION,
+    VARIANT_RST_DURING_SEND_COMPLETION = 0,
     // Induce the RST while waiting for our transaction to read.
     // In this case, the send completed - everything copied into the SNDBUF.
-    VARIANT_RST_DURING_READ_COMPLETION
+    VARIANT_RST_DURING_READ_COMPLETION = 1
   };
 
   for (int variant = VARIANT_RST_DURING_SEND_COMPLETION;
        variant <= VARIANT_RST_DURING_READ_COMPLETION;
        ++variant) {
-    DelayedSocketData data1(1, reads, arraysize(reads), NULL, 0);
+    SequencedSocketData data1(reads, arraysize(reads), writes1, 1 + variant);
 
-    DelayedSocketData data2(1, reads2, arraysize(reads2), NULL, 0);
+    SequencedSocketData data2(reads2, arraysize(reads2), writes2,
+                              arraysize(writes2));
 
     NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
                                        BoundNetLog(), GetParam(), NULL);
@@ -4935,9 +4834,7 @@
         }
 
         // Now schedule the ERR_CONNECTION_RESET.
-        EXPECT_EQ(3u, data1.read_index());
         data1.CompleteRead();
-        EXPECT_EQ(4u, data1.read_index());
       }
       rv = callback.WaitForResult();
       EXPECT_EQ(OK, rv);
@@ -4951,9 +4848,11 @@
       EXPECT_EQ(OK, rv);
       EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
       EXPECT_EQ("hello!", response_data);
+      base::RunLoop().RunUntilIdle();
     }
 
     helper.VerifyDataConsumed();
+    base::RunLoop().RunUntilIdle();
   }
 }
 
@@ -4962,18 +4861,18 @@
   HttpStreamFactory::set_spdy_enabled(true);
   scoped_ptr<SpdyFrame> req(
       spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
-  MockWrite spdy_writes[] = { CreateMockWrite(*req) };
+  MockWrite spdy_writes[] = {CreateMockWrite(*req, 0)};
 
   scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
   scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
   MockRead spdy_reads[] = {
-    CreateMockRead(*resp),
-    CreateMockRead(*body),
-    MockRead(ASYNC, 0, 0)  // EOF
+      CreateMockRead(*resp, 1),
+      CreateMockRead(*body, 2),
+      MockRead(ASYNC, 0, 3)  // EOF
   };
 
-  DelayedSocketData data(1, spdy_reads, arraysize(spdy_reads),
-                         spdy_writes, arraysize(spdy_writes));
+  SequencedSocketData data(spdy_reads, arraysize(spdy_reads), spdy_writes,
+                           arraysize(spdy_writes));
   NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
                                      BoundNetLog(), GetParam(), NULL);
   helper.RunToCompletion(&data);
@@ -4983,12 +4882,20 @@
   EXPECT_EQ("hello!", out.response_data);
 
   HttpStreamFactory::set_spdy_enabled(false);
-  MockRead http_reads[] = {
-    MockRead("HTTP/1.1 200 OK\r\n\r\n"),
-    MockRead("hello from http"),
-    MockRead(SYNCHRONOUS, OK),
+  MockWrite http_writes[] = {
+      MockWrite(SYNCHRONOUS, 0,
+                "GET / HTTP/1.1\r\n"
+                "Host: www.example.org\r\n"
+                "Connection: keep-alive\r\n\r\n"),
   };
-  DelayedSocketData data2(1, http_reads, arraysize(http_reads), NULL, 0);
+
+  MockRead http_reads[] = {
+      MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 OK\r\n\r\n"),
+      MockRead(SYNCHRONOUS, 2, "hello from http"),
+      MockRead(SYNCHRONOUS, OK, 3),
+  };
+  SequencedSocketData data2(http_reads, arraysize(http_reads), http_writes,
+                            arraysize(http_writes));
   NormalSpdyTransactionHelper helper2(CreateGetRequest(), DEFAULT_PRIORITY,
                                      BoundNetLog(), GetParam(), NULL);
   helper2.SetSpdyDisabled();
@@ -5017,8 +4924,7 @@
                                   arraysize(kExtraAuthorizationHeaders) / 2,
                                   false, 3, LOWEST, true));
   MockWrite spdy_writes[] = {
-    CreateMockWrite(*req_get, 1),
-    CreateMockWrite(*req_get_authorization, 4),
+      CreateMockWrite(*req_get, 0), CreateMockWrite(*req_get_authorization, 3),
   };
 
   // The first response is a 401 authentication challenge, and the second
@@ -5040,15 +4946,15 @@
       spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
   scoped_ptr<SpdyFrame> body_data(spdy_util_.ConstructSpdyBodyFrame(3, true));
   MockRead spdy_reads[] = {
-    CreateMockRead(*resp_authentication, 2),
-    CreateMockRead(*body_authentication, 3),
-    CreateMockRead(*resp_data, 5),
-    CreateMockRead(*body_data, 6),
-    MockRead(ASYNC, 0, 7),
+      CreateMockRead(*resp_authentication, 1),
+      CreateMockRead(*body_authentication, 2),
+      CreateMockRead(*resp_data, 4),
+      CreateMockRead(*body_data, 5),
+      MockRead(ASYNC, 0, 6),
   };
 
-  OrderedSocketData data(spdy_reads, arraysize(spdy_reads),
-                         spdy_writes, arraysize(spdy_writes));
+  SequencedSocketData data(spdy_reads, arraysize(spdy_reads), spdy_writes,
+                           arraysize(spdy_writes));
   HttpRequestInfo request(CreateGetRequest());
   BoundNetLog net_log;
   NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY,
@@ -5099,7 +5005,7 @@
   scoped_ptr<SpdyFrame> stream1_body(
       spdy_util_.ConstructSpdyBodyFrame(1, true));
   MockWrite writes[] = {
-    CreateMockWrite(*stream1_syn, 1),
+      CreateMockWrite(*stream1_syn, 0),
   };
 
   scoped_ptr<SpdyHeaderBlock> initial_headers(new SpdyHeaderBlock());
@@ -5128,19 +5034,18 @@
       spdy_util_.ConstructSpdyBodyFrame(
           2, kPushedData, strlen(kPushedData), true));
   MockRead reads[] = {
-    CreateMockRead(*stream1_reply, 2),
-    CreateMockRead(*stream2_syn, 3),
-    CreateMockRead(*stream2_headers, 4),
-    CreateMockRead(*stream1_body, 5, SYNCHRONOUS),
-    CreateMockRead(*stream2_body, 5),
-    MockRead(ASYNC, ERR_IO_PENDING, 7),  // Force a pause
+      CreateMockRead(*stream1_reply, 1),
+      CreateMockRead(*stream2_syn, 2),
+      CreateMockRead(*stream2_headers, 3),
+      CreateMockRead(*stream1_body, 4, SYNCHRONOUS),
+      CreateMockRead(*stream2_body, 5),
+      MockRead(SYNCHRONOUS, ERR_IO_PENDING, 6),  // Force a pause
   };
 
   HttpResponseInfo response;
   HttpResponseInfo response2;
   std::string expected_push_result("pushed");
-  OrderedSocketData data(reads, arraysize(reads),
-                         writes, arraysize(writes));
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
   RunServerPushTest(&data,
                     &response,
                     &response2,
@@ -5526,7 +5431,7 @@
   scoped_ptr<SpdyFrame> rst(
       spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR));
   MockWrite writes[] = {
-      CreateMockWrite(*req), CreateMockWrite(*rst),
+      CreateMockWrite(*req, 0), CreateMockWrite(*rst, 4),
   };
 
   scoped_ptr<SpdyFrame> stream1_reply(
@@ -5545,14 +5450,13 @@
   scoped_ptr<SpdyFrame> stream1_body(
       spdy_util_.ConstructSpdyBodyFrame(1, true));
   MockRead reads[] = {
-    CreateMockRead(*stream1_reply),
-    CreateMockRead(*stream1_headers),
-    CreateMockRead(*stream1_body),
-    MockRead(ASYNC, 0, 0)  // EOF
+      CreateMockRead(*stream1_reply, 1),
+      CreateMockRead(*stream1_headers, 2),
+      CreateMockRead(*stream1_body, 3),
+      MockRead(ASYNC, 0, 5)  // EOF
   };
 
-  DelayedSocketData data(1, reads, arraysize(reads),
-                         writes, arraysize(writes));
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
   NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
                                      BoundNetLog(), GetParam(), NULL);
   helper.RunToCompletion(&data);
@@ -5566,8 +5470,7 @@
   scoped_ptr<SpdyFrame> rst(
       spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR));
   MockWrite writes[] = {
-    CreateMockWrite(*req),
-    CreateMockWrite(*rst),
+      CreateMockWrite(*req, 0), CreateMockWrite(*rst, 4),
   };
 
   scoped_ptr<SpdyFrame> stream1_reply(
@@ -5588,15 +5491,14 @@
   scoped_ptr<SpdyFrame> stream1_body2(
       spdy_util_.ConstructSpdyBodyFrame(1, true));
   MockRead reads[] = {
-    CreateMockRead(*stream1_reply),
-    CreateMockRead(*stream1_body),
-    CreateMockRead(*stream1_headers),
-    CreateMockRead(*stream1_body2),
-    MockRead(ASYNC, 0, 0)  // EOF
+      CreateMockRead(*stream1_reply, 1),
+      CreateMockRead(*stream1_body, 2),
+      CreateMockRead(*stream1_headers, 3),
+      CreateMockRead(*stream1_body2, 5),
+      MockRead(ASYNC, 0, 6)  // EOF
   };
 
-  DelayedSocketData data(1, reads, arraysize(reads),
-                         writes, arraysize(writes));
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
   NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
                                      BoundNetLog(), GetParam(), NULL);
   helper.RunToCompletion(&data);
@@ -5644,8 +5546,7 @@
     scoped_ptr<SpdyFrame> push_rst(
         spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_REFUSED_STREAM));
     MockWrite writes[] = {
-      CreateMockWrite(*stream1_syn, 1),
-      CreateMockWrite(*push_rst, 4),
+        CreateMockWrite(*stream1_syn, 0), CreateMockWrite(*push_rst, 3),
     };
 
     scoped_ptr<SpdyFrame>
@@ -5664,16 +5565,16 @@
         spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_CANCEL));
 
     MockRead reads[] = {
-      CreateMockRead(*stream1_reply, 2),
-      CreateMockRead(*stream2_syn, 3),
-      CreateMockRead(*stream1_body, 5, SYNCHRONOUS),
-      CreateMockRead(*stream2_body, 6),
-      MockRead(ASYNC, ERR_IO_PENDING, 7),  // Force a pause
+        CreateMockRead(*stream1_reply, 1),
+        CreateMockRead(*stream2_syn, 2),
+        CreateMockRead(*stream1_body, 4),
+        CreateMockRead(*stream2_body, 5),
+        MockRead(SYNCHRONOUS, ERR_IO_PENDING, 6),  // Force a pause
     };
 
     HttpResponseInfo response;
-    OrderedSocketData data(reads, arraysize(reads),
-                           writes, arraysize(writes));
+    SequencedSocketData data(reads, arraysize(reads), writes,
+                             arraysize(writes));
 
     HttpRequestInfo request;
     request.method = "GET";
@@ -5727,8 +5628,7 @@
   scoped_ptr<SpdyFrame> req2(
       spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, LOWEST, true));
   MockWrite writes[] = {
-    CreateMockWrite(*req, 1),
-    CreateMockWrite(*req2, 3),
+      CreateMockWrite(*req, 0), CreateMockWrite(*req2, 2),
   };
 
   scoped_ptr<SpdyFrame> refused(
@@ -5736,14 +5636,13 @@
   scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
   scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(3, true));
   MockRead reads[] = {
-    CreateMockRead(*refused, 2),
-    CreateMockRead(*resp, 4),
-    CreateMockRead(*body, 5),
-    MockRead(ASYNC, 0, 6)  // EOF
+      CreateMockRead(*refused, 1),
+      CreateMockRead(*resp, 3),
+      CreateMockRead(*body, 4),
+      MockRead(ASYNC, 0, 5)  // EOF
   };
 
-  OrderedSocketData data(reads, arraysize(reads),
-                         writes, arraysize(writes));
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
   NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
                                      BoundNetLog(), GetParam(), NULL);
 
@@ -5761,14 +5660,8 @@
   EXPECT_EQ(OK, rv);
 
   // Verify that we consumed all test data.
-  EXPECT_TRUE(data.at_read_eof()) << "Read count: "
-                                   << data.read_count()
-                                   << " Read index: "
-                                   << data.read_index();
-  EXPECT_TRUE(data.at_write_eof()) << "Write count: "
-                                    << data.write_count()
-                                    << " Write index: "
-                                    << data.write_index();
+  EXPECT_TRUE(data.AllReadDataConsumed());
+  EXPECT_TRUE(data.AllWriteDataConsumed());
 
   // Verify the SYN_REPLY.
   HttpResponseInfo response = *trans->GetResponseInfo();
@@ -6029,16 +5922,14 @@
     writes.push_back(MockWrite(ASYNC, kHttp2ConnectionHeaderPrefix,
                                kHttp2ConnectionHeaderPrefixSize, 0));
   }
-  writes.push_back(CreateMockWrite(*initial_settings_frame));
-  writes.push_back(CreateMockWrite(*initial_window_update));
-  writes.push_back(CreateMockWrite(*req));
-  writes.push_back(CreateMockWrite(*session_window_update));
-  writes.push_back(CreateMockWrite(*stream_window_update));
+  writes.push_back(CreateMockWrite(*initial_settings_frame, writes.size()));
+  writes.push_back(CreateMockWrite(*initial_window_update, writes.size()));
+  writes.push_back(CreateMockWrite(*req, writes.size()));
 
   std::vector<MockRead> reads;
   scoped_ptr<SpdyFrame> resp(
       spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
-  reads.push_back(CreateMockRead(*resp));
+  reads.push_back(CreateMockRead(*resp, writes.size() + reads.size()));
 
   ScopedVector<SpdyFrame> body_frames;
   const std::string body_data(kChunkSize, 'x');
@@ -6046,13 +5937,20 @@
     size_t frame_size = std::min(remaining, body_data.size());
     body_frames.push_back(spdy_util_.ConstructSpdyBodyFrame(
         1, body_data.data(), frame_size, false));
-    reads.push_back(CreateMockRead(*body_frames.back()));
+    reads.push_back(
+        CreateMockRead(*body_frames.back(), writes.size() + reads.size()));
     remaining -= frame_size;
   }
-  reads.push_back(MockRead(ASYNC, ERR_IO_PENDING, 0));  // Yield.
+  reads.push_back(
+      MockRead(ASYNC, ERR_IO_PENDING, writes.size() + reads.size()));  // Yield.
 
-  DelayedSocketData data(2, vector_as_array(&reads), reads.size(),
-                         vector_as_array(&writes), writes.size());
+  writes.push_back(
+      CreateMockWrite(*session_window_update, writes.size() + reads.size()));
+  writes.push_back(
+      CreateMockWrite(*stream_window_update, writes.size() + reads.size()));
+
+  SequencedSocketData data(vector_as_array(&reads), reads.size(),
+                           vector_as_array(&writes), writes.size());
 
   NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
                                      BoundNetLog(), GetParam(), NULL);
@@ -6174,9 +6072,9 @@
 // This test constructs a POST request followed by enough data frames
 // containing 'a' that would make the window size 0, followed by another
 // data frame containing default content (which is "hello!") and this frame
-// also contains a FIN flag.  DelayedSocketData is used to enforce all
-// writes go through before a read could happen.  However, the last frame
-// ("hello!")  is not supposed to go through since by the time its turn
+// also contains a FIN flag.  SequencedSocketData is used to enforce all
+// writes, save the last, go through before a read could happen.  The last frame
+// ("hello!") is not permitted to go through since by the time its turn
 // arrives, window size is 0.  At this point MessageLoop::Run() called via
 // callback would block.  Therefore we call MessageLoop::RunUntilIdle()
 // which returns after performing all possible writes.  We use DCHECKS to
@@ -6218,11 +6116,13 @@
   // Fill in mock writes.
   scoped_ptr<MockWrite[]> writes(new MockWrite[num_writes]);
   size_t i = 0;
-  writes[i] = CreateMockWrite(*req);
+  writes[i] = CreateMockWrite(*req, i);
   for (i = 1; i < num_writes - 2; i++)
-    writes[i] = CreateMockWrite(*body1);
-  writes[i++] = CreateMockWrite(*body2);
-  writes[i] = CreateMockWrite(*body3);
+    writes[i] = CreateMockWrite(*body1, i);
+  writes[i] = CreateMockWrite(*body2, i);
+  // The last write must not be attempted until after the WINDOW_UPDATES
+  // have been received.
+  writes[i + 1] = CreateMockWrite(*body3, i + 4, SYNCHRONOUS);
 
   // Construct read frame, give enough space to upload the rest of the
   // data.
@@ -6232,25 +6132,17 @@
       spdy_util_.ConstructSpdyWindowUpdate(1, kUploadDataSize));
   scoped_ptr<SpdyFrame> reply(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
   MockRead reads[] = {
-    CreateMockRead(*session_window_update),
-    CreateMockRead(*session_window_update),
-    CreateMockRead(*window_update),
-    CreateMockRead(*window_update),
-    CreateMockRead(*reply),
-    CreateMockRead(*body2),
-    CreateMockRead(*body3),
-    MockRead(ASYNC, 0, 0)  // EOF
+      MockRead(ASYNC, ERR_IO_PENDING, i + 1),  // Force a pause
+      CreateMockRead(*session_window_update, i + 2),
+      CreateMockRead(*window_update, i + 3),
+      // Now the last write will occur.
+      CreateMockRead(*reply, i + 5),
+      CreateMockRead(*body2, i + 6),
+      CreateMockRead(*body3, i + 7),
+      MockRead(ASYNC, 0, i + 8)  // EOF
   };
 
-  // Skip the session window updates unless we're using SPDY/3.1 and
-  // above.
-  size_t read_offset = (GetParam().protocol >= kProtoSPDY31) ? 0 : 2;
-  size_t num_reads = arraysize(reads) - read_offset;
-
-  // Force all writes to happen before any read, last write will not
-  // actually queue a frame, due to window size being 0.
-  DelayedSocketData data(num_writes, reads + read_offset, num_reads,
-                         writes.get(), num_writes);
+  SequencedSocketData data(reads, arraysize(reads), writes.get(), num_writes);
 
   ScopedVector<UploadElementReader> element_readers;
   std::string upload_data_string(initial_window_size, 'a');
@@ -6288,7 +6180,7 @@
   // since we're send-stalled.
   EXPECT_TRUE(stream->stream()->send_stalled_by_flow_control());
 
-  data.ForceNextRead();   // Read in WINDOW_UPDATE frame.
+  data.CompleteRead();  // Read in WINDOW_UPDATE frame.
   rv = callback.WaitForResult();
   helper.VerifyDataConsumed();
 }
@@ -6551,7 +6443,7 @@
       CreateMockWrite(*req, 0), CreateMockWrite(*goaway, 2),
   };
 
-  DelayedSocketData data(1, reads, arraysize(reads), writes, arraysize(writes));
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
   NormalSpdyTransactionHelper helper(
       CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL);
   helper.RunToCompletion(&data);
@@ -6585,7 +6477,7 @@
       CreateMockWrite(*req, 0), CreateMockWrite(*goaway, 3),
   };
 
-  DelayedSocketData data(1, reads, arraysize(reads), writes, arraysize(writes));
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
   NormalSpdyTransactionHelper helper(
       CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL);
   helper.RunToCompletion(&data);
@@ -6600,17 +6492,18 @@
     // Construct the request.
     scoped_ptr<SpdyFrame> req(
         spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
-    MockWrite writes[] = {CreateMockWrite(*req)};
+    MockWrite writes[] = {CreateMockWrite(*req, 0)};
 
     scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
     scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
     MockRead reads[] = {
-        CreateMockRead(*resp), CreateMockRead(*body),
-        MockRead(ASYNC, 0, 0)  // EOF
+        CreateMockRead(*resp, 1),
+        CreateMockRead(*body, 2),
+        MockRead(ASYNC, 0, 3)  // EOF
     };
 
-    DelayedSocketData data(
-        1, reads, arraysize(reads), writes, arraysize(writes));
+    SequencedSocketData data(reads, arraysize(reads), writes,
+                             arraysize(writes));
     HttpRequestInfo request;
     request.method = "GET";
     request.url = GURL("https://www.example.org/");
@@ -6662,7 +6555,7 @@
         spdy_util_.ConstructSpdyGoAway(0, GOAWAY_INADEQUATE_SECURITY, ""));
     MockWrite writes[] = {CreateMockWrite(*goaway)};
 
-    DelayedSocketData data(1, NULL, 0, writes, arraysize(writes));
+    StaticSocketDataProvider data(NULL, 0, writes, arraysize(writes));
     HttpRequestInfo request;
     request.method = "GET";
     request.url = GURL("https://www.example.org/");
diff --git a/net/spdy/spdy_protocol.h b/net/spdy/spdy_protocol.h
index 1837feb2..f4d2222 100644
--- a/net/spdy/spdy_protocol.h
+++ b/net/spdy/spdy_protocol.h
@@ -999,10 +999,10 @@
         parent_stream_id_(0),
         weight_(1),
         exclusive_(false) {}
-  explicit SpdyPriorityIR(SpdyStreamId stream_id,
-                          SpdyStreamId parent_stream_id,
-                          uint8 weight,
-                          bool exclusive)
+  SpdyPriorityIR(SpdyStreamId stream_id,
+                 SpdyStreamId parent_stream_id,
+                 uint8 weight,
+                 bool exclusive)
       : SpdyFrameWithStreamIdIR(stream_id),
         parent_stream_id_(parent_stream_id),
         weight_(weight),
diff --git a/net/spdy/write_blocked_list.h b/net/spdy/write_blocked_list.h
index c6d60b3..bb3bcfff 100644
--- a/net/spdy/write_blocked_list.h
+++ b/net/spdy/write_blocked_list.h
@@ -28,8 +28,7 @@
   typedef std::deque<IdType> BlockedList;
   typedef typename BlockedList::iterator iterator;
 
-  explicit WriteBlockedList(bool use_stream_to_priority_map)
-      : use_stream_to_priority_(use_stream_to_priority_map) {}
+  WriteBlockedList() {}
 
   static SpdyPriority ClampPriority(SpdyPriority priority) {
     if (priority < kHighestPriority) {
@@ -58,9 +57,7 @@
     DCHECK(!write_blocked_lists_[priority].empty());
     IdType stream_id = write_blocked_lists_[priority].front();
     write_blocked_lists_[priority].pop_front();
-    if (use_stream_to_priority_) {
-      stream_to_priority_.erase(stream_id);
-    }
+    stream_to_priority_.erase(stream_id);
     return stream_id;
   }
 
@@ -88,44 +85,38 @@
     DVLOG(2) << "Adding stream " << stream_id << " at priority "
              << static_cast<int>(priority);
     bool should_insert_stream = true;
-    if (use_stream_to_priority_) {
-      typename StreamToPriorityMap::iterator iter =
-          stream_to_priority_.find(stream_id);
-      if (iter != stream_to_priority_.end()) {
-        DVLOG(1) << "Stream " << stream_id << " already in write blocked list.";
-        if (iter->second == priority) {
-          // The stream is already in the write blocked list for the priority.
-          should_insert_stream = false;
-        } else {
-          // The stream is in a write blocked list for a different priority.
-          bool removed =
-              RemoveStreamFromWriteBlockedList(stream_id, iter->second);
-          DCHECK(removed);
-        }
+    typename StreamToPriorityMap::iterator iter =
+        stream_to_priority_.find(stream_id);
+    if (iter != stream_to_priority_.end()) {
+      DVLOG(1) << "Stream " << stream_id << " already in write blocked list.";
+      if (iter->second == priority) {
+        // The stream is already in the write blocked list for the priority.
+        should_insert_stream = false;
+      } else {
+        // The stream is in a write blocked list for a different priority.
+        bool removed =
+            RemoveStreamFromWriteBlockedList(stream_id, iter->second);
+        DCHECK(removed);
       }
-      if (should_insert_stream) {
-        stream_to_priority_[stream_id] = priority;
-        write_blocked_lists_[priority].push_back(stream_id);
-      }
-    } else {
+    }
+    if (should_insert_stream) {
+      stream_to_priority_[stream_id] = priority;
       write_blocked_lists_[priority].push_back(stream_id);
     }
   }
 
   bool RemoveStreamFromWriteBlockedList(IdType stream_id,
                                         SpdyPriority priority) {
-    if (use_stream_to_priority_) {
-      typename StreamToPriorityMap::iterator iter =
-          stream_to_priority_.find(stream_id);
-      if (iter == stream_to_priority_.end()) {
-        // The stream is not present in the write blocked list.
-        return false;
-      } else if (iter->second == priority) {
-        stream_to_priority_.erase(iter);
-      } else {
-        // The stream is not present at the specified priority level.
-        return false;
-      }
+    typename StreamToPriorityMap::iterator iter =
+        stream_to_priority_.find(stream_id);
+    if (iter == stream_to_priority_.end()) {
+      // The stream is not present in the write blocked list.
+      return false;
+    } else if (iter->second == priority) {
+      stream_to_priority_.erase(iter);
+    } else {
+      // The stream is not present at the specified priority level.
+      return false;
     }
     // We shouldn't really add a stream_id to a list multiple times,
     // but under some conditions it does happen. Doing a check in PushBack
@@ -161,8 +152,6 @@
     return num_blocked_streams;
   }
 
-  bool avoids_inserting_duplicates() const { return use_stream_to_priority_; }
-
  private:
   friend class net::test::WriteBlockedListPeer;
 
@@ -170,7 +159,6 @@
 
   BlockedList write_blocked_lists_[kLowestPriority + 1];
   StreamToPriorityMap stream_to_priority_;
-  bool use_stream_to_priority_;
 };
 
 }  // namespace net
diff --git a/net/spdy/write_blocked_list_test.cc b/net/spdy/write_blocked_list_test.cc
index 50c3f35..20a1b7e4 100644
--- a/net/spdy/write_blocked_list_test.cc
+++ b/net/spdy/write_blocked_list_test.cc
@@ -23,14 +23,12 @@
 
 typedef WriteBlockedList<int> IntWriteBlockedList;
 
-class WriteBlockedListTest : public ::testing::TestWithParam<bool> {
+class WriteBlockedListTest : public ::testing::Test {
  public:
-  WriteBlockedListTest() : list(GetParam()) {}
-
   IntWriteBlockedList list;
 };
 
-TEST_P(WriteBlockedListTest, GetHighestPriority) {
+TEST_F(WriteBlockedListTest, GetHighestPriority) {
   EXPECT_FALSE(list.HasWriteBlockedStreams());
   list.PushBack(1, 1);
   EXPECT_TRUE(list.HasWriteBlockedStreams());
@@ -40,7 +38,7 @@
   EXPECT_EQ(0, list.GetHighestPriorityWriteBlockedList());
 }
 
-TEST_P(WriteBlockedListTest, HasWriteBlockedStreamsOfGreaterThanPriority) {
+TEST_F(WriteBlockedListTest, HasWriteBlockedStreamsOfGreaterThanPriority) {
   list.PushBack(1, 4);
   EXPECT_TRUE(list.HasWriteBlockedStreamsGreaterThanPriority(5));
   EXPECT_FALSE(list.HasWriteBlockedStreamsGreaterThanPriority(4));
@@ -49,7 +47,7 @@
   EXPECT_FALSE(list.HasWriteBlockedStreamsGreaterThanPriority(2));
 }
 
-TEST_P(WriteBlockedListTest, RemoveStreamFromWriteBlockedList) {
+TEST_F(WriteBlockedListTest, RemoveStreamFromWriteBlockedList) {
   list.PushBack(1, 4);
   EXPECT_TRUE(list.HasWriteBlockedStreams());
 
@@ -66,100 +64,52 @@
   EXPECT_TRUE(list.HasWriteBlockedStreams());
 }
 
-TEST_P(WriteBlockedListTest, PopFront) {
+TEST_F(WriteBlockedListTest, PopFront) {
   list.PushBack(1, 4);
   EXPECT_EQ(1u, list.NumBlockedStreams());
   list.PushBack(2, 4);
   list.PushBack(1, 4);
   list.PushBack(3, 4);
-  if (GetParam()) {
-    EXPECT_EQ(3u, list.NumBlockedStreams());
-  } else {
-    EXPECT_EQ(4u, list.NumBlockedStreams());
-  }
+  EXPECT_EQ(3u, list.NumBlockedStreams());
 
   EXPECT_EQ(1, list.PopFront(4));
   EXPECT_EQ(2, list.PopFront(4));
-  EXPECT_EQ(1, list.PopFront(4));
-  if (!GetParam()) {
-    EXPECT_EQ(1, list.PopFront(4));
-  }
   EXPECT_EQ(1u, list.NumBlockedStreams());
   EXPECT_EQ(3, list.PopFront(4));
 }
 
-TEST_P(WriteBlockedListTest, UpdateStreamPriorityInWriteBlockedList) {
-  if (GetParam()) {
-    list.PushBack(1, 1);
-    list.PushBack(2, 2);
-    list.PushBack(3, 3);
-    list.PushBack(1, 3);  // Re-prioritizes stream 1 at priority 3.
-    list.PushBack(1, 3);  // No effect.
-    EXPECT_EQ(3u, list.NumBlockedStreams());
-    EXPECT_EQ(0u, WriteBlockedListPeer::GetWriteBlockedList(1, &list)->size());
-    EXPECT_EQ(1u, WriteBlockedListPeer::GetWriteBlockedList(2, &list)->size());
-    EXPECT_EQ(2u, WriteBlockedListPeer::GetWriteBlockedList(3, &list)->size());
+TEST_F(WriteBlockedListTest, UpdateStreamPriorityInWriteBlockedList) {
+  list.PushBack(1, 1);
+  list.PushBack(2, 2);
+  list.PushBack(3, 3);
+  list.PushBack(1, 3);  // Re-prioritizes stream 1 at priority 3.
+  list.PushBack(1, 3);  // No effect.
+  EXPECT_EQ(3u, list.NumBlockedStreams());
+  EXPECT_EQ(0u, WriteBlockedListPeer::GetWriteBlockedList(1, &list)->size());
+  EXPECT_EQ(1u, WriteBlockedListPeer::GetWriteBlockedList(2, &list)->size());
+  EXPECT_EQ(2u, WriteBlockedListPeer::GetWriteBlockedList(3, &list)->size());
 
-    list.UpdateStreamPriorityInWriteBlockedList(1, 3, 2);
-    EXPECT_EQ(0u, WriteBlockedListPeer::GetWriteBlockedList(1, &list)->size());
-    EXPECT_EQ(2u, WriteBlockedListPeer::GetWriteBlockedList(2, &list)->size());
-    list.UpdateStreamPriorityInWriteBlockedList(3, 3, 1);
-    EXPECT_EQ(1u, WriteBlockedListPeer::GetWriteBlockedList(1, &list)->size());
-    EXPECT_EQ(0u, WriteBlockedListPeer::GetWriteBlockedList(3, &list)->size());
+  list.UpdateStreamPriorityInWriteBlockedList(1, 3, 2);
+  EXPECT_EQ(0u, WriteBlockedListPeer::GetWriteBlockedList(1, &list)->size());
+  EXPECT_EQ(2u, WriteBlockedListPeer::GetWriteBlockedList(2, &list)->size());
+  list.UpdateStreamPriorityInWriteBlockedList(3, 3, 1);
+  EXPECT_EQ(1u, WriteBlockedListPeer::GetWriteBlockedList(1, &list)->size());
+  EXPECT_EQ(0u, WriteBlockedListPeer::GetWriteBlockedList(3, &list)->size());
 
-    // Redundant update.
-    list.UpdateStreamPriorityInWriteBlockedList(1, 2, 2);
-    EXPECT_EQ(2u, WriteBlockedListPeer::GetWriteBlockedList(2, &list)->size());
+  // Redundant update.
+  list.UpdateStreamPriorityInWriteBlockedList(1, 2, 2);
+  EXPECT_EQ(2u, WriteBlockedListPeer::GetWriteBlockedList(2, &list)->size());
 
-    // No entries for given stream_id / old_priority pair.
-    list.UpdateStreamPriorityInWriteBlockedList(4, 4, 1);
-    EXPECT_EQ(1u, WriteBlockedListPeer::GetWriteBlockedList(1, &list)->size());
-    EXPECT_EQ(2u, WriteBlockedListPeer::GetWriteBlockedList(2, &list)->size());
-    EXPECT_EQ(0u, WriteBlockedListPeer::GetWriteBlockedList(4, &list)->size());
+  // No entries for given stream_id / old_priority pair.
+  list.UpdateStreamPriorityInWriteBlockedList(4, 4, 1);
+  EXPECT_EQ(1u, WriteBlockedListPeer::GetWriteBlockedList(1, &list)->size());
+  EXPECT_EQ(2u, WriteBlockedListPeer::GetWriteBlockedList(2, &list)->size());
+  EXPECT_EQ(0u, WriteBlockedListPeer::GetWriteBlockedList(4, &list)->size());
 
-    EXPECT_EQ(3, list.PopFront(1));
-    EXPECT_EQ(2, list.PopFront(2));
-    EXPECT_EQ(1, list.PopFront(2));
-    EXPECT_EQ(0u, list.NumBlockedStreams());
-  } else {
-    list.PushBack(1, 1);
-    list.PushBack(2, 2);
-    list.PushBack(3, 3);
-    list.PushBack(1, 3);
-    list.PushBack(1, 3);
-    EXPECT_EQ(5u, list.NumBlockedStreams());
-    EXPECT_EQ(1u, WriteBlockedListPeer::GetWriteBlockedList(1, &list)->size());
-    EXPECT_EQ(1u, WriteBlockedListPeer::GetWriteBlockedList(2, &list)->size());
-    EXPECT_EQ(3u, WriteBlockedListPeer::GetWriteBlockedList(3, &list)->size());
-
-    list.UpdateStreamPriorityInWriteBlockedList(1, 1, 2);
-    EXPECT_EQ(0u, WriteBlockedListPeer::GetWriteBlockedList(1, &list)->size());
-    EXPECT_EQ(2u, WriteBlockedListPeer::GetWriteBlockedList(2, &list)->size());
-    list.UpdateStreamPriorityInWriteBlockedList(3, 3, 1);
-    EXPECT_EQ(1u, WriteBlockedListPeer::GetWriteBlockedList(1, &list)->size());
-    EXPECT_EQ(2u, WriteBlockedListPeer::GetWriteBlockedList(3, &list)->size());
-
-    // Redundant update.
-    list.UpdateStreamPriorityInWriteBlockedList(1, 3, 3);
-    EXPECT_EQ(2u, WriteBlockedListPeer::GetWriteBlockedList(3, &list)->size());
-
-    // No entries for given stream_id / old_priority pair.
-    list.UpdateStreamPriorityInWriteBlockedList(4, 4, 1);
-    EXPECT_EQ(1u, WriteBlockedListPeer::GetWriteBlockedList(1, &list)->size());
-    EXPECT_EQ(2u, WriteBlockedListPeer::GetWriteBlockedList(2, &list)->size());
-    EXPECT_EQ(0u, WriteBlockedListPeer::GetWriteBlockedList(4, &list)->size());
-
-    // Update multiple entries.
-    list.UpdateStreamPriorityInWriteBlockedList(1, 3, 4);
-    EXPECT_EQ(0u, WriteBlockedListPeer::GetWriteBlockedList(3, &list)->size());
-    EXPECT_EQ(1u, WriteBlockedListPeer::GetWriteBlockedList(4, &list)->size());
-
-    EXPECT_EQ(3, list.PopFront(1));
-    EXPECT_EQ(2, list.PopFront(2));
-    EXPECT_EQ(1, list.PopFront(2));
-    EXPECT_EQ(1, list.PopFront(4));
-    EXPECT_EQ(0u, list.NumBlockedStreams());
-  }
+  EXPECT_EQ(3, list.PopFront(1));
+  EXPECT_EQ(2, list.PopFront(2));
+  EXPECT_EQ(1, list.PopFront(2));
+  EXPECT_EQ(0u, list.NumBlockedStreams());
 }
 
 }  // namespace
diff --git a/net/ssl/ssl_failure_state.h b/net/ssl/ssl_failure_state.h
new file mode 100644
index 0000000..5f43e0a
--- /dev/null
+++ b/net/ssl/ssl_failure_state.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 NET_SSL_SSL_FAILURE_STATE_H_
+#define NET_SSL_SSL_FAILURE_STATE_H_
+
+namespace net {
+
+// Describes the most likely cause for the TLS handshake failure. This is an
+// approximation used to classify the causes of TLS version fallback. These
+// values are used in histograms, so new values must be appended.
+enum SSLFailureState {
+  // The connection was successful.
+  SSL_FAILURE_NONE = 0,
+
+  // The connection failed for unknown reasons.
+  SSL_FAILURE_UNKNOWN = 1,
+
+  // The connection failed after sending ClientHello and before receiving
+  // ServerHello.
+  SSL_FAILURE_CLIENT_HELLO = 2,
+
+  // The connection failed after negotiating TLS_RSA_WITH_AES_128_GCM_SHA256 or
+  // TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 and completing the client's second
+  // leg. Some Microsoft IIS servers fail at this point. See
+  // https://crbug.com/433406.
+  SSL_FAILURE_BUGGY_GCM = 3,
+
+  // The connection failed after CertificateVerify was sent. Some servers are
+  // known to incorrectly implement TLS 1.2 client auth.
+  SSL_FAILURE_CLIENT_AUTH = 4,
+
+  // The connection failed because the server attempted to resume a session at
+  // the wrong version. Some versions of OpenSSL may do this in rare
+  // circumstances. See https://crbug.com/441456
+  SSL_FAILURE_SESSION_MISMATCH = 5,
+
+  // The connection failed after sending the NextProto message. Some F5 servers
+  // fail to parse such messages in TLS 1.1 and TLS 1.2, but not 1.0. See
+  // https://crbug.com/466977.
+  SSL_FAILURE_NEXT_PROTO = 6,
+
+  SSL_FAILURE_MAX,
+};
+
+}  // namespace net
+
+#endif  // NET_SSL_SSL_FAILURE_STATE_H_
diff --git a/net/test/spawned_test_server/remote_test_server.cc b/net/test/spawned_test_server/remote_test_server.cc
index 1d1481b..bf2c025 100644
--- a/net/test/spawned_test_server/remote_test_server.cc
+++ b/net/test/spawned_test_server/remote_test_server.cc
@@ -103,7 +103,7 @@
 
   // Generate JSON-formatted argument string.
   std::string arguments_string;
-  base::JSONWriter::Write(&arguments_dict, &arguments_string);
+  base::JSONWriter::Write(arguments_dict, &arguments_string);
   if (arguments_string.empty())
     return false;
 
@@ -123,7 +123,7 @@
   // the remote server.
   server_data_dict.SetInteger("port", test_server_port);
   std::string server_data;
-  base::JSONWriter::Write(&server_data_dict, &server_data);
+  base::JSONWriter::Write(server_data_dict, &server_data);
   if (server_data.empty() || !ParseServerData(server_data)) {
     LOG(ERROR) << "Could not parse server_data: " << server_data;
     return false;
diff --git a/net/tools/get_server_time/get_server_time.cc b/net/tools/get_server_time/get_server_time.cc
index 9915e8e..fe1c124 100644
--- a/net/tools/get_server_time/get_server_time.cc
+++ b/net/tools/get_server_time/get_server_time.cc
@@ -122,7 +122,7 @@
     scoped_ptr<base::Value> params(entry.ParametersToValue());
     std::string params_str;
     if (params.get()) {
-      base::JSONWriter::Write(params.get(), &params_str);
+      base::JSONWriter::Write(*params, &params_str);
       params_str.insert(0, ": ");
     }
 
diff --git a/net/tools/net_watcher/net_watcher.cc b/net/tools/net_watcher/net_watcher.cc
index 8d1d056..02c373a 100644
--- a/net/tools/net_watcher/net_watcher.cc
+++ b/net/tools/net_watcher/net_watcher.cc
@@ -71,7 +71,7 @@
 std::string ProxyConfigToString(const net::ProxyConfig& config) {
   scoped_ptr<base::Value> config_value(config.ToValue());
   std::string str;
-  base::JSONWriter::Write(config_value.get(), &str);
+  base::JSONWriter::Write(*config_value, &str);
   return str;
 }
 
diff --git a/net/tools/quic/quic_dispatcher.cc b/net/tools/quic/quic_dispatcher.cc
index 1b252ef..04c7c10 100644
--- a/net/tools/quic/quic_dispatcher.cc
+++ b/net/tools/quic/quic_dispatcher.cc
@@ -9,6 +9,7 @@
 #include "base/debug/stack_trace.h"
 #include "base/logging.h"
 #include "base/stl_util.h"
+#include "net/quic/quic_flags.h"
 #include "net/quic/quic_utils.h"
 #include "net/tools/quic/quic_per_connection_packet_writer.h"
 #include "net/tools/quic/quic_time_wait_list_manager.h"
@@ -20,6 +21,12 @@
 using std::make_pair;
 using base::StringPiece;
 
+// The threshold size for the session map, over which the dispatcher will start
+// sending stateless rejects (SREJ), rather than stateful rejects (REJ) to
+// clients who support them.  If -1, stateless rejects will not be sent.  If 0,
+// the server will only send stateless rejects to clients who support them.
+int32 FLAGS_quic_session_map_threshold_for_stateless_rejects = -1;
+
 namespace {
 
 // An alarm that informs the QuicDispatcher to delete old sessions.
@@ -290,6 +297,17 @@
       session_map_.insert(make_pair(connection_id, session));
       session->connection()->ProcessUdpPacket(
           current_server_address_, current_client_address_, *current_packet_);
+
+      if (FLAGS_enable_quic_stateless_reject_support &&
+          session->UsingStatelessRejectsIfPeerSupported() &&
+          session->PeerSupportsStatelessRejects() &&
+          !session->IsCryptoHandshakeConfirmed()) {
+        DVLOG(1) << "Removing new session for " << connection_id
+                 << " because the session is in stateless reject mode and"
+                 << " encryption has not been established.";
+        session->connection()->CloseConnection(
+            QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT, /* from_peer */ false);
+      }
       break;
     }
     case kFateTimeWait:
@@ -298,7 +316,8 @@
       DVLOG(1) << "Adding connection ID " << connection_id
                << "to time-wait list.";
       time_wait_list_manager_->AddConnectionIdToTimeWait(
-          connection_id, framer_.version(), nullptr);
+          connection_id, framer_.version(),
+          /*connection_rejected_statelessly=*/false, nullptr);
       DCHECK(time_wait_list_manager_->IsConnectionIdInTimeWait(
           header.public_header.connection_id));
       time_wait_list_manager_->ProcessPacket(
@@ -343,14 +362,16 @@
   return kFateProcess;
 }
 
-void QuicDispatcher::CleanUpSession(SessionMap::iterator it) {
+void QuicDispatcher::CleanUpSession(SessionMap::iterator it,
+                                    bool should_close_statelessly) {
   QuicConnection* connection = it->second->connection();
   QuicEncryptedPacket* connection_close_packet =
       connection->ReleaseConnectionClosePacket();
   write_blocked_list_.erase(connection);
-  time_wait_list_manager_->AddConnectionIdToTimeWait(it->first,
-                                                     connection->version(),
-                                                     connection_close_packet);
+  DCHECK(!should_close_statelessly || !connection_close_packet);
+  time_wait_list_manager_->AddConnectionIdToTimeWait(
+      it->first, connection->version(), should_close_statelessly,
+      connection_close_packet);
   session_map_.erase(it);
 }
 
@@ -407,7 +428,9 @@
     delete_sessions_alarm_->Set(helper()->GetClock()->ApproximateNow());
   }
   closed_session_list_.push_back(it->second);
-  CleanUpSession(it);
+  const bool should_close_statelessly =
+      (error == QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT);
+  CleanUpSession(it, should_close_statelessly);
 }
 
 void QuicDispatcher::OnWriteBlocked(
@@ -444,6 +467,12 @@
 
   QuicServerSession* session = new QuicServerSession(config_, connection, this);
   session->InitializeSession(crypto_config_);
+  if (FLAGS_quic_session_map_threshold_for_stateless_rejects != -1 &&
+      session_map_.size() >=
+          static_cast<size_t>(
+              FLAGS_quic_session_map_threshold_for_stateless_rejects)) {
+    session->set_use_stateless_rejects_if_peer_supported(true);
+  }
   return session;
 }
 
diff --git a/net/tools/quic/quic_dispatcher.h b/net/tools/quic/quic_dispatcher.h
index 9fcc03b..8381969 100644
--- a/net/tools/quic/quic_dispatcher.h
+++ b/net/tools/quic/quic_dispatcher.h
@@ -226,9 +226,10 @@
   // of a data packet that is destined for the time wait manager.
   void OnUnauthenticatedHeader(const QuicPacketHeader& header);
 
-  // Removes the session from the session map and write blocked list, and
-  // adds the ConnectionId to the time-wait list.
-  void CleanUpSession(SessionMap::iterator it);
+  // Removes the session from the session map and write blocked list, and adds
+  // the ConnectionId to the time-wait list.  If |session_closed_statelessly| is
+  // true, any future packets for the ConnectionId will be black-holed.
+  void CleanUpSession(SessionMap::iterator it, bool session_closed_statelessly);
 
   bool HandlePacketForTimeWait(const QuicPacketPublicHeader& header);
 
diff --git a/net/tools/quic/quic_dispatcher_test.cc b/net/tools/quic/quic_dispatcher_test.cc
index 0e3fdff..95b0030f 100644
--- a/net/tools/quic/quic_dispatcher_test.cc
+++ b/net/tools/quic/quic_dispatcher_test.cc
@@ -4,6 +4,7 @@
 
 #include "net/tools/quic/quic_dispatcher.h"
 
+#include <ostream>
 #include <string>
 
 #include "base/strings/string_piece.h"
@@ -31,6 +32,7 @@
 using net::test::MockSession;
 using net::test::ValueRestore;
 using std::string;
+using std::vector;
 using testing::DoAll;
 using testing::InSequence;
 using testing::Invoke;
@@ -52,21 +54,28 @@
   MOCK_METHOD1(CreateIncomingDataStream, QuicDataStream*(QuicStreamId id));
   MOCK_METHOD0(CreateOutgoingDataStream, QuicDataStream*());
 
+  void SetCryptoStream(QuicCryptoServerStream* crypto_stream) {
+    crypto_stream_ = crypto_stream;
+  }
+
+  QuicCryptoServerStream* GetCryptoStream() override { return crypto_stream_; }
+
  private:
+  QuicCryptoServerStream* crypto_stream_;
+
   DISALLOW_COPY_AND_ASSIGN(TestServerSession);
 };
 
 class TestDispatcher : public QuicDispatcher {
  public:
-  explicit TestDispatcher(const QuicConfig& config,
-                          const QuicCryptoServerConfig* crypto_config,
-                          EpollServer* eps)
+  TestDispatcher(const QuicConfig& config,
+                 const QuicCryptoServerConfig* crypto_config,
+                 EpollServer* eps)
       : QuicDispatcher(config,
                        crypto_config,
                        QuicSupportedVersions(),
                        new QuicDispatcher::DefaultPacketWriterFactory(),
-                       new QuicEpollConnectionHelper(eps)) {
-  }
+                       new QuicEpollConnectionHelper(eps)) {}
 
   MOCK_METHOD3(CreateQuicSession,
                QuicServerSession*(QuicConnectionId connection_id,
@@ -77,8 +86,8 @@
   using QuicDispatcher::current_client_address;
 };
 
-// A Connection class which unregisters the session from the dispatcher
-// when sending connection close.
+// A Connection class which unregisters the session from the dispatcher when
+// sending connection close.
 // It'd be slightly more realistic to do this from the Session but it would
 // involve a lot more mocking.
 class MockServerConnection : public MockConnection {
@@ -269,7 +278,7 @@
   // wait list manager.
   EXPECT_CALL(*time_wait_list_manager_,
               ProcessPacket(_, _, connection_id, _, _)).Times(1);
-  EXPECT_CALL(*time_wait_list_manager_, AddConnectionIdToTimeWait(_, _, _))
+  EXPECT_CALL(*time_wait_list_manager_, AddConnectionIdToTimeWait(_, _, _, _))
       .Times(0);
   ProcessPacket(client_address, connection_id, true, "foo");
 }
@@ -284,11 +293,130 @@
   EXPECT_CALL(dispatcher_, CreateQuicSession(_, _, _)).Times(0);
   EXPECT_CALL(*time_wait_list_manager_,
               ProcessPacket(_, _, connection_id, _, _)).Times(1);
-  EXPECT_CALL(*time_wait_list_manager_, AddConnectionIdToTimeWait(_, _, _))
+  EXPECT_CALL(*time_wait_list_manager_, AddConnectionIdToTimeWait(_, _, _, _))
       .Times(1);
   ProcessPacket(client_address, connection_id, false, "data");
 }
 
+// Enables mocking of the handshake-confirmation for stateless rejects.
+class MockQuicCryptoServerStream : public QuicCryptoServerStream {
+ public:
+  MockQuicCryptoServerStream(const QuicCryptoServerConfig& crypto_config,
+                             QuicSession* session)
+      : QuicCryptoServerStream(&crypto_config, session) {}
+  void set_handshake_confirmed_for_testing(bool handshake_confirmed) {
+    handshake_confirmed_ = handshake_confirmed;
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MockQuicCryptoServerStream);
+};
+
+struct StatelessRejectTestParams {
+  StatelessRejectTestParams(bool enable_stateless_rejects_via_flag,
+                            bool use_stateless_rejects_if_peer_supported,
+                            bool client_supports_statelesss_rejects,
+                            bool crypto_handshake_successful)
+      : enable_stateless_rejects_via_flag(enable_stateless_rejects_via_flag),
+        use_stateless_rejects_if_peer_supported(
+            use_stateless_rejects_if_peer_supported),
+        client_supports_statelesss_rejects(client_supports_statelesss_rejects),
+        crypto_handshake_successful(crypto_handshake_successful) {}
+
+  friend std::ostream& operator<<(std::ostream& os,
+                                  const StatelessRejectTestParams& p) {
+    os << "  enable_stateless_rejects_via_flag: "
+       << p.enable_stateless_rejects_via_flag << std::endl;
+    os << "{ use_stateless_rejects_if_peer_supported: "
+       << p.use_stateless_rejects_if_peer_supported << std::endl;
+    os << "{ client_supports_statelesss_rejects: "
+       << p.client_supports_statelesss_rejects << std::endl;
+    os << "  crypto_handshake_successful: " << p.crypto_handshake_successful
+       << " }";
+    return os;
+  }
+
+  // This only enables the stateless reject feature via the feature-flag.
+  // It does not force the crypto server to emit stateless rejects.
+  bool enable_stateless_rejects_via_flag;
+  // If true, this forces the server to send a stateless reject when rejecting
+  // messages.  This should be a no-op if enable_stateless_rejects_via_flag is
+  // false or the peer does not support them.
+  bool use_stateless_rejects_if_peer_supported;
+  // Whether or not the client supports stateless rejects.
+  bool client_supports_statelesss_rejects;
+  // Should the initial crypto handshake succeed or not.
+  bool crypto_handshake_successful;
+};
+
+// Constructs various test permutations for stateless rejects.
+vector<StatelessRejectTestParams> GetStatelessRejectTestParams() {
+  vector<StatelessRejectTestParams> params;
+  for (bool enable_stateless_rejects_via_flag : {true, false}) {
+    for (bool use_stateless_rejects_if_peer_supported : {true, false}) {
+      for (bool client_supports_statelesss_rejects : {true, false}) {
+        for (bool crypto_handshake_successful : {true, false}) {
+          params.push_back(StatelessRejectTestParams(
+              enable_stateless_rejects_via_flag,
+              use_stateless_rejects_if_peer_supported,
+              client_supports_statelesss_rejects, crypto_handshake_successful));
+        }
+      }
+    }
+  }
+  return params;
+}
+
+class QuicDispatcherStatelessRejectTest
+    : public QuicDispatcherTest,
+      public ::testing::WithParamInterface<StatelessRejectTestParams> {
+ public:
+  QuicDispatcherStatelessRejectTest() : crypto_stream1_(nullptr) {}
+
+  ~QuicDispatcherStatelessRejectTest() override {
+    if (crypto_stream1_) {
+      delete crypto_stream1_;
+    }
+  }
+
+  // This test setup assumes that all testing will be done using
+  // crypto_stream1_.
+  void SetUp() override {
+    FLAGS_enable_quic_stateless_reject_support =
+        GetParam().enable_stateless_rejects_via_flag;
+  }
+
+  // Returns true or false, depending on whether the server will emit
+  // a stateless reject, depending upon the parameters of the test.
+  bool ExpectStatelessReject() {
+    return GetParam().enable_stateless_rejects_via_flag &&
+           GetParam().use_stateless_rejects_if_peer_supported &&
+           !GetParam().crypto_handshake_successful &&
+           GetParam().client_supports_statelesss_rejects;
+  }
+
+  // Sets up dispatcher_, sesession1_, and crypto_stream1_ based on
+  // the test parameters.
+  QuicServerSession* CreateSessionBasedOnTestParams(
+      QuicConnectionId connection_id,
+      const IPEndPoint& client_address) {
+    CreateSession(&dispatcher_, config_, connection_id, client_address,
+                  &session1_);
+
+    crypto_stream1_ = new MockQuicCryptoServerStream(crypto_config_, session1_);
+    session1_->SetCryptoStream(crypto_stream1_);
+    crypto_stream1_->set_use_stateless_rejects_if_peer_supported(
+        GetParam().use_stateless_rejects_if_peer_supported);
+    crypto_stream1_->set_handshake_confirmed_for_testing(
+        GetParam().crypto_handshake_successful);
+    crypto_stream1_->set_peer_supports_stateless_rejects(
+        GetParam().client_supports_statelesss_rejects);
+    return session1_;
+  }
+
+  MockQuicCryptoServerStream* crypto_stream1_;
+};
+
 TEST_F(QuicDispatcherTest, ProcessPacketWithZeroPort) {
   CreateTimeWaitListManager();
 
@@ -298,7 +426,7 @@
   // dispatcher_ should drop this packet.
   EXPECT_CALL(dispatcher_, CreateQuicSession(1, _, client_address)).Times(0);
   EXPECT_CALL(*time_wait_list_manager_, ProcessPacket(_, _, _, _, _)).Times(0);
-  EXPECT_CALL(*time_wait_list_manager_, AddConnectionIdToTimeWait(_, _, _))
+  EXPECT_CALL(*time_wait_list_manager_, AddConnectionIdToTimeWait(_, _, _, _))
       .Times(0);
   ProcessPacket(client_address, 1, true, "foo");
 }
@@ -330,7 +458,7 @@
   EXPECT_CALL(dispatcher_, CreateQuicSession(_, _, _)).Times(0);
   EXPECT_CALL(*time_wait_list_manager_,
               ProcessPacket(_, _, connection_id, _, _)).Times(1);
-  EXPECT_CALL(*time_wait_list_manager_, AddConnectionIdToTimeWait(_, _, _))
+  EXPECT_CALL(*time_wait_list_manager_, AddConnectionIdToTimeWait(_, _, _, _))
       .Times(1);
   // A packet whose sequence number is one to large to be allowed to start a
   // connection.
@@ -339,6 +467,52 @@
                 QuicDispatcher::kMaxReasonableInitialSequenceNumber + 1);
 }
 
+INSTANTIATE_TEST_CASE_P(QuicDispatcherStatelessRejectTests,
+                        QuicDispatcherStatelessRejectTest,
+                        ::testing::ValuesIn(GetStatelessRejectTestParams()));
+
+// Parameterized test for stateless rejects.  Should test all
+// combinations of enabling/disabling, reject/no-reject for stateless
+// rejects.
+TEST_P(QuicDispatcherStatelessRejectTest, ParameterizedBasicTest) {
+  CreateTimeWaitListManager();
+
+  IPEndPoint client_address(net::test::Loopback4(), 1);
+  QuicConnectionId connection_id = 1;
+  EXPECT_CALL(dispatcher_, CreateQuicSession(connection_id, _, client_address))
+      .WillOnce(testing::Return(
+          CreateSessionBasedOnTestParams(connection_id, client_address)));
+
+  // Process the first packet for the connection.
+  if (ExpectStatelessReject()) {
+    // If this is a stateless reject, we expect the connection to close.
+    EXPECT_CALL(*session1_, OnConnectionClosed(_, _))
+        .Times(1)
+        .WillOnce(WithoutArgs(Invoke(
+            reinterpret_cast<MockServerConnection*>(session1_->connection()),
+            &MockServerConnection::UnregisterOnConnectionClosed)));
+  }
+  ProcessPacket(client_address, connection_id, true, "foo");
+
+  // Send a second packet and check the results.  If this is a stateless reject,
+  // the existing connection_id will go on the time-wait list.
+  EXPECT_EQ(ExpectStatelessReject(),
+            time_wait_list_manager_->IsConnectionIdInTimeWait(connection_id));
+  if (ExpectStatelessReject()) {
+    // The second packet will be processed on the time-wait list.
+    EXPECT_CALL(*time_wait_list_manager_,
+                ProcessPacket(_, _, connection_id, _, _)).Times(1);
+  } else {
+    // The second packet will trigger a packet-validation
+    EXPECT_CALL(*reinterpret_cast<MockConnection*>(session1_->connection()),
+                ProcessUdpPacket(_, _, _))
+        .Times(1)
+        .WillOnce(testing::WithArgs<2>(
+            Invoke(this, &QuicDispatcherTest::ValidatePacket)));
+  }
+  ProcessPacket(client_address, connection_id, true, "foo");
+}
+
 // Verify the stopgap test: Packets with truncated connection IDs should be
 // dropped.
 class QuicDispatcherTestStrayPacketConnectionId
@@ -358,7 +532,7 @@
   EXPECT_CALL(dispatcher_, CreateQuicSession(_, _, _)).Times(0);
   EXPECT_CALL(*time_wait_list_manager_,
               ProcessPacket(_, _, connection_id, _, _)).Times(0);
-  EXPECT_CALL(*time_wait_list_manager_, AddConnectionIdToTimeWait(_, _, _))
+  EXPECT_CALL(*time_wait_list_manager_, AddConnectionIdToTimeWait(_, _, _, _))
       .Times(0);
   ProcessPacket(client_address, connection_id, true, "data",
                 connection_id_length, PACKET_6BYTE_SEQUENCE_NUMBER);
diff --git a/net/tools/quic/quic_server.cc b/net/tools/quic/quic_server.cc
index b285b33..5d551e68 100644
--- a/net/tools/quic/quic_server.cc
+++ b/net/tools/quic/quic_server.cc
@@ -27,10 +27,6 @@
 
 // TODO(rtenneti): Add support for MMSG_MORE.
 #define MMSG_MORE 0
-// If true, QuicListener uses the QuicPacketReader to read packets instead of
-// QuicServer.
-// TODO(rtenneti): Enable this flag after MMSG_MORE is set to 1.
-#define FLAGS_quic_use_optimized_packet_reader false
 
 #ifndef SO_RXQ_OVFL
 #define SO_RXQ_OVFL 40
@@ -221,32 +217,13 @@
     bool read = true;
     while (read) {
       if (use_recvmmsg_) {
-        if (FLAGS_quic_use_optimized_packet_reader) {
-          read = packet_reader_->ReadAndDispatchPackets(
-              fd_, port_, dispatcher_.get(),
-              overflow_supported_ ? &packets_dropped_ : nullptr);
-        } else {
-// TODO(rtenneti): Add support for ReadAndDispatchPackets.
-#if 0
-          read = ReadAndDispatchPackets(
-              fd_, port_, dispatcher_.get(),
-              overflow_supported_ ? &packets_dropped_ : nullptr);
-#else
-          read = ReadAndDispatchSinglePacket(
-              fd_, port_, dispatcher_.get(),
-              overflow_supported_ ? &packets_dropped_ : nullptr);
-#endif
-        }
+        read = packet_reader_->ReadAndDispatchPackets(
+            fd_, port_, dispatcher_.get(),
+            overflow_supported_ ? &packets_dropped_ : nullptr);
       } else {
-        if (FLAGS_quic_use_optimized_packet_reader) {
-          read = QuicPacketReader::ReadAndDispatchSinglePacket(
-              fd_, port_, dispatcher_.get(),
-              overflow_supported_ ? &packets_dropped_ : nullptr);
-        } else {
-          read = ReadAndDispatchSinglePacket(
-              fd_, port_, dispatcher_.get(),
-              overflow_supported_ ? &packets_dropped_ : nullptr);
-        }
+        read = QuicPacketReader::ReadAndDispatchSinglePacket(
+            fd_, port_, dispatcher_.get(),
+            overflow_supported_ ? &packets_dropped_ : nullptr);
       }
     }
   }
@@ -260,35 +237,5 @@
   }
 }
 
-/* static */
-bool QuicServer::ReadAndDispatchSinglePacket(int fd,
-                                             int port,
-                                             ProcessPacketInterface* processor,
-                                             QuicPacketCount* packets_dropped) {
-  // Allocate some extra space so we can send an error if the client goes over
-  // the limit.
-  char buf[2 * kMaxPacketSize];
-
-  IPEndPoint client_address;
-  IPAddressNumber server_ip;
-  int bytes_read =
-      QuicSocketUtils::ReadPacket(fd, buf, arraysize(buf),
-                                  packets_dropped,
-                                  &server_ip, &client_address);
-
-  if (bytes_read < 0) {
-    return false;  // We failed to read.
-  }
-
-  QuicEncryptedPacket packet(buf, bytes_read, false);
-
-  IPEndPoint server_address(server_ip, port);
-  processor->ProcessPacket(server_address, client_address, packet);
-
-  // The socket read was successful, so return true even if packet dispatch
-  // failed.
-  return true;
-}
-
 }  // namespace tools
 }  // namespace net
diff --git a/net/tools/quic/quic_server.h b/net/tools/quic/quic_server.h
index 865de95..56b9e4d 100644
--- a/net/tools/quic/quic_server.h
+++ b/net/tools/quic/quic_server.h
@@ -55,20 +55,6 @@
   void OnEvent(int fd, EpollEvent* event) override;
   void OnUnregistration(int fd, bool replaced) override {}
 
-  // Reads a number of packets from the given fd, and then passes them off to
-  // the QuicDispatcher.  Returns true if some packets are read, false
-  // otherwise.
-  // If packets_dropped is non-null, the socket is configured to track
-  // dropped packets, and some packets are read, it will be set to the number of
-  // dropped packets.
-  static bool ReadAndDispatchPackets(int fd, int port,
-                                     ProcessPacketInterface* processor,
-                                     QuicPacketCount* packets_dropped);
-  // Same as ReadAndDispatchPackets, only does one packet at a time.
-  static bool ReadAndDispatchSinglePacket(int fd, int port,
-                                          ProcessPacketInterface* processor,
-                                          QuicPacketCount* packets_dropped);
-
   void OnShutdown(EpollServer* eps, int fd) override {}
 
   void SetStrikeRegisterNoStartupPeriod() {
diff --git a/net/tools/quic/quic_server_session.cc b/net/tools/quic/quic_server_session.cc
index 2d80451..8999397 100644
--- a/net/tools/quic/quic_server_session.cc
+++ b/net/tools/quic/quic_server_session.cc
@@ -175,6 +175,11 @@
 }
 
 bool QuicServerSession::ShouldCreateIncomingDataStream(QuicStreamId id) {
+  if (!connection()->connected()) {
+    LOG(DFATAL) << "ShouldCreateIncomingDataStream called when disconnected";
+    return false;
+  }
+
   if (id % 2 == 0) {
     DVLOG(1) << "Invalid incoming even stream_id:" << id;
     connection()->SendConnectionClose(QUIC_INVALID_STREAM_ID);
diff --git a/net/tools/quic/quic_server_session.h b/net/tools/quic/quic_server_session.h
index 5cd6dfd..dc63341 100644
--- a/net/tools/quic/quic_server_session.h
+++ b/net/tools/quic/quic_server_session.h
@@ -76,10 +76,31 @@
   // Override base class to process FEC config received from client.
   void OnConfigNegotiated() override;
 
+  bool UsingStatelessRejectsIfPeerSupported() {
+    if (GetCryptoStream() == nullptr) {
+      return false;
+    }
+    return GetCryptoStream()->use_stateless_rejects_if_peer_supported();
+  }
+
+  bool PeerSupportsStatelessRejects() {
+    if (GetCryptoStream() == nullptr) {
+      return false;
+    }
+    return GetCryptoStream()->peer_supports_stateless_rejects();
+  }
+
   void set_serving_region(std::string serving_region) {
     serving_region_ = serving_region;
   }
 
+  void set_use_stateless_rejects_if_peer_supported(
+      bool use_stateless_rejects_if_peer_supported) {
+    DCHECK(GetCryptoStream() != nullptr);
+    GetCryptoStream()->set_use_stateless_rejects_if_peer_supported(
+        use_stateless_rejects_if_peer_supported);
+  }
+
  protected:
   // QuicSession methods:
   QuicDataStream* CreateIncomingDataStream(QuicStreamId id) override;
diff --git a/net/tools/quic/quic_server_session_test.cc b/net/tools/quic/quic_server_session_test.cc
index 665ca6b..b48021b 100644
--- a/net/tools/quic/quic_server_session_test.cc
+++ b/net/tools/quic/quic_server_session_test.cc
@@ -18,6 +18,7 @@
 #include "net/quic/test_tools/quic_session_peer.h"
 #include "net/quic/test_tools/quic_sustained_bandwidth_recorder_peer.h"
 #include "net/quic/test_tools/quic_test_utils.h"
+#include "net/test/gtest_util.h"
 #include "net/tools/quic/quic_spdy_server_stream.h"
 #include "net/tools/quic/test_tools/quic_test_utils.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -262,6 +263,13 @@
             QuicServerSessionPeer::GetIncomingDataStream(session_.get(), 4));
 }
 
+TEST_P(QuicServerSessionTest, GetStreamDisconnected) {
+  // Don't create new streams if the connection is disconnected.
+  QuicConnectionPeer::CloseConnection(connection_);
+  EXPECT_DFATAL(QuicServerSessionPeer::GetIncomingDataStream(session_.get(), 4),
+                "ShouldCreateIncomingDataStream called when disconnected");
+}
+
 TEST_P(QuicServerSessionTest, SetFecProtectionFromConfig) {
   ValueRestore<bool> old_flag(&FLAGS_enable_quic_fec, true);
 
diff --git a/net/tools/quic/quic_time_wait_list_manager.cc b/net/tools/quic/quic_time_wait_list_manager.cc
index baba81e0..c9405e55 100644
--- a/net/tools/quic/quic_time_wait_list_manager.cc
+++ b/net/tools/quic/quic_time_wait_list_manager.cc
@@ -106,7 +106,11 @@
 void QuicTimeWaitListManager::AddConnectionIdToTimeWait(
     QuicConnectionId connection_id,
     QuicVersion version,
+    bool connection_rejected_statelessly,
     QuicEncryptedPacket* close_packet) {
+  DCHECK(!connection_rejected_statelessly || !close_packet)
+      << "Connections that were rejected statelessly should not "
+      << "have a close packet.  connection_id = " << connection_id;
   int num_packets = 0;
   ConnectionIdMap::iterator it = connection_id_map_.find(connection_id);
   const bool new_connection_id = it == connection_id_map_.end();
@@ -118,10 +122,8 @@
   TrimTimeWaitListIfNeeded();
   DCHECK_LT(num_connections(),
             static_cast<size_t>(FLAGS_quic_time_wait_list_max_connections));
-  ConnectionIdData data(num_packets,
-                        version,
-                        clock_->ApproximateNow(),
-                        close_packet);
+  ConnectionIdData data(num_packets, version, clock_->ApproximateNow(),
+                        close_packet, connection_rejected_statelessly);
   connection_id_map_.insert(std::make_pair(connection_id, data));
   if (new_connection_id) {
     visitor_->OnConnectionAddedToTimeWaitList(connection_id);
@@ -164,22 +166,24 @@
   ConnectionIdMap::iterator it = connection_id_map_.find(connection_id);
   DCHECK(it != connection_id_map_.end());
   // Increment the received packet count.
-  ++((it->second).num_packets);
-  if (!ShouldSendResponse((it->second).num_packets)) {
+  ConnectionIdData* connection_data = &it->second;
+  ++(connection_data->num_packets);
+  if (!ShouldSendResponse(connection_data->num_packets)) {
     return;
   }
-  if (it->second.close_packet) {
-    QueuedPacket* queued_packet =
-        new QueuedPacket(server_address,
-                         client_address,
-                         it->second.close_packet->Clone());
+  if (connection_data->close_packet) {
+    QueuedPacket* queued_packet = new QueuedPacket(
+        server_address, client_address, connection_data->close_packet->Clone());
     // Takes ownership of the packet.
     SendOrQueuePacket(queued_packet);
-  } else {
+  } else if (!connection_data->connection_rejected_statelessly) {
     SendPublicReset(server_address,
                     client_address,
                     connection_id,
                     sequence_number);
+  } else {
+    DVLOG(3) << "Time wait list not sending response for connection "
+             << connection_id << " due to previous stateless reject.";
   }
 }
 
diff --git a/net/tools/quic/quic_time_wait_list_manager.h b/net/tools/quic/quic_time_wait_list_manager.h
index 8c12869..bbaf6f0 100644
--- a/net/tools/quic/quic_time_wait_list_manager.h
+++ b/net/tools/quic/quic_time_wait_list_manager.h
@@ -55,9 +55,16 @@
   // and sends it again when packets are received for added connection_ids. If
   // nullptr, a public reset packet is sent with the specified |version|.
   // DCHECKs that connection_id is not already on the list. "virtual" to
-  // override in tests.
+  // override in tests.  If "connection_rejected_statelessly" is true, it means
+  // that the connection was closed due to a stateless reject, and no close
+  // packet is expected.  Any packets that are received for connection_id will
+  // be black-holed.
+  // TODO(jokulik): In the future, we plan send (redundant) SREJ packets back to
+  // the client in response to stray data-packets that arrive after the first
+  // SREJ.  This requires some new plumbing, so we black-hole for now.
   virtual void AddConnectionIdToTimeWait(QuicConnectionId connection_id,
                                          QuicVersion version,
+                                         bool connection_rejected_statelessly,
                                          QuicEncryptedPacket* close_packet);
 
   // Returns true if the connection_id is in time wait state, false otherwise.
@@ -145,15 +152,18 @@
     ConnectionIdData(int num_packets_,
                      QuicVersion version_,
                      QuicTime time_added_,
-                     QuicEncryptedPacket* close_packet)
+                     QuicEncryptedPacket* close_packet,
+                     bool connection_rejected_statelessly)
         : num_packets(num_packets_),
           version(version_),
           time_added(time_added_),
-          close_packet(close_packet) {}
+          close_packet(close_packet),
+          connection_rejected_statelessly(connection_rejected_statelessly) {}
     int num_packets;
     QuicVersion version;
     QuicTime time_added;
     QuicEncryptedPacket* close_packet;
+    bool connection_rejected_statelessly;
   };
 
   // linked_hash_map allows lookup by ConnectionId and traversal in add order.
diff --git a/net/tools/quic/quic_time_wait_list_manager_test.cc b/net/tools/quic/quic_time_wait_list_manager_test.cc
index 42073146..8f12c7e 100644
--- a/net/tools/quic/quic_time_wait_list_manager_test.cc
+++ b/net/tools/quic/quic_time_wait_list_manager_test.cc
@@ -114,14 +114,22 @@
   }
 
   void AddConnectionId(QuicConnectionId connection_id) {
-    AddConnectionId(connection_id, QuicVersionMax(), nullptr);
+    AddConnectionId(connection_id, QuicVersionMax(),
+                    /*connection_rejected_statelessly=*/false, nullptr);
+  }
+
+  void AddStatelessConnectionId(QuicConnectionId connection_id) {
+    time_wait_list_manager_.AddConnectionIdToTimeWait(
+        connection_id, QuicVersionMax(),
+        /*connection_rejected_statelessly=*/true, nullptr);
   }
 
   void AddConnectionId(QuicConnectionId connection_id,
                        QuicVersion version,
+                       bool connection_rejected_statelessly,
                        QuicEncryptedPacket* packet) {
     time_wait_list_manager_.AddConnectionIdToTimeWait(
-        connection_id, version, packet);
+        connection_id, version, connection_rejected_statelessly, packet);
   }
 
   bool IsConnectionIdInTimeWait(QuicConnectionId connection_id) {
@@ -231,14 +239,21 @@
   EXPECT_TRUE(IsConnectionIdInTimeWait(connection_id_));
 }
 
+TEST_F(QuicTimeWaitListManagerTest, CheckStatelessConnectionIdInTimeWait) {
+  EXPECT_FALSE(IsConnectionIdInTimeWait(connection_id_));
+  EXPECT_CALL(visitor_, OnConnectionAddedToTimeWaitList(connection_id_));
+  AddStatelessConnectionId(connection_id_);
+  EXPECT_EQ(1u, time_wait_list_manager_.num_connections());
+  EXPECT_TRUE(IsConnectionIdInTimeWait(connection_id_));
+}
+
 TEST_F(QuicTimeWaitListManagerTest, SendConnectionClose) {
   const size_t kConnectionCloseLength = 100;
   EXPECT_CALL(visitor_, OnConnectionAddedToTimeWaitList(connection_id_));
-  AddConnectionId(
-      connection_id_,
-      QuicVersionMax(),
-      new QuicEncryptedPacket(
-          new char[kConnectionCloseLength], kConnectionCloseLength, true));
+  AddConnectionId(connection_id_, QuicVersionMax(),
+                  /*connection_rejected_statelessly=*/false,
+                  new QuicEncryptedPacket(new char[kConnectionCloseLength],
+                                          kConnectionCloseLength, true));
   const int kRandomSequenceNumber = 1;
   EXPECT_CALL(writer_, WritePacket(_, kConnectionCloseLength,
                                    server_address_.address(),
@@ -283,6 +298,13 @@
   }
 }
 
+TEST_F(QuicTimeWaitListManagerTest, NoPublicResetForStatelessConnections) {
+  EXPECT_CALL(visitor_, OnConnectionAddedToTimeWaitList(connection_id_));
+  AddStatelessConnectionId(connection_id_);
+  const int kRandomSequenceNumber = 1;
+  ProcessPacket(connection_id_, kRandomSequenceNumber);
+}
+
 TEST_F(QuicTimeWaitListManagerTest, CleanUpOldConnectionIds) {
   const size_t kConnectionIdCount = 100;
   const size_t kOldConnectionIdCount = 31;
@@ -406,9 +428,12 @@
   EXPECT_CALL(visitor_, OnConnectionAddedToTimeWaitList(kConnectionId1));
   EXPECT_CALL(visitor_, OnConnectionAddedToTimeWaitList(kConnectionId2));
   EXPECT_CALL(visitor_, OnConnectionAddedToTimeWaitList(kConnectionId3));
-  AddConnectionId(kConnectionId1, QuicVersionMin(), nullptr);
-  AddConnectionId(kConnectionId2, QuicVersionMax(), nullptr);
-  AddConnectionId(kConnectionId3, QuicVersionMax(), nullptr);
+  AddConnectionId(kConnectionId1, QuicVersionMin(),
+                  /*connection_rejected_statelessly=*/false, nullptr);
+  AddConnectionId(kConnectionId2, QuicVersionMax(),
+                  /*connection_rejected_statelessly=*/false, nullptr);
+  AddConnectionId(kConnectionId3, QuicVersionMax(),
+                  /*connection_rejected_statelessly=*/false, nullptr);
 
   EXPECT_EQ(QuicVersionMin(),
             QuicTimeWaitListManagerPeer::GetQuicVersionFromConnectionId(
@@ -428,11 +453,10 @@
   AddConnectionId(connection_id_);
   EXPECT_TRUE(IsConnectionIdInTimeWait(connection_id_));
   const size_t kConnectionCloseLength = 100;
-  AddConnectionId(
-      connection_id_,
-      QuicVersionMax(),
-      new QuicEncryptedPacket(
-          new char[kConnectionCloseLength], kConnectionCloseLength, true));
+  AddConnectionId(connection_id_, QuicVersionMax(),
+                  /*connection_rejected_statelessly=*/false,
+                  new QuicEncryptedPacket(new char[kConnectionCloseLength],
+                                          kConnectionCloseLength, true));
   EXPECT_TRUE(IsConnectionIdInTimeWait(connection_id_));
   EXPECT_EQ(1u, time_wait_list_manager_.num_connections());
 
diff --git a/net/tools/quic/test_tools/packet_dropping_test_writer.cc b/net/tools/quic/test_tools/packet_dropping_test_writer.cc
index e31a728..7957380 100644
--- a/net/tools/quic/test_tools/packet_dropping_test_writer.cc
+++ b/net/tools/quic/test_tools/packet_dropping_test_writer.cc
@@ -46,8 +46,10 @@
 PacketDroppingTestWriter::PacketDroppingTestWriter()
     : clock_(nullptr),
       cur_buffer_size_(0),
+      num_calls_to_write_(0),
       config_mutex_(),
       fake_packet_loss_percentage_(0),
+      fake_drop_first_n_packets_(0),
       fake_blocked_socket_percentage_(0),
       fake_packet_reorder_percentage_(0),
       fake_packet_delay_(QuicTime::Delta::Zero()),
@@ -76,9 +78,16 @@
     size_t buf_len,
     const net::IPAddressNumber& self_address,
     const net::IPEndPoint& peer_address) {
+  ++num_calls_to_write_;
   ReleaseOldPackets();
 
   base::AutoLock locked(config_mutex_);
+  if (fake_drop_first_n_packets_ > 0 &&
+      num_calls_to_write_ <= static_cast<uint64>(fake_drop_first_n_packets_)) {
+    DVLOG(1) << "Dropping first " << fake_drop_first_n_packets_
+             << " packets (packet number " << num_calls_to_write_ << ")";
+    return WriteResult(WRITE_STATUS_OK, buf_len);
+  }
   if (fake_packet_loss_percentage_ > 0 &&
       simple_random_.RandUint64() % 100 <
           static_cast<uint64>(fake_packet_loss_percentage_)) {
diff --git a/net/tools/quic/test_tools/packet_dropping_test_writer.h b/net/tools/quic/test_tools/packet_dropping_test_writer.h
index e181fdbf..ae1aac0 100644
--- a/net/tools/quic/test_tools/packet_dropping_test_writer.h
+++ b/net/tools/quic/test_tools/packet_dropping_test_writer.h
@@ -69,6 +69,13 @@
     fake_packet_loss_percentage_ = fake_packet_loss_percentage;
   }
 
+  // Simulate dropping the first n packets unconditionally.
+  // Subsequent packets will be lost at fake_packet_loss_percentage_ if set.
+  void set_fake_drop_first_n_packets(int32 fake_drop_first_n_packets) {
+    base::AutoLock locked(config_mutex_);
+    fake_drop_first_n_packets_ = fake_drop_first_n_packets;
+  }
+
   // The percent of time WritePacket will block and set WriteResult's status
   // to WRITE_STATUS_BLOCKED.
   void set_fake_blocked_socket_percentage(
@@ -141,9 +148,11 @@
   // Stored packets delayed by fake packet delay or bandwidth restrictions.
   DelayedPacketList delayed_packets_;
   QuicByteCount cur_buffer_size_;
+  uint64 num_calls_to_write_;
 
   base::Lock config_mutex_;
   int32 fake_packet_loss_percentage_;
+  int32 fake_drop_first_n_packets_;
   int32 fake_blocked_socket_percentage_;
   int32 fake_packet_reorder_percentage_;
   QuicTime::Delta fake_packet_delay_;
diff --git a/net/tools/quic/test_tools/quic_test_utils.cc b/net/tools/quic/test_tools/quic_test_utils.cc
index 5e954dd..11ff985 100644
--- a/net/tools/quic/test_tools/quic_test_utils.cc
+++ b/net/tools/quic/test_tools/quic_test_utils.cc
@@ -123,8 +123,8 @@
                               QuicSupportedVersions()) {
   // Though AddConnectionIdToTimeWait is mocked, we want to retain its
   // functionality.
-  EXPECT_CALL(*this, AddConnectionIdToTimeWait(_, _, _)).Times(AnyNumber());
-  ON_CALL(*this, AddConnectionIdToTimeWait(_, _, _))
+  EXPECT_CALL(*this, AddConnectionIdToTimeWait(_, _, _, _)).Times(AnyNumber());
+  ON_CALL(*this, AddConnectionIdToTimeWait(_, _, _, _))
       .WillByDefault(
           Invoke(this, &MockTimeWaitListManager::
                            QuicTimeWaitListManager_AddConnectionIdToTimeWait));
diff --git a/net/tools/quic/test_tools/quic_test_utils.h b/net/tools/quic/test_tools/quic_test_utils.h
index e7884680..dac5f5c 100644
--- a/net/tools/quic/test_tools/quic_test_utils.h
+++ b/net/tools/quic/test_tools/quic_test_utils.h
@@ -154,20 +154,21 @@
   MockTimeWaitListManager(QuicPacketWriter* writer,
                           QuicServerSessionVisitor* visitor,
                           QuicConnectionHelperInterface* helper);
-
   ~MockTimeWaitListManager() override;
 
-  MOCK_METHOD3(AddConnectionIdToTimeWait,
+  MOCK_METHOD4(AddConnectionIdToTimeWait,
                void(QuicConnectionId connection_id,
                     QuicVersion version,
+                    bool connection_rejected_statelessly,
                     QuicEncryptedPacket* close_packet));
 
   void QuicTimeWaitListManager_AddConnectionIdToTimeWait(
       QuicConnectionId connection_id,
       QuicVersion version,
+      bool connection_rejected_statelessly,
       QuicEncryptedPacket* close_packet) {
-    QuicTimeWaitListManager::AddConnectionIdToTimeWait(connection_id, version,
-                                                       close_packet);
+    QuicTimeWaitListManager::AddConnectionIdToTimeWait(
+        connection_id, version, connection_rejected_statelessly, close_packet);
   }
 
   MOCK_METHOD5(ProcessPacket,
diff --git a/pdf/out_of_process_instance.cc b/pdf/out_of_process_instance.cc
index 8c240a60..d8188ad4 100644
--- a/pdf/out_of_process_instance.cc
+++ b/pdf/out_of_process_instance.cc
@@ -469,7 +469,7 @@
           engine_->HasPermission(PDFEngine::PERMISSION_COPY_ACCESSIBLE);
       node.SetBoolean(kAccessibleCopyable, has_permissions);
       std::string json;
-      base::JSONWriter::Write(&node, &json);
+      base::JSONWriter::Write(node, &json);
       reply.Set(pp::Var(kJSAccessibilityJSON), pp::Var(json));
     }
     PostMessage(reply);
diff --git a/pdf/pdfium/pdfium_engine.cc b/pdf/pdfium/pdfium_engine.cc
index 8012dd26..f4df4a99 100644
--- a/pdf/pdfium/pdfium_engine.cc
+++ b/pdf/pdfium/pdfium_engine.cc
@@ -661,17 +661,11 @@
     pages_[i]->Unload();
 
   if (doc_) {
-    if (form_) {
-      FORM_DoDocumentAAction(form_, FPDFDOC_AACTION_WC);
-    }
+    FORM_DoDocumentAAction(form_, FPDFDOC_AACTION_WC);
     FPDF_CloseDocument(doc_);
-    if (form_) {
-      FPDFDOC_ExitFormFillEnvironment(form_);
-    }
+    FPDFDOC_ExitFormFillEnvironment(form_);
   }
-
-  if (fpdf_availability_)
-    FPDFAvail_Destroy(fpdf_availability_);
+  FPDFAvail_Destroy(fpdf_availability_);
 
   STLDeleteElements(&pages_);
 }
@@ -2440,7 +2434,7 @@
   scoped_ptr<base::Value> node(
       pages_[index]->GetAccessibleContentAsValue(current_rotation_));
   std::string page_json;
-  base::JSONWriter::Write(node.get(), &page_json);
+  base::JSONWriter::Write(*node, &page_json);
   return page_json;
 }
 
diff --git a/printing/printed_document.cc b/printing/printed_document.cc
index 62fbef8..3b17eff 100644
--- a/printing/printed_document.cc
+++ b/printing/printed_document.cc
@@ -78,7 +78,7 @@
   PrintSettingsToJobSettingsDebug(settings, &job_settings);
   std::string settings_str;
   base::JSONWriter::WriteWithOptions(
-      &job_settings, base::JSONWriter::OPTIONS_PRETTY_PRINT, &settings_str);
+      job_settings, base::JSONWriter::OPTIONS_PRETTY_PRINT, &settings_str);
   scoped_refptr<base::RefCountedMemory> data =
       base::RefCountedString::TakeString(&settings_str);
   blocking_runner->PostTask(
diff --git a/remoting/app_remoting_webapp.gyp b/remoting/app_remoting_webapp.gyp
index 9c8add8a..7373778d 100644
--- a/remoting/app_remoting_webapp.gyp
+++ b/remoting/app_remoting_webapp.gyp
@@ -92,6 +92,7 @@
 
   'targets': [
     {
+      # GN version: //remoting/webapp:ar_sample_app
       # Sample AppRemoting app.
       'target_name': 'ar_sample_app',
       'app_key': 'Sample_App',
diff --git a/remoting/app_remoting_webapp_build.gypi b/remoting/app_remoting_webapp_build.gypi
index 9f7572cb..bc6ffa6 100644
--- a/remoting/app_remoting_webapp_build.gypi
+++ b/remoting/app_remoting_webapp_build.gypi
@@ -11,6 +11,7 @@
     'app_remoting_webapp_files.gypi',
   ],
 
+  # GN version: See remoting/webapp/build_template.gni
   'target_defaults': {
     'type': 'none',
 
@@ -119,7 +120,6 @@
           '<(ar_app_manifest_app)', # Manifest template
           'app_remoting',  # Web app type
           '<@(ar_webapp_files)',
-          '<@(ar_generated_html_files)',
           '--locales_listfile',
           '<(ar_webapp_locales_listfile)',
           '--jinja_paths',
diff --git a/remoting/base/buffered_socket_writer_unittest.cc b/remoting/base/buffered_socket_writer_unittest.cc
index 0c740447..07bb2ec 100644
--- a/remoting/base/buffered_socket_writer_unittest.cc
+++ b/remoting/base/buffered_socket_writer_unittest.cc
@@ -45,6 +45,14 @@
                                 size);
   }
 
+  bool AllReadDataConsumed() const override {
+    return true;
+  }
+
+  bool AllWriteDataConsumed() const override {
+    return true;
+  }
+
   void Reset() override {}
 
   std::string written_data() { return written_data_; }
diff --git a/remoting/base/vlog_net_log.cc b/remoting/base/vlog_net_log.cc
index 39a388a7..bfcea02 100644
--- a/remoting/base/vlog_net_log.cc
+++ b/remoting/base/vlog_net_log.cc
@@ -35,7 +35,7 @@
   if (VLOG_IS_ON(4)) {
     scoped_ptr<base::Value> value(entry.ToValue());
     std::string json;
-    base::JSONWriter::Write(value.get(), &json);
+    base::JSONWriter::Write(*value, &json);
     VLOG(4) << json;
   }
 }
diff --git a/remoting/client/plugin/chromoting_instance.cc b/remoting/client/plugin/chromoting_instance.cc
index 3faab96..a3544aa9 100644
--- a/remoting/client/plugin/chromoting_instance.cc
+++ b/remoting/client/plugin/chromoting_instance.cc
@@ -1016,12 +1016,12 @@
 void ChromotingInstance::PostLegacyJsonMessage(
     const std::string& method,
     scoped_ptr<base::DictionaryValue> data) {
-  scoped_ptr<base::DictionaryValue> message(new base::DictionaryValue());
-  message->SetString("method", method);
-  message->Set("data", data.release());
+  base::DictionaryValue message;
+  message.SetString("method", method);
+  message.Set("data", data.release());
 
   std::string message_json;
-  base::JSONWriter::Write(message.get(), &message_json);
+  base::JSONWriter::Write(message, &message_json);
   PostMessage(pp::Var(message_json));
 }
 
diff --git a/remoting/codec/video_encoder_vpx.cc b/remoting/codec/video_encoder_vpx.cc
index 724fbecd..c74f0d8 100644
--- a/remoting/codec/video_encoder_vpx.cc
+++ b/remoting/codec/video_encoder_vpx.cc
@@ -39,6 +39,10 @@
 const int kVp9I420ProfileNumber = 0;
 const int kVp9I444ProfileNumber = 1;
 
+// Magic encoder constants for adaptive quantization strategy.
+const int kVp9AqModeNone = 0;
+const int kVp9AqModeCyclicRefresh = 3;
+
 void SetCommonCodecParameters(vpx_codec_enc_cfg_t* config,
                               const webrtc::DesktopSize& size) {
   // Use millisecond granularity time base.
@@ -137,6 +141,11 @@
   ret = vpx_codec_control(
       codec, VP9E_SET_TUNE_CONTENT, VP9E_CONTENT_SCREEN);
   DCHECK_EQ(VPX_CODEC_OK, ret) << "Failed to set screen content mode";
+
+  // Set cyclic refresh (aka "top-off") only for lossy encoding.
+  int aq_mode = lossless_encode ? kVp9AqModeNone : kVp9AqModeCyclicRefresh;
+  ret = vpx_codec_control(codec, VP9E_SET_AQ_MODE, aq_mode);
+  DCHECK_EQ(VPX_CODEC_OK, ret) << "Failed to set aq mode";
 }
 
 void FreeImageIfMismatched(bool use_i444,
@@ -273,7 +282,7 @@
   PrepareImage(frame, &updated_region);
 
   // Update active map based on updated region.
-  PrepareActiveMap(updated_region);
+  SetActiveMapFromRegion(updated_region);
 
   // Apply active map to the encoder.
   vpx_active_map_t act_map;
@@ -293,6 +302,14 @@
       << "Details: " << vpx_codec_error(codec_.get()) << "\n"
       << vpx_codec_error_detail(codec_.get());
 
+  if (use_vp9_ && !lossless_encode_) {
+    ret = vpx_codec_control(codec_.get(), VP9E_GET_ACTIVEMAP, &act_map);
+    DCHECK_EQ(ret, VPX_CODEC_OK)
+        << "Failed to fetch active map: "
+        << vpx_codec_err_to_string(ret) << "\n";
+    UpdateRegionFromActiveMap(&updated_region);
+  }
+
   // Read the encoded data.
   vpx_codec_iter_t iter = NULL;
   bool got_data = false;
@@ -485,7 +502,7 @@
   }
 }
 
-void VideoEncoderVpx::PrepareActiveMap(
+void VideoEncoderVpx::SetActiveMapFromRegion(
     const webrtc::DesktopRegion& updated_region) {
   // Clear active map first.
   memset(active_map_.get(), 0, active_map_width_ * active_map_height_);
@@ -510,4 +527,26 @@
   }
 }
 
+void VideoEncoderVpx::UpdateRegionFromActiveMap(
+    webrtc::DesktopRegion* updated_region) {
+  const uint8* map = active_map_.get();
+  for (int y = 0; y < active_map_height_; ++y) {
+    for (int x0 = 0; x0 < active_map_width_;) {
+      int x1 = x0;
+      for (; x1 < active_map_width_; ++x1) {
+        if (map[y * active_map_width_ + x1] == 0)
+          break;
+      }
+      if (x1 > x0) {
+        updated_region->AddRect(webrtc::DesktopRect::MakeLTRB(
+            kMacroBlockSize * x0, kMacroBlockSize * y, kMacroBlockSize * x1,
+            kMacroBlockSize * (y + 1)));
+      }
+      x0 = x1 + 1;
+    }
+  }
+  updated_region->IntersectWith(
+      webrtc::DesktopRect::MakeWH(image_->w, image_->h));
+}
+
 }  // namespace remoting
diff --git a/remoting/codec/video_encoder_vpx.h b/remoting/codec/video_encoder_vpx.h
index a7433a1..d8d39eb 100644
--- a/remoting/codec/video_encoder_vpx.h
+++ b/remoting/codec/video_encoder_vpx.h
@@ -47,7 +47,11 @@
 
   // Updates the active map according to |updated_region|. Active map is then
   // given to the encoder to speed up encoding.
-  void PrepareActiveMap(const webrtc::DesktopRegion& updated_region);
+  void SetActiveMapFromRegion(const webrtc::DesktopRegion& updated_region);
+
+  // Adds areas changed in the most recent frame to |updated_region|. This
+  // includes both content changes and areas enhanced by cyclic refresh.
+  void UpdateRegionFromActiveMap(webrtc::DesktopRegion* updated_region);
 
   // True if the encoder is for VP9, false for VP8.
   const bool use_vp9_;
diff --git a/remoting/host/cast_extension_session.cc b/remoting/host/cast_extension_session.cc
index 9bceaa6..843a79d 100644
--- a/remoting/host/cast_extension_session.cc
+++ b/remoting/host/cast_extension_session.cc
@@ -202,15 +202,15 @@
   peer_connection_->SetLocalDescription(
       CastSetSessionDescriptionObserver::Create(), desc);
 
-  scoped_ptr<base::DictionaryValue> json(new base::DictionaryValue());
-  json->SetString(kWebRtcSessionDescType, desc->type());
+  base::DictionaryValue json;
+  json.SetString(kWebRtcSessionDescType, desc->type());
   std::string subject =
       (desc->type() == "offer") ? kSubjectOffer : kSubjectAnswer;
   std::string desc_str;
   desc->ToString(&desc_str);
-  json->SetString(kWebRtcSessionDescSDP, desc_str);
+  json.SetString(kWebRtcSessionDescSDP, desc_str);
   std::string json_str;
-  if (!base::JSONWriter::Write(json.get(), &json_str)) {
+  if (!base::JSONWriter::Write(json, &json_str)) {
     LOG(ERROR) << "Failed to serialize sdp message.";
     return;
   }
@@ -420,7 +420,7 @@
   message_dict.SetString(kTopLevelData, data);
   std::string message_json;
 
-  if (!base::JSONWriter::Write(&message_dict, &message_json)) {
+  if (!base::JSONWriter::Write(message_dict, &message_json)) {
     LOG(ERROR) << "Failed to serialize JSON message.";
     return false;
   }
@@ -647,12 +647,12 @@
     LOG(ERROR) << "PeerConnectionObserver: failed to serialize candidate.";
     return;
   }
-  scoped_ptr<base::DictionaryValue> json(new base::DictionaryValue());
-  json->SetString(kWebRtcSDPMid, candidate->sdp_mid());
-  json->SetInteger(kWebRtcSDPMLineIndex, candidate->sdp_mline_index());
-  json->SetString(kWebRtcCandidate, candidate_str);
+  base::DictionaryValue json;
+  json.SetString(kWebRtcSDPMid, candidate->sdp_mid());
+  json.SetInteger(kWebRtcSDPMLineIndex, candidate->sdp_mline_index());
+  json.SetString(kWebRtcCandidate, candidate_str);
   std::string json_str;
-  if (!base::JSONWriter::Write(json.get(), &json_str)) {
+  if (!base::JSONWriter::Write(json, &json_str)) {
     LOG(ERROR) << "Failed to serialize candidate message.";
     return;
   }
diff --git a/remoting/host/gnubby_auth_handler_posix.cc b/remoting/host/gnubby_auth_handler_posix.cc
index 13c8f41..4639f01 100644
--- a/remoting/host/gnubby_auth_handler_posix.cc
+++ b/remoting/host/gnubby_auth_handler_posix.cc
@@ -174,7 +174,7 @@
   request.Set(kDataPayload, bytes);
 
   std::string request_json;
-  if (!base::JSONWriter::Write(&request, &request_json)) {
+  if (!base::JSONWriter::Write(request, &request_json)) {
     LOG(ERROR) << "Failed to create request json";
     return;
   }
diff --git a/remoting/host/host_config.cc b/remoting/host/host_config.cc
index 40ae940b..2250d6fc4 100644
--- a/remoting/host/host_config.cc
+++ b/remoting/host/host_config.cc
@@ -28,7 +28,7 @@
 
 std::string HostConfigToJson(const base::DictionaryValue& host_config) {
   std::string data;
-  base::JSONWriter::Write(&host_config, &data);
+  base::JSONWriter::Write(host_config, &data);
   return data;
 }
 
diff --git a/remoting/host/it2me/it2me_native_messaging_host.cc b/remoting/host/it2me/it2me_native_messaging_host.cc
index 7af2db74..441224e 100644
--- a/remoting/host/it2me/it2me_native_messaging_host.cc
+++ b/remoting/host/it2me/it2me_native_messaging_host.cc
@@ -121,7 +121,7 @@
     scoped_ptr<base::DictionaryValue> message) const {
   DCHECK(task_runner()->BelongsToCurrentThread());
   std::string message_json;
-  base::JSONWriter::Write(message.get(), &message_json);
+  base::JSONWriter::Write(*message, &message_json);
   client_->PostMessageFromNativeHost(message_json);
 }
 
diff --git a/remoting/host/it2me/it2me_native_messaging_host_unittest.cc b/remoting/host/it2me/it2me_native_messaging_host_unittest.cc
index a6c6724..cfe66bb 100644
--- a/remoting/host/it2me/it2me_native_messaging_host_unittest.cc
+++ b/remoting/host/it2me/it2me_native_messaging_host_unittest.cc
@@ -291,7 +291,7 @@
 void It2MeNativeMessagingHostTest::WriteMessageToInputPipe(
     const base::Value& message) {
   std::string message_json;
-  base::JSONWriter::Write(&message, &message_json);
+  base::JSONWriter::Write(message, &message_json);
 
   uint32 length = message_json.length();
   input_write_file_.WriteAtCurrentPos(reinterpret_cast<char*>(&length),
diff --git a/remoting/host/native_messaging/native_messaging_pipe.cc b/remoting/host/native_messaging/native_messaging_pipe.cc
index 8521472d..da204d1 100644
--- a/remoting/host/native_messaging/native_messaging_pipe.cc
+++ b/remoting/host/native_messaging/native_messaging_pipe.cc
@@ -27,7 +27,7 @@
 
 void NativeMessagingPipe::OnMessage(scoped_ptr<base::Value> message) {
   std::string message_json;
-  base::JSONWriter::Write(message.get(), &message_json);
+  base::JSONWriter::Write(*message, &message_json);
   host_->OnMessage(message_json);
 }
 
diff --git a/remoting/host/native_messaging/native_messaging_writer.cc b/remoting/host/native_messaging/native_messaging_writer.cc
index 3266fdb7..030cfd3 100644
--- a/remoting/host/native_messaging/native_messaging_writer.cc
+++ b/remoting/host/native_messaging/native_messaging_writer.cc
@@ -44,7 +44,7 @@
   }
 
   std::string message_json;
-  base::JSONWriter::Write(&message, &message_json);
+  base::JSONWriter::Write(message, &message_json);
 
   CHECK_LE(message_json.length(), kMaximumMessageSize);
 
diff --git a/remoting/host/policy_watcher_unittest.cc b/remoting/host/policy_watcher_unittest.cc
index 1d683cbc..b9cbefd 100644
--- a/remoting/host/policy_watcher_unittest.cc
+++ b/remoting/host/policy_watcher_unittest.cc
@@ -27,11 +27,11 @@
   if (!equal) {
     std::string actual_value;
     base::JSONWriter::WriteWithOptions(
-        arg, base::JSONWriter::OPTIONS_PRETTY_PRINT, &actual_value);
+        *arg, base::JSONWriter::OPTIONS_PRETTY_PRINT, &actual_value);
 
     std::string expected_value;
     base::JSONWriter::WriteWithOptions(
-        dict, base::JSONWriter::OPTIONS_PRETTY_PRINT, &expected_value);
+        *dict, base::JSONWriter::OPTIONS_PRETTY_PRINT, &expected_value);
 
     *result_listener << "Policies are not equal. ";
     *result_listener << "Expected policy: " << expected_value << ". ";
diff --git a/remoting/host/setup/daemon_controller_delegate_win.cc b/remoting/host/setup/daemon_controller_delegate_win.cc
index 0dcae692..1795110f 100644
--- a/remoting/host/setup/daemon_controller_delegate_win.cc
+++ b/remoting/host/setup/daemon_controller_delegate_win.cc
@@ -186,7 +186,7 @@
     }
   }
   std::string unprivileged_config_str;
-  base::JSONWriter::Write(&unprivileged_config_dict, &unprivileged_config_str);
+  base::JSONWriter::Write(unprivileged_config_dict, &unprivileged_config_str);
 
   // Write the full configuration file to a temporary location.
   base::FilePath full_config_file_path =
@@ -413,7 +413,7 @@
 
   // Write the updated config.
   std::string config_updated_str;
-  base::JSONWriter::Write(config_old.get(), &config_updated_str);
+  base::JSONWriter::Write(*config_old, &config_updated_str);
   bool result = WriteConfig(config_updated_str);
 
   InvokeCompletionCallback(done, result);
@@ -458,7 +458,7 @@
 
   // Set the configuration.
   std::string config_str;
-  base::JSONWriter::Write(config.release(), &config_str);
+  base::JSONWriter::Write(*config, &config_str);
 
   // Determine the config directory path and create it if necessary.
   base::FilePath config_dir = remoting::GetConfigDir();
diff --git a/remoting/host/setup/me2me_native_messaging_host_unittest.cc b/remoting/host/setup/me2me_native_messaging_host_unittest.cc
index bdd6daf9..b44c2bda 100644
--- a/remoting/host/setup/me2me_native_messaging_host_unittest.cc
+++ b/remoting/host/setup/me2me_native_messaging_host_unittest.cc
@@ -409,7 +409,7 @@
 void Me2MeNativeMessagingHostTest::WriteMessageToInputPipe(
     const base::Value& message) {
   std::string message_json;
-  base::JSONWriter::Write(&message, &message_json);
+  base::JSONWriter::Write(message, &message_json);
 
   uint32 length = message_json.length();
   input_write_file_.WriteAtCurrentPos(reinterpret_cast<char*>(&length),
diff --git a/remoting/host/setup/service_client.cc b/remoting/host/setup/service_client.cc
index 260f7621..f99f6a6c 100644
--- a/remoting/host/setup/service_client.cc
+++ b/remoting/host/setup/service_client.cc
@@ -83,7 +83,7 @@
   if (!host_client_id.empty())
     url_suffix = "?hostClientId=" + host_client_id;
   std::string post_body_str;
-  base::JSONWriter::Write(&post_body, &post_body_str);
+  base::JSONWriter::Write(post_body, &post_body_str);
   MakeChromotingRequest(net::URLFetcher::POST,
                         url_suffix,
                         post_body_str,
diff --git a/remoting/host/token_validator_factory_impl_unittest.cc b/remoting/host/token_validator_factory_impl_unittest.cc
index bfbed9f..aa5a024 100644
--- a/remoting/host/token_validator_factory_impl_unittest.cc
+++ b/remoting/host/token_validator_factory_impl_unittest.cc
@@ -108,7 +108,7 @@
     response_dict.SetString("token_type", "shared_secret");
     response_dict.SetString("scope", scope);
     std::string response;
-    base::JSONWriter::Write(&response_dict, &response);
+    base::JSONWriter::Write(response_dict, &response);
     return response;
   }
 
@@ -116,7 +116,7 @@
     base::DictionaryValue response_dict;
     response_dict.SetString("error", error);
     std::string response;
-    base::JSONWriter::Write(&response_dict, &response);
+    base::JSONWriter::Write(response_dict, &response);
     return response;
   }
 
diff --git a/remoting/host/video_frame_recorder_host_extension.cc b/remoting/host/video_frame_recorder_host_extension.cc
index 61bd7460..efa110e 100644
--- a/remoting/host/video_frame_recorder_host_extension.cc
+++ b/remoting/host/video_frame_recorder_host_extension.cc
@@ -159,7 +159,7 @@
   // Note that JSONWriter::Write() can only fail due to invalid inputs, and will
   // DCHECK in Debug builds in that case.
   std::string reply_json;
-  if (!base::JSONWriter::Write(&reply_message, &reply_json)) {
+  if (!base::JSONWriter::Write(reply_message, &reply_json)) {
     return;
   }
 
diff --git a/remoting/remoting_client.gypi b/remoting/remoting_client.gypi
index e82139c..bef823d3 100644
--- a/remoting/remoting_client.gypi
+++ b/remoting/remoting_client.gypi
@@ -49,12 +49,11 @@
     },  # end of target 'remoting_client'
 
     {
-      # GN version: //remoting/webapp:html
+      # GN version: See remoting/webapp/build_template.gni
       'target_name': 'remoting_webapp_html',
       'type': 'none',
       'actions': [
         {
-          # GN version: //remoting/webapp:main_html
           'action_name': 'Build Remoting Webapp main.html',
           'inputs': [
             'webapp/build-html.py',
@@ -75,7 +74,6 @@
           ],
         },
         {
-          # GN version: //remoting/webapp:wcs_sandbox_html
           'action_name': 'Build Remoting Webapp wcs_sandbox.html',
           'inputs': [
             'webapp/build-html.py',
@@ -92,7 +90,6 @@
           ],
         },
         {
-          # GN version: //remoting/webapp:background_html
           'action_name': 'Build Remoting Webapp background.html',
           'inputs': [
             'webapp/build-html.py',
@@ -128,6 +125,7 @@
     },  # end of target 'remoting_webapp_html'
 
     {
+      # GN version: //remoting/webapp:webapp
       'target_name': 'remoting_webapp',
       'type': 'none',
       'dependencies': [
@@ -143,6 +141,7 @@
     },  # end of target 'remoting_webapp'
 
     {
+      # GN version: //remoting/webapp:webapp_v1
       'target_name': 'remoting_webapp_v1',
       'type': 'none',
       'variables': {
@@ -158,6 +157,7 @@
     ['disable_nacl==0 and disable_nacl_untrusted==0', {
       'targets': [
         {
+          # GN version: //remoting/webapp:webapp_v1
           'target_name': 'remoting_webapp_v2',
           'type': 'none',
           'variables': {
diff --git a/remoting/remoting_version.gni b/remoting/remoting_version.gni
index cb8fb659..db117bd1 100644
--- a/remoting/remoting_version.gni
+++ b/remoting/remoting_version.gni
@@ -15,7 +15,7 @@
 
 # Set these files as being input dependencies to the scripts, so the build will
 # be re-run if the files change.
-_script_deps = [
+remoting_version_files = [
   _remoting_version_abspath,
   _chrome_version_abspath,
   _remoting_branding_abspath,
@@ -35,7 +35,7 @@
                               "-t \"@MAJOR@\"",
                             ],
                             "value",
-                            _script_deps)
+                            remoting_version_files)
 
 version_minor = exec_script(_version_py_abspath,
                             [
@@ -44,7 +44,7 @@
                               "-t \"@REMOTING_PATCH@\"",
                             ],
                             "value",
-                            _script_deps)
+                            remoting_version_files)
 
 version_short =
     "${version_major}.${version_minor}." + exec_script(_version_py_abspath,
@@ -56,7 +56,7 @@
                                                          "-t \"@BUILD@\"",
                                                        ],
                                                        "value",
-                                                       _script_deps)
+                                                       remoting_version_files)
 
 version_full = "${version_short}." + exec_script(_version_py_abspath,
                                                  [
@@ -67,7 +67,7 @@
                                                    "-t \"@PATCH@\"",
                                                  ],
                                                  "value",
-                                                 _script_deps)
+                                                 remoting_version_files)
 
 prefpane_bundle_name = exec_script(_version_py_abspath,
                                    [
@@ -76,7 +76,7 @@
                                      "-t \"@MAC_PREFPANE_BUNDLE_NAME@\"",
                                    ],
                                    "string",
-                                   _script_deps)
+                                   remoting_version_files)
 
 host_bundle_name = exec_script(_version_py_abspath,
                                [
@@ -85,4 +85,4 @@
                                  "-t \"@MAC_HOST_BUNDLE_NAME@\"",
                                ],
                                "string",
-                               _script_deps)
+                               remoting_version_files)
diff --git a/remoting/signaling/xmpp_signal_strategy_unittest.cc b/remoting/signaling/xmpp_signal_strategy_unittest.cc
index b4c4a53..2193982 100644
--- a/remoting/signaling/xmpp_signal_strategy_unittest.cc
+++ b/remoting/signaling/xmpp_signal_strategy_unittest.cc
@@ -29,6 +29,14 @@
 
   void Reset() override {}
 
+  bool AllReadDataConsumed() const override {
+    return true;
+  }
+
+  bool AllWriteDataConsumed() const override {
+    return true;
+  }
+
   void ReceiveData(const std::string& text) {
     socket()->OnReadComplete(
         net::MockRead(net::ASYNC, text.data(), text.size()));
diff --git a/remoting/webapp/BUILD.gn b/remoting/webapp/BUILD.gn
index 02b66677..e3e79664 100644
--- a/remoting/webapp/BUILD.gn
+++ b/remoting/webapp/BUILD.gn
@@ -10,6 +10,7 @@
 group("webapp") {
   deps = [
     ":webapp_v1",
+    ":ar_sample_app",
   ]
 
   if (enable_nacl) {
@@ -17,17 +18,17 @@
   }
 }
 
-remoting_webapp("webapp_v1") {
+desktop_remoting_webapp("webapp_v1") {
   webapp_type = "v1"
-  output_dir = "remoting.webapp"
-  zip_path = "remoting-webapp.zip"
+  output_dir = "remoting/remoting-webapp"
+  zip_path = "remoting/remoting-webapp.zip"
   extra_files = []
 }
 
-remoting_webapp("webapp_v2") {
+desktop_remoting_webapp("webapp_v2") {
   webapp_type = "v2_pnacl"
-  output_dir = "remoting.webapp.v2"
-  zip_path = "remoting-webapp.v2.zip"
+  output_dir = "remoting/remoting-webapp.v2"
+  zip_path = "remoting/remoting-webapp.v2.zip"
   extra_files = [
     "crd/remoting_client_pnacl.nmf.jinja2",
     # TODO(garykac): Get correct path to this.
@@ -35,91 +36,12 @@
   ]
 }
 
-group("html") {
-  deps = [
-    ":background_html",
-    ":main_html",
-    ":message_window_html",
-    ":wcs_sandbox_html",
-  ]
-}
-
-action("main_html") {
-  script = "build-html.py"
-
-  inputs = [ remoting_webapp_template_main ] + remoting_webapp_template_files +
-           remoting_webapp_crd_main_html_all_js_files
-
-  outputs = [
-    "$target_gen_dir/main.html",
-  ]
-
-  args = [
-    rebase_path("$target_gen_dir/main.html", root_build_dir),
-    rebase_path(remoting_webapp_template_main, root_build_dir),
-  ]
-  args += [
-    "--template-dir",
-    rebase_path(remoting_dir, root_build_dir),
-  ]
-  args += [ "--templates" ] +
-          rebase_path(remoting_webapp_template_files, remoting_dir)
-  args += [ "--js" ] +
-          rebase_path(remoting_webapp_crd_main_html_all_js_files, remoting_dir)
-}
-
-action("wcs_sandbox_html") {
-  script = "build-html.py"
-
-  inputs = [ remoting_webapp_template_wcs_sandbox ] +
-           remoting_webapp_wcs_sandbox_html_all_js_files
-
-  outputs = [
-    "$target_gen_dir/wcs_sandbox.html",
-  ]
-
-  args = [
-    rebase_path("$target_gen_dir/wcs_sandbox.html", root_build_dir),
-    rebase_path(remoting_webapp_template_wcs_sandbox, root_build_dir),
-  ]
-  args +=
-      [ "--js" ] +
-      rebase_path(remoting_webapp_wcs_sandbox_html_all_js_files, remoting_dir)
-}
-
-action("background_html") {
-  script = "build-html.py"
-
-  inputs = [ remoting_webapp_template_background ] +
-           remoting_webapp_background_html_all_js_files
-
-  outputs = [
-    "$target_gen_dir/background.html",
-  ]
-
-  args = [
-    rebase_path("$target_gen_dir/background.html", root_build_dir),
-    rebase_path(remoting_webapp_template_background, root_build_dir),
-  ]
-  args += [ "--js" ] + rebase_path(remoting_webapp_background_html_all_js_files,
-                                   remoting_dir)
-}
-
-action("message_window_html") {
-  script = "build-html.py"
-
-  inputs = [ remoting_webapp_template_message_window ] +
-           remoting_webapp_message_window_html_all_js_files
-
-  outputs = [
-    "$target_gen_dir/message_window.html",
-  ]
-
-  args = [
-    rebase_path("$target_gen_dir/message_window.html", root_build_dir),
-    rebase_path(remoting_webapp_template_message_window, root_build_dir),
-  ]
-  args +=
-      [ "--js" ] + rebase_path(remoting_webapp_message_window_html_all_js_files,
-                               remoting_dir)
+app_remoting_webapp("ar_sample_app") {
+  app_key = "Sample_App"
+  app_id = "ljacajndfccfgnfohlgkdphmbnpkjflk"
+  app_client_id = "sample_client_id"
+  app_name = "App Remoting Client"
+  app_description = "App Remoting client"
+  app_capabilities = [ "GOOGLE_DRIVE" ]
+  manifest_key = "remotingdevbuild"
 }
diff --git a/remoting/webapp/build-webapp.py b/remoting/webapp/build-webapp.py
index e2a0abe5c..8f61ca1 100755
--- a/remoting/webapp/build-webapp.py
+++ b/remoting/webapp/build-webapp.py
@@ -169,7 +169,7 @@
       raise
     else:
       pass
-  os.mkdir(destination, 0775)
+  os.makedirs(destination, 0775)
 
   if buildtype != 'Official' and buildtype != 'Release' and buildtype != 'Dev':
     raise Exception('Unknown buildtype: ' + buildtype)
diff --git a/remoting/webapp/build_template.gni b/remoting/webapp/build_template.gni
index 5d4233c..8930b04 100644
--- a/remoting/webapp/build_template.gni
+++ b/remoting/webapp/build_template.gni
@@ -15,17 +15,24 @@
 # to this directory.
 remoting_dir = "//remoting"
 
-template("remoting_webapp") {
-  locales_listfile = target_name + "_locales"
-  listfile = "$target_gen_dir/${target_name}_locales.txt"
-  listfile_rel = rebase_path(listfile, root_build_dir)
+buildtype = "Dev"
+if (!is_debug) {
+  if (is_official_build) {
+    buildtype = "Official"
+  } else {
+    buildtype = "Release"
+  }
+}
 
-  action(locales_listfile) {
+template("build_locales_listfile") {
+  action(target_name) {
+    locales_listfile_output = invoker.locales_listfile_output
+
     script = "../tools/build/remoting_localize.py"
 
     inputs = []
     outputs = [
-      listfile,
+      locales_listfile_output,
     ]
 
     args = [
@@ -33,10 +40,88 @@
       rebase_path(webapp_locale_dir, root_build_dir) +
           "/@{json_suffix}/messages.json",
       "--locales_listfile",
-      listfile_rel,
+      rebase_path(locales_listfile_output, root_build_dir),
     ]
     args += remoting_locales
   }
+}
+
+template("build_webapp_html") {
+  action(target_name) {
+    html_template_file = invoker.html_template_file
+    html_template_files = invoker.html_template_files
+    js_files = invoker.js_files
+    html_output = invoker.html_output
+
+    script = "build-html.py"
+
+    inputs = [ html_template_file ] + html_template_files + js_files
+
+    outputs = [
+      html_output,
+    ]
+
+    args = [
+      rebase_path(html_output, root_build_dir),
+      rebase_path(html_template_file, root_build_dir),
+    ]
+    args += [
+      "--template-dir",
+      rebase_path(remoting_dir, root_build_dir),
+    ]
+    args += [ "--templates" ] + html_template_files
+    args += [ "--js" ] + rebase_path(js_files, remoting_dir)
+  }
+}
+
+template("desktop_remoting_webapp") {
+  locales_listfile = target_name + "_locales"
+  locales_listfile_output = "$target_gen_dir/${target_name}_locales.txt"
+
+  build_locales_listfile(locales_listfile) {
+    # Template uses locales_listfile_output from outer scope.
+  }
+
+  background_html = target_name + "_background_html"
+  background_html_output = "$target_gen_dir/html/$target_name/background.html"
+
+  build_webapp_html(background_html) {
+    html_template_file = remoting_webapp_template_background
+    html_template_files = []
+    js_files = remoting_webapp_background_html_all_js_files
+    html_output = background_html_output
+  }
+
+  message_window_html = target_name + "_message_window_html"
+  message_window_html_output =
+      "$target_gen_dir/html/$target_name/message_window.html"
+
+  build_webapp_html(message_window_html) {
+    html_template_file = remoting_webapp_template_message_window
+    html_template_files = []
+    js_files = remoting_webapp_message_window_html_all_js_files
+    html_output = message_window_html_output
+  }
+
+  wcs_sandbox_html = target_name + "_wcs_sandbox_html"
+  wcs_sandbox_html_output = "$target_gen_dir/html/$target_name/wcs_sandbox.html"
+
+  build_webapp_html(wcs_sandbox_html) {
+    html_template_file = remoting_webapp_template_wcs_sandbox
+    html_template_files = []
+    js_files = remoting_webapp_wcs_sandbox_html_all_js_files
+    html_output = wcs_sandbox_html_output
+  }
+
+  main_html = target_name + "_main_html"
+  main_html_output = "$target_gen_dir/html/$target_name/main.html"
+
+  build_webapp_html(main_html) {
+    html_template_file = remoting_webapp_template_main
+    html_template_files = remoting_webapp_template_files
+    js_files = remoting_webapp_crd_main_html_all_js_files
+    html_output = main_html_output
+  }
 
   action(target_name) {
     script = "build-webapp.py"
@@ -46,39 +131,37 @@
     zip_path = invoker.zip_path
     extra_files = invoker.extra_files
 
-    inputs = []
+    inputs =
+        [ rebase_path("crd/manifest.json.jinja2", root_build_dir) ] +
+        remoting_version_files +
+        rebase_path(remoting_webapp_crd_files, root_build_dir) + extra_files
+
     outputs = [
       "$target_gen_dir/$zip_path",
     ]
 
     deps = [
-      ":html",
       ":$locales_listfile",
+      ":$background_html",
+      ":$message_window_html",
+      ":$wcs_sandbox_html",
+      ":$main_html",
       "//remoting/resources",
     ]
 
-    buildtype = "Dev"
-    if (!is_debug) {
-      if (is_official_build) {
-        buildtype = "Official"
-      } else {
-        buildtype = "Release"
-      }
-    }
-
-    generated_html_files = [
-      "$target_gen_dir/background.html",
-      "$target_gen_dir/main.html",
-      "$target_gen_dir/message_window.html",
-      "$target_gen_dir/wcs_sandbox.html",
+    dr_generated_html_files = [
+      background_html_output,
+      message_window_html_output,
+      wcs_sandbox_html_output,
+      main_html_output,
     ]
 
     # Create a file that contains a list of all the resource files needed
     # to build the webapp. This is needed to avoid problems on platforms that
     # limit the size of a command line.
-    file_list = "$target_gen_dir/${target_name}_file_list.txt"
+    file_list = "$target_gen_dir/${target_name}_files.txt"
     files = []
-    files += rebase_path(generated_html_files, root_build_dir)
+    files += rebase_path(dr_generated_html_files, root_build_dir)
     files += rebase_path(remoting_webapp_crd_files, root_build_dir)
     files += rebase_path(extra_files, root_build_dir)
     write_file(file_list, files)
@@ -97,7 +180,7 @@
     ]
     args += [
       "--locales_listfile",
-      listfile_rel,
+      rebase_path(locales_listfile_output, root_build_dir),
     ]
     args += [
       "--use_gcd",
@@ -105,3 +188,198 @@
     ]
   }
 }
+
+template("app_remoting_webapp") {
+  locales_listfile = target_name + "_locales"
+  locales_listfile_output = "$target_gen_dir/${target_name}_locales.txt"
+
+  build_locales_listfile(locales_listfile) {
+    # Template uses locales_listfile_output from outer scope.
+  }
+
+  feedback_consent_html = target_name + "_feedback_consent_html"
+  feedback_consent_html_output =
+      "$target_gen_dir/html/$target_name/feedback_consent.html"
+
+  build_webapp_html(feedback_consent_html) {
+    html_template_file = ar_feedback_consent_template
+    html_template_files = []
+    js_files = ar_feedback_consent_html_all_js_files
+    html_output = feedback_consent_html_output
+  }
+
+  loading_window_html = target_name + "_loading_window_html"
+  loading_window_html_output =
+      "$target_gen_dir/html/$target_name/loading_window.html"
+
+  build_webapp_html(loading_window_html) {
+    html_template_file = ar_loading_window_template
+    html_template_files = []
+
+    # The loading window is just a reskin of the message window -- all JS code
+    # is shared.
+    js_files = remoting_webapp_message_window_html_all_js_files
+    html_output = loading_window_html_output
+  }
+
+  message_window_html = target_name + "_message_window_html"
+  message_window_html_output =
+      "$target_gen_dir/html/$target_name/message_window.html"
+
+  build_webapp_html(message_window_html) {
+    html_template_file = remoting_webapp_template_message_window
+    html_template_files = []
+    js_files = remoting_webapp_message_window_html_all_js_files
+    html_output = message_window_html_output
+  }
+
+  wcs_sandbox_html = target_name + "_wcs_sandbox_html"
+  wcs_sandbox_html_output = "$target_gen_dir/html/$target_name/wcs_sandbox.html"
+
+  build_webapp_html(wcs_sandbox_html) {
+    html_template_file = remoting_webapp_template_wcs_sandbox
+    html_template_files = []
+    js_files = remoting_webapp_wcs_sandbox_html_all_js_files
+    html_output = wcs_sandbox_html_output
+  }
+
+  main_html = target_name + "_main_html"
+  main_html_output = "$target_gen_dir/html/$target_name/main.html"
+
+  build_webapp_html(main_html) {
+    html_template_file = ar_main_template
+    html_template_files = ar_main_template_files
+    js_files = ar_main_js_files
+    html_output = main_html_output
+  }
+
+  action(target_name) {
+    script = "build-webapp.py"
+
+    app_key = invoker.app_key
+    app_id = invoker.app_id
+    app_client_id = invoker.app_client_id
+    app_name = invoker.app_name
+    app_description = invoker.app_description
+    app_capabilities = invoker.app_capabilities
+    manifest_key = invoker.manifest_key
+
+    # These asserts are so that these variables get marked as being used so
+    # that GN doesn't complain about them.
+    assert(app_key != "" || app_key == "")
+    assert(app_id != "" || app_id == "")
+
+    # TODO(garykac) For internal targets, we need to extract the vendor and app
+    # name from the target.
+    ar_app_name = "sample_app"  #target_name
+    ar_app_path = "app_remoting/apps/$ar_app_name"
+    ar_app_manifest = "$ar_app_path/manifest.json.jinja2"
+    ar_app_manifest_common = "app_remoting/manifest_common.json.jinja2"
+
+    output_dir = "remoting/app_remoting/$ar_service_environment/$target_name"
+    zip_path = "remoting/app_remoting/$ar_service_environment/$target_name.zip"
+
+    ar_app_specific_files = [
+      "$ar_app_path/icon16.png",
+      "$ar_app_path/icon48.png",
+      "$ar_app_path/icon128.png",
+      "$ar_app_path/loading_splash.png",
+    ]
+
+    ar_generated_html_files = [
+      feedback_consent_html_output,
+      loading_window_html_output,
+      message_window_html_output,
+      wcs_sandbox_html_output,
+      main_html_output,
+    ]
+
+    ar_webapp_files =
+        ar_app_specific_files + ar_shared_resource_files + ar_all_js_files
+
+    inputs = [
+               rebase_path(ar_app_manifest, root_build_dir),
+               rebase_path(ar_app_manifest_common, root_build_dir),
+             ] + remoting_version_files + ar_webapp_files
+
+    outputs = [
+      "$target_gen_dir/$zip_path",
+    ]
+
+    deps = [
+      ":$locales_listfile",
+      ":$feedback_consent_html",
+      ":$loading_window_html",
+      ":$message_window_html",
+      ":$wcs_sandbox_html",
+      ":$main_html",
+      "//remoting/resources",
+    ]
+
+    # Create a file that contains a list of all the resource files needed
+    # to build the webapp. This is needed to avoid problems on platforms that
+    # limit the size of a command line.
+    file_list = "$target_gen_dir/${target_name}_files.txt"
+    files = []
+    files += rebase_path(ar_generated_html_files, root_build_dir)
+    files += rebase_path(ar_webapp_files, root_build_dir)
+    write_file(file_list, files)
+
+    args = [
+      buildtype,
+      version_full,
+      output_dir,
+      zip_path,
+      rebase_path(ar_app_manifest, root_build_dir),
+      "app_remoting",  # Web app type
+    ]
+    args += [
+      "--files_listfile",
+      rebase_path(file_list, root_build_dir),
+    ]
+    args += [
+      "--locales_listfile",
+      rebase_path(locales_listfile_output, root_build_dir),
+    ]
+    args += [
+      "--jinja_paths",
+      rebase_path("app_remoting", root_build_dir),
+    ]
+
+    if (is_debug) {
+      # Normally, the app-id for the orchestrator is automatically extracted
+      # from the webapp's extension id, but that approach doesn't work for
+      # dev webapp builds (since they all share the same dev extension id).
+      # The --appid arg will create a webapp that registers the given app-id
+      # rather than using the extension id.
+      # This is only done for Dev apps because the app-id for Release apps
+      # *must* match the extension id.
+      args += [
+        "--appid",
+        app_id,
+      ]
+    }
+
+    args += [
+      "--app_name",
+      app_name,
+    ]
+    args += [
+      "--app_description",
+      app_description,
+    ]
+    args += [ "--app_capabilities" ] + app_capabilities
+    args += [
+      "--service_environment",
+      ar_service_environment,
+    ]
+    args += [
+      "--manifest_key",
+      manifest_key,
+    ]
+    args += [
+      "--app_client_id",
+      app_client_id,
+    ]
+  }
+}
diff --git a/remoting/webapp/files.gni b/remoting/webapp/files.gni
index 08e34271..4bc2b83 100644
--- a/remoting/webapp/files.gni
+++ b/remoting/webapp/files.gni
@@ -10,7 +10,8 @@
 #   MM   `Mb.YM.    , 8M   MM `Mb    MM    MM    MM    MM YM.    ,
 # .JMML. .JMM.`Mbmmd' `Moo9^Yo.`Wbmd"MML..JMML  JMML  JMML.`Mbmmd'
 #
-# Please keep this file in sync with remoting/remoting_webapp_files.gypi.
+# Please keep this file in sync with remoting/remoting_webapp_files.gypi
+# and remoting/app_remoting_webapp_files.gypi.
 
 # Jscompile proto files.
 # These provide type information for jscompile.
@@ -235,13 +236,11 @@
 remoting_webapp_js_cast_extension_files = [ "crd/js/cast_extension_handler.js" ]
 
 # Client JavaScript files.
-remoting_webapp_js_client_files = [ "crd/js/video_frame_recorder.js" ]
-
-# Remoting core JavaScript files.
-remoting_webapp_js_core_files = [
+remoting_webapp_js_client_files = [
   "crd/js/apps_v2_migration.js",
   "crd/js/event_handlers.js",
   "crd/js/gcd_client.js",
+  "crd/js/video_frame_recorder.js",
 ]
 
 # Gnubby authentication JavaScript files.
@@ -278,7 +277,6 @@
   "crd/js/crd_auth_dialog.js",
   "crd/js/crd_event_handlers.js",
   "crd/js/crd_experimental.js",
-  "crd/js/crd_main.js",
   "crd/js/desktop_connected_view.js",
   "crd/js/desktop_remoting.js",
   "crd/js/desktop_remoting_activity.js",
@@ -324,7 +322,8 @@
 
 # The CRD-specific JavaScript files required by main.html.
 remoting_webapp_crd_main_html_all_js_files =
-    remoting_webapp_shared_main_html_js_files + remoting_webapp_crd_js_ui_files
+    remoting_webapp_shared_main_html_js_files +
+    remoting_webapp_crd_js_ui_files + [ "crd/js/crd_main.js" ]
 
 # These template files are used to construct main.html.
 remoting_webapp_template_files = [
@@ -353,7 +352,7 @@
 ]
 
 #
-# Webapp background.html generation files.
+# DesktopRemoting background.html generation files.
 #
 
 remoting_webapp_template_background = "crd/html/template_background.html"
@@ -390,7 +389,7 @@
 ]
 
 #
-# Webapp wcs_sandbox.html generation files.
+# DesktopRemoting wcs_sandbox.html generation files.
 #
 
 remoting_webapp_template_wcs_sandbox = "base/html/template_wcs_sandbox.html"
@@ -413,7 +412,7 @@
 ]
 
 #
-# Webapp message_window.html generation files.
+# DesktopRemoting message_window.html generation files.
 #
 
 remoting_webapp_template_message_window =
@@ -428,7 +427,7 @@
     remoting_webapp_message_window_html_js_files + [ "base/js/base.js" ]
 
 #
-# Complete webapp JS and resource files.
+# DesktopRemoting webapp JS and resource files.
 #
 
 # All the JavaScript files that are shared by webapps.
@@ -498,3 +497,114 @@
   "<@(remoting_webapp_template_files)",
   "<@(remoting_webapp_crd_js_files)",
 ]
+
+#
+# AppRemoting Files
+#
+
+ar_shared_resource_files = [
+                             "app_remoting/html/ar_dialog.css",
+                             "app_remoting/html/ar_main.css",
+                             "app_remoting/html/feedback_consent.css",
+                             "app_remoting/html/loading_window.css",
+                             "app_remoting/html/context_menu.css",
+                             "../resources/drag.webp",
+                           ] + remoting_webapp_resource_files
+
+#
+# AppRemoting main.html generation files.
+#
+
+# These template files are used to construct the webapp html files.
+ar_main_template = "app_remoting/html/template_lg.html"
+
+ar_main_template_files = [
+  "base/html/client_plugin.html",
+  "app_remoting/html/context_menu.html",
+  "app_remoting/html/idle_dialog.html",
+]
+
+ar_main_js_files = [
+                     "app_remoting/js/application_context_menu.js",
+                     "app_remoting/js/app_connected_view.js",
+                     "app_remoting/js/app_remoting.js",
+                     "app_remoting/js/app_remoting_activity.js",
+                     "app_remoting/js/ar_auth_dialog.js",
+                     "app_remoting/js/ar_main.js",
+                     "app_remoting/js/context_menu_adapter.js",
+                     "app_remoting/js/context_menu_chrome.js",
+                     "app_remoting/js/context_menu_dom.js",
+                     "app_remoting/js/drag_and_drop.js",
+                     "app_remoting/js/idle_detector.js",
+                     "app_remoting/js/keyboard_layouts_menu.js",
+                     "app_remoting/js/loading_window.js",
+                     "app_remoting/js/submenu_manager.js",
+                     "app_remoting/js/window_activation_menu.js",
+                     "base/js/application.js",
+                     "base/js/base.js",
+                     "base/js/message_window_helper.js",
+                     "base/js/message_window_manager.js",
+                   ] + remoting_webapp_shared_js_auth_google_files +
+                   remoting_webapp_shared_js_client_files +
+                   remoting_webapp_shared_js_core_files +
+                   remoting_webapp_shared_js_host_files +
+                   remoting_webapp_shared_js_logging_files +
+                   remoting_webapp_shared_js_signaling_files +
+                   remoting_webapp_shared_js_ui_files
+
+#
+# AppRemoting feedback_consent.html generation files.
+#
+
+ar_feedback_consent_template =
+    "app_remoting/html/template_feedback_consent.html"
+
+# These JS files are specific to the feedback consent page and are not part
+# of the main JS files.
+ar_feedback_consent_html_js_files = [ "app_remoting/js/feedback_consent.js" ]
+
+# All the JavaScript files required by feedback_consent.html.
+ar_feedback_consent_html_all_js_files = [
+  "app_remoting/js/feedback_consent.js",
+  "base/js/base.js",
+  "base/js/error.js",
+  "base/js/identity.js",
+  "base/js/oauth2_api.js",
+  "base/js/oauth2_api_impl.js",
+  "base/js/plugin_settings.js",
+  "base/js/l10n.js",
+  "base/js/xhr.js",
+]
+
+#
+# AppRemoting loading_window.html generation files.
+#
+
+# Variables for loading_window.html. Note that the JS files are the same as
+# for message_window.html, and are not duplicated here.
+ar_loading_window_template = "app_remoting/html/template_loading_window.html"
+
+#
+# AppRemoting background JS files.
+# These files are referenced from the manifest
+#
+
+ar_background_js_files = [
+  "app_remoting/js/ar_background.js",
+  "base/js/platform.js",
+]
+
+ar_all_js_files =
+    ar_main_js_files + ar_feedback_consent_html_js_files +
+    remoting_webapp_message_window_html_js_files +
+    remoting_webapp_wcs_sandbox_html_js_files + ar_background_js_files
+
+# Files that contain localizable strings.
+app_remoting_webapp_localizable_files =
+    [
+      ar_main_template,
+      ar_feedback_consent_template,
+      ar_loading_window_template,
+      remoting_webapp_template_message_window,
+      remoting_webapp_template_wcs_sandbox,
+    ] + ar_main_template_files + ar_all_js_files
diff --git a/skia/config/SkUserConfig.h b/skia/config/SkUserConfig.h
index ba9bde3f..06c49e7 100644
--- a/skia/config/SkUserConfig.h
+++ b/skia/config/SkUserConfig.h
@@ -265,6 +265,10 @@
 #   define SK_IGNORE_ETC1_SUPPORT
 #endif
 
+#ifndef    SK_SUPPORT_LEGACY_IMAGEFILTER_TRANSFORM_SCRATCH_LAYTER
+#   define SK_SUPPORT_LEGACY_IMAGEFILTER_TRANSFORM_SCRATCH_LAYTER
+#endif
+
 #ifndef    SK_IGNORE_GPU_DITHER
 #   define SK_IGNORE_GPU_DITHER
 #endif
diff --git a/skia/skia_test_expectations.txt b/skia/skia_test_expectations.txt
index 0f3de22b..4327f6e 100644
--- a/skia/skia_test_expectations.txt
+++ b/skia/skia_test_expectations.txt
@@ -48,9 +48,4 @@
 #
 # START OVERRIDES HERE
 
-# The Skia CL https://codereview.chromium.org/1138893002
-# (Plus xfermode using Sk4px) fixed two images:
-crbug.com/487587 fast/canvas/canvas-composite-transformclip.html [ ImageOnlyFailure ]
-crbug.com/487587 virtual/display_list_2d_canvas/fast/canvas/canvas-composite-transformclip.html [ ImageOnlyFailure ]
-
 # END OVERRIDES HERE (this line ensures that the file is newline-terminated)
diff --git a/sync/BUILD.gn b/sync/BUILD.gn
index bb30475..515f8309 100644
--- a/sync/BUILD.gn
+++ b/sync/BUILD.gn
@@ -743,37 +743,6 @@
   ]
 }
 
-# GYP version: sync/sync_tests.gypi:test_support_accounts_client
-static_library("test_support_accounts_client") {
-  testonly = true
-  sources = [
-    "test/accounts_client/test_accounts_client.cc",
-    "test/accounts_client/test_accounts_client.h",
-    "test/accounts_client/url_request_context_getter.cc",
-    "test/accounts_client/url_request_context_getter.h",
-  ]
-  deps = [
-    "//base",
-    "//net",
-    "//url",
-  ]
-}
-
-# GYP version: sync/sync_tests.gypi:sync_endtoend_tests
-test("sync_endtoend_tests") {
-  sources = [
-    "test/accounts_client/test_accounts_client_unittest.cc",
-  ]
-  deps = [
-    "//base",
-    "//base/test:run_all_unittests",
-    "//testing/gmock",
-    "//testing/gtest",
-    "//url",
-    ":test_support_accounts_client",
-  ]
-}
-
 if (!is_ios) {
   # GYP version: sync/sync_tests.gypi:run_sync_testserver
   executable("run_sync_testserver") {
diff --git a/sync/api/sync_data.cc b/sync/api/sync_data.cc
index 0dd567d6..d6c9152 100644
--- a/sync/api/sync_data.cc
+++ b/sync/api/sync_data.cc
@@ -155,10 +155,9 @@
 
   std::string type = ModelTypeToString(GetDataType());
   std::string specifics;
-  scoped_ptr<base::DictionaryValue> value(
-      EntitySpecificsToValue(GetSpecifics()));
-  base::JSONWriter::WriteWithOptions(
-      value.get(), base::JSONWriter::OPTIONS_PRETTY_PRINT, &specifics);
+  base::JSONWriter::WriteWithOptions(*EntitySpecificsToValue(GetSpecifics()),
+                                     base::JSONWriter::OPTIONS_PRETTY_PRINT,
+                                     &specifics);
 
   if (IsLocal()) {
     SyncDataLocal sync_data_local(*this);
diff --git a/sync/engine/traffic_logger.cc b/sync/engine/traffic_logger.cc
index bc285bd..1e9a6bc 100644
--- a/sync/engine/traffic_logger.cc
+++ b/sync/engine/traffic_logger.cc
@@ -25,9 +25,8 @@
     scoped_ptr<base::DictionaryValue> value =
         (*to_dictionary_value)(data, true /* include_specifics */);
     std::string message;
-    base::JSONWriter::WriteWithOptions(value.get(),
-        base::JSONWriter::OPTIONS_PRETTY_PRINT,
-        &message);
+    base::JSONWriter::WriteWithOptions(
+        *value, base::JSONWriter::OPTIONS_PRETTY_PRINT, &message);
     DVLOG(1) << "\n" << description << "\n" << message << "\n";
   }
 }
diff --git a/sync/internal_api/public/engine/model_safe_worker.cc b/sync/internal_api/public/engine/model_safe_worker.cc
index 9692a78e..f054e503 100644
--- a/sync/internal_api/public/engine/model_safe_worker.cc
+++ b/sync/internal_api/public/engine/model_safe_worker.cc
@@ -24,10 +24,8 @@
 
 std::string ModelSafeRoutingInfoToString(
     const ModelSafeRoutingInfo& routing_info) {
-  scoped_ptr<base::DictionaryValue> dict =
-      ModelSafeRoutingInfoToValue(routing_info);
   std::string json;
-  base::JSONWriter::Write(dict.get(), &json);
+  base::JSONWriter::Write(*ModelSafeRoutingInfoToValue(routing_info), &json);
   return json;
 }
 
diff --git a/sync/internal_api/public/sessions/sync_session_snapshot.cc b/sync/internal_api/public/sessions/sync_session_snapshot.cc
index dcb3f73..9614330 100644
--- a/sync/internal_api/public/sessions/sync_session_snapshot.cc
+++ b/sync/internal_api/public/sessions/sync_session_snapshot.cc
@@ -105,7 +105,7 @@
 std::string SyncSessionSnapshot::ToString() const {
   std::string json;
   base::JSONWriter::WriteWithOptions(
-      ToValue().get(), base::JSONWriter::OPTIONS_PRETTY_PRINT, &json);
+      *ToValue(), base::JSONWriter::OPTIONS_PRETTY_PRINT, &json);
   return json;
 }
 
diff --git a/sync/js/js_event_details.cc b/sync/js/js_event_details.cc
index 0517b39..d430632 100644
--- a/sync/js/js_event_details.cc
+++ b/sync/js/js_event_details.cc
@@ -21,7 +21,7 @@
 
 std::string JsEventDetails::ToString() const {
   std::string str;
-  base::JSONWriter::Write(&Get(), &str);
+  base::JSONWriter::Write(Get(), &str);
   return str;
 }
 
diff --git a/sync/sync_tests.gypi b/sync/sync_tests.gypi
index 198f659..eba5872 100644
--- a/sync/sync_tests.gypi
+++ b/sync/sync_tests.gypi
@@ -373,46 +373,6 @@
         }],
       ],
     },
-
-    # Test support files for using the Test Accounts service.
-    # GN version: //sync:test_support_accounts_client
-    {
-      'target_name': 'test_support_accounts_client',
-      'type': 'static_library',
-      'direct_dependent_settings': {
-        'include_dirs': [
-          '..',
-        ],
-      },
-      'dependencies': [
-        '../base/base.gyp:base',
-        '../net/net.gyp:net',
-      ],
-      'sources': [
-        'test/accounts_client/test_accounts_client.cc',
-        'test/accounts_client/test_accounts_client.h',
-        'test/accounts_client/url_request_context_getter.cc',
-        'test/accounts_client/url_request_context_getter.h',
-      ],
-    },
-
-    # The Sync end-to-end (and associated infrastructure) tests.
-    # GN version: //sync:sync_endtoend_tests
-    {
-      'target_name': 'sync_endtoend_tests',
-      'type': '<(gtest_target_type)',
-      'dependencies': [
-        '../base/base.gyp:run_all_unittests',
-        '../testing/gmock.gyp:gmock',
-        '../testing/gtest.gyp:gtest',
-        '../url/url.gyp:url_lib',
-        'test_support_accounts_client',
-      ],
-      'sources': [
-        'test/accounts_client/test_accounts_client_unittest.cc',
-      ],
-    },
-
   ],
   'conditions': [
     ['OS != "ios"', {
diff --git a/sync/syncable/nigori_util.cc b/sync/syncable/nigori_util.cc
index 1eb92277..1ad5095 100644
--- a/sync/syncable/nigori_util.cc
+++ b/sync/syncable/nigori_util.cc
@@ -175,9 +175,8 @@
     if (VLOG_IS_ON(2)) {
       scoped_ptr<base::DictionaryValue> value(entry->ToValue(NULL));
       std::string info;
-      base::JSONWriter::WriteWithOptions(value.get(),
-                                         base::JSONWriter::OPTIONS_PRETTY_PRINT,
-                                         &info);
+      base::JSONWriter::WriteWithOptions(
+          *value, base::JSONWriter::OPTIONS_PRETTY_PRINT, &info);
       DVLOG(2) << "Encrypting specifics of type "
                << ModelTypeToString(type)
                << " with content: "
diff --git a/sync/test/accounts_client/DEPS b/sync/test/accounts_client/DEPS
deleted file mode 100644
index db6d6e2..0000000
--- a/sync/test/accounts_client/DEPS
+++ /dev/null
@@ -1,5 +0,0 @@
-include_rules = [
-  # Allow this directory to depend on net since it's test infrastructure and
-  # not test cases.
-  "+net",
-]
diff --git a/sync/test/accounts_client/test_accounts_client.cc b/sync/test/accounts_client/test_accounts_client.cc
deleted file mode 100644
index 2856ed2..0000000
--- a/sync/test/accounts_client/test_accounts_client.cc
+++ /dev/null
@@ -1,161 +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.
-
-#include "sync/test/accounts_client/test_accounts_client.h"
-
-#include <algorithm>
-#include <string>
-#include <vector>
-
-#include "base/json/json_reader.h"
-#include "base/json/json_writer.h"
-#include "base/message_loop/message_loop.h"
-#include "base/run_loop.h"
-#include "base/strings/stringprintf.h"
-#include "base/time/time.h"
-#include "base/values.h"
-#include "net/base/url_util.h"
-#include "net/http/http_status_code.h"
-#include "net/url_request/url_fetcher.h"
-#include "net/url_request/url_fetcher_delegate.h"
-#include "net/url_request/url_request.h"
-#include "net/url_request/url_request_context_getter.h"
-#include "sync/test/accounts_client/url_request_context_getter.h"
-
-using std::string;
-using std::vector;
-
-static const int kMaxSessionLifetimeSeconds = 30 * 60;
-static const string kClaimPath = "claim";
-static const string kReleasePath = "release";
-static const base::TimeDelta kRequestTimeout = base::TimeDelta::FromSeconds(10);
-
-AccountSession::AccountSession() {}
-AccountSession::~AccountSession() {}
-
-class AccountsRequestDelegate : public net::URLFetcherDelegate {
- public:
-  AccountsRequestDelegate(base::RunLoop* run_loop) : response_(""),
-      success_(false), run_loop_(run_loop) {}
-
-  void OnURLFetchComplete(const net::URLFetcher* source) override {
-    string url = source->GetURL().spec();
-    source->GetResponseAsString(&response_);
-
-    if (!source->GetStatus().is_success()) {
-      int error = source->GetStatus().error();
-      DVLOG(0) << "The request failed with error code " << error << "."
-               << "\nRequested URL: " << url << ".";
-    } else if (source->GetResponseCode() != net::HTTP_OK) {
-      DVLOG(0) << "The request failed with response code "
-               << source->GetResponseCode() << "."
-               << "\nRequested URL: " << url
-               << "\nResponse body: \"" << response_ << "\"";
-    } else {
-      success_ = true;
-    }
-
-    run_loop_->Quit();
-  }
-
-  string response() const { return response_; }
-  bool success() const { return success_; }
-
- private:
-  string response_;
-  bool success_;
-  base::RunLoop* run_loop_;
-};
-
-TestAccountsClient::TestAccountsClient(const string& server,
-                                       const string& account_space,
-                                       const vector<string>& usernames)
-    : server_(server), account_space_(account_space), usernames_(usernames) {
-}
-
-TestAccountsClient::~TestAccountsClient() {}
-
-bool TestAccountsClient::ClaimAccount(AccountSession* session) {
-  GURL url = CreateGURLWithPath(kClaimPath);
-  url = net::AppendQueryParameter(url, "account_space", account_space_);
-  string max_lifetime_seconds = base::StringPrintf("%d",
-                                                   kMaxSessionLifetimeSeconds);
-  url = net::AppendQueryParameter(url, "max_lifetime_seconds",
-                                  max_lifetime_seconds);
-
-  // TODO(pvalenzuela): Select N random usernames instead of all usernames.
-  for (vector<string>::iterator it = usernames_.begin();
-       it != usernames_.end(); ++it) {
-    url = net::AppendQueryParameter(url, "username", *it);
-  }
-
-  string response;
-  if (!SendRequest(url, &response)) {
-    return false;
-  }
-
-  scoped_ptr<base::Value> value(base::JSONReader::Read(response));
-  base::DictionaryValue* dict_value;
-  if (value != NULL && value->GetAsDictionary(&dict_value) &&
-      dict_value != NULL) {
-    dict_value->GetString("username", &session->username);
-    dict_value->GetString("account_space", &session->account_space);
-    dict_value->GetString("session_id", &session->session_id);
-    dict_value->GetString("expiration_time", &session->expiration_time);
-  } else {
-    return false;
-  }
-
-  return true;
-}
-
-void TestAccountsClient::ReleaseAccount(const AccountSession& session) {
-  // The expiration_time field is ignored since it isn't passed as part of the
-  // release request.
-  if (session.username.empty() || session.account_space.empty() ||
-      account_space_.compare(session.account_space) != 0 ||
-      session.session_id.empty()) {
-    return;
-  }
-
-  GURL url = CreateGURLWithPath(kReleasePath);
-  url = net::AppendQueryParameter(url, "account_space", session.account_space);
-  url = net::AppendQueryParameter(url, "username", session.username);
-  url = net::AppendQueryParameter(url, "session_id", session.session_id);
-
-  // This operation is best effort, so don't send any errors back to the caller.
-  string response;
-  SendRequest(url, &response);
-}
-
-GURL TestAccountsClient::CreateGURLWithPath(const string& path) {
-  return GURL(base::StringPrintf("%s/%s", server_.c_str(), path.c_str()));
-}
-
-
-bool TestAccountsClient::SendRequest(const GURL& url, string* response) {
-  base::MessageLoop* loop = base::MessageLoop::current();
-  scoped_refptr<URLRequestContextGetter> context_getter(
-      new URLRequestContextGetter(loop->message_loop_proxy()));
-
-  base::RunLoop run_loop;
-
-  AccountsRequestDelegate delegate(&run_loop);
-  scoped_ptr<net::URLFetcher> fetcher =
-      net::URLFetcher::Create(url, net::URLFetcher::POST, &delegate);
-  fetcher->SetRequestContext(context_getter.get());
-  fetcher->SetUploadData("application/json", "");
-  fetcher->Start();
-
-  base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
-    run_loop.QuitClosure(),
-    kRequestTimeout);
-  run_loop.Run();
-
-  if (delegate.success()) {
-    *response = delegate.response();
-  }
-
-  return delegate.success();
-}
diff --git a/sync/test/accounts_client/test_accounts_client.h b/sync/test/accounts_client/test_accounts_client.h
deleted file mode 100644
index 15a582e..0000000
--- a/sync/test/accounts_client/test_accounts_client.h
+++ /dev/null
@@ -1,63 +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.
-
-#ifndef SYNC_TEST_ACCOUNTS_CLIENT_TEST_ACCOUNTS_CLIENT_H_
-#define SYNC_TEST_ACCOUNTS_CLIENT_TEST_ACCOUNTS_CLIENT_H_
-
-#include <string>
-#include <vector>
-
-#include "base/message_loop/message_loop.h"
-#include "url/gurl.h"
-
-using std::string;
-using std::vector;
-
-// The data associated with an account session.
-struct AccountSession {
-  AccountSession();
-  ~AccountSession();
-
-  string username;
-  string account_space;
-  string session_id;
-  string expiration_time;
-};
-
-// A test-side client for the Test Accounts service. This service provides
-// short-term, exclusive access to test accounts for the purpose of testing
-// against real Chrome Sync servers.
-class TestAccountsClient {
- public:
-  // Creates a client associated with the given |server| URL (e.g.,
-  // http://service-runs-here.com), |account_space| (for account segregation),
-  // and |usernames| (the collection of accounts to be chosen from).
-  TestAccountsClient(const string& server,
-                     const string& account_space,
-                     const vector<string>& usernames);
-
-  virtual ~TestAccountsClient();
-
-  // Attempts to claim an account via the Test Accounts service. If
-  // successful, true is returned and the given |session| has its data set.
-  // If an error occurred, then false is returned.
-  bool ClaimAccount(AccountSession* session);
-
-  // Attempts to release an account via the Test Accounts service. The value
-  // of |session| should be one returned from ClaimAccount(). This function
-  // is best-effort and fails silently.
-  void ReleaseAccount(const AccountSession& session);
-
-  // Sends an HTTP POST request to the Test Accounts service.
-  virtual bool SendRequest(const GURL& url, string* response);
-
- private:
-  GURL CreateGURLWithPath(const string& path);
-  base::MessageLoopForIO io_loop_;
-  const string server_;
-  const string account_space_;
-  vector<string> usernames_;
-};
-
-#endif  // SYNC_TEST_ACCOUNTS_CLIENT_TEST_ACCOUNTS_CLIENT_H_
diff --git a/sync/test/accounts_client/test_accounts_client_unittest.cc b/sync/test/accounts_client/test_accounts_client_unittest.cc
deleted file mode 100644
index f73a43b..0000000
--- a/sync/test/accounts_client/test_accounts_client_unittest.cc
+++ /dev/null
@@ -1,98 +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.
-
-#include <vector>
-
-#include "base/json/json_writer.h"
-#include "base/values.h"
-#include "sync/test/accounts_client/test_accounts_client.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "url/gurl.h"
-
-using std::string;
-using std::vector;
-using testing::_;
-using testing::DoAll;
-using testing::Return;
-using testing::SetArgPointee;
-
-namespace {
-static const string kServer = "https://test-account-service";
-static const string kUsername = "foobar@baz.com";
-static const string kAccountSpace = "test_account_space";
-static const string kSessionId = "1234-ABCD";
-static const string kExpirationTime = "12:00";
-} // namespace
-
-static AccountSession CreateValidAccountSession() {
-  AccountSession session;
-  session.username = kUsername;
-  session.account_space = kAccountSpace;
-  session.session_id = kSessionId;
-  session.expiration_time = kExpirationTime;
-  return session;
-}
-
-class NoNetworkTestAccountsClient : public TestAccountsClient {
- public:
-  NoNetworkTestAccountsClient(const string& server,
-                              const string& account_space,
-                              vector<string> usernames)
-      : TestAccountsClient(server, account_space, usernames) {}
-  MOCK_METHOD2(SendRequest, bool(const GURL&, string*));
-};
-
-TEST(TestAccountsClientTest, ClaimAccountError) {
-  vector<string> usernames;
-  NoNetworkTestAccountsClient client(kServer, kAccountSpace, usernames);
-  EXPECT_CALL(client, SendRequest(_, _))
-      .WillOnce(Return(false));
-  AccountSession session;
-  EXPECT_FALSE(client.ClaimAccount(&session));
-}
-
-TEST(TestAccountsClientTest, ClaimAccountSuccess) {
-  vector<string> usernames;
-  usernames.push_back("foo0@gmail.com");
-  usernames.push_back("foo1@gmail.com");
-  usernames.push_back("foo2@gmail.com");
-  NoNetworkTestAccountsClient client(kServer, kAccountSpace, usernames);
-
-  base::DictionaryValue success_dict;
-  success_dict.Set("username", new base::StringValue(kUsername));
-  success_dict.Set("account_space", new base::StringValue(kAccountSpace));
-  success_dict.Set("session_id", new base::StringValue(kSessionId));
-  success_dict.Set("expiration_time", new base::StringValue(kExpirationTime));
-
-  string success_response;
-  base::JSONWriter::Write(&success_dict, &success_response);
-  EXPECT_CALL(client, SendRequest(_, _))
-      .WillOnce(DoAll(SetArgPointee<1>(success_response), Return(true)));
-
-  AccountSession session;
-  EXPECT_TRUE(client.ClaimAccount(&session));
-  EXPECT_EQ(kUsername, session.username);
-  EXPECT_EQ(kAccountSpace, session.account_space);
-  EXPECT_EQ(kSessionId, session.session_id);
-  EXPECT_EQ(kExpirationTime, session.expiration_time);
-}
-
-TEST(TestAccountsClientTest, ReleaseAccountEmptySession) {
-  vector<string> usernames;
-  NoNetworkTestAccountsClient client(kServer, kAccountSpace, usernames);
-  AccountSession session;
-  // No expectation for SendRequest is made because no network call should be
-  // performed in this scenario.
-  client.ReleaseAccount(session);
-}
-
-TEST(TestAccountsClientTest, ReleaseAccountSuccess) {
-  vector<string> usernames;
-  NoNetworkTestAccountsClient client(kServer, kAccountSpace, usernames);
-  EXPECT_CALL(client, SendRequest(_, _))
-      .WillOnce(Return(true));
-  AccountSession session = CreateValidAccountSession();
-  client.ReleaseAccount(session);
-}
diff --git a/sync/test/accounts_client/url_request_context_getter.cc b/sync/test/accounts_client/url_request_context_getter.cc
deleted file mode 100644
index 11e1cc2..0000000
--- a/sync/test/accounts_client/url_request_context_getter.cc
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright (c) 2012 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 "sync/test/accounts_client/url_request_context_getter.h"
-
-#include <string>
-
-#include "net/proxy/proxy_config_service_fixed.h"
-#include "net/url_request/url_request_context.h"
-#include "net/url_request/url_request_context_builder.h"
-
-URLRequestContextGetter::URLRequestContextGetter(
-    scoped_refptr<base::SingleThreadTaskRunner> network_task_runner)
-    : network_task_runner_(network_task_runner) {
-}
-
-net::URLRequestContext* URLRequestContextGetter::GetURLRequestContext() {
-  CHECK(network_task_runner_->BelongsToCurrentThread());
-  if (!url_request_context_) {
-    net::URLRequestContextBuilder builder;
-    // net::HttpServer fails to parse headers if user-agent header is blank.
-    builder.set_user_agent("sync-test-accounts-client");
-    builder.DisableHttpCache();
-#if defined(OS_LINUX) || defined(OS_ANDROID)
-    builder.set_proxy_config_service(
-        new net::ProxyConfigServiceFixed(net::ProxyConfig::CreateDirect()));
-#endif
-    url_request_context_.reset(builder.Build());
-  }
-  return url_request_context_.get();
-}
-
-scoped_refptr<base::SingleThreadTaskRunner>
-    URLRequestContextGetter::GetNetworkTaskRunner() const {
-  return network_task_runner_;
-}
-
-URLRequestContextGetter::~URLRequestContextGetter() {}
diff --git a/sync/test/accounts_client/url_request_context_getter.h b/sync/test/accounts_client/url_request_context_getter.h
deleted file mode 100644
index 20a3931..0000000
--- a/sync/test/accounts_client/url_request_context_getter.h
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright (c) 2012 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 SYNC_TEST_ACCOUNTS_CLIENT_URL_REQUEST_CONTEXT_GETTER_H_
-#define SYNC_TEST_ACCOUNTS_CLIENT_URL_REQUEST_CONTEXT_GETTER_H_
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
-#include "net/url_request/url_request_context_getter.h"
-
-namespace base {
-class SingleThreadTaskRunner;
-}
-
-namespace net {
-class URLRequestContext;
-}
-
-class URLRequestContextGetter : public net::URLRequestContextGetter {
- public:
-  explicit URLRequestContextGetter(
-      scoped_refptr<base::SingleThreadTaskRunner> network_task_runner);
-
-  // Overridden from net::URLRequestContextGetter:
-  net::URLRequestContext* GetURLRequestContext() override;
-  scoped_refptr<base::SingleThreadTaskRunner> GetNetworkTaskRunner()
-      const override;
-
- private:
-  ~URLRequestContextGetter() override;
-
-  scoped_refptr<base::SingleThreadTaskRunner> network_task_runner_;
-
-  // Only accessed on the IO thread.
-  scoped_ptr<net::URLRequestContext> url_request_context_;
-
-  DISALLOW_COPY_AND_ASSIGN(URLRequestContextGetter);
-};
-
-#endif  // SYNC_TEST_ACCOUNTS_CLIENT_URL_REQUEST_CONTEXT_GETTER_H_
diff --git a/sync/test/fake_server/fake_server_verifier.cc b/sync/test/fake_server/fake_server_verifier.cc
index bc64550..b968d0f 100644
--- a/sync/test/fake_server/fake_server_verifier.cc
+++ b/sync/test/fake_server/fake_server_verifier.cc
@@ -53,8 +53,7 @@
 string ConvertFakeServerContentsToString(
     const base::DictionaryValue& entities) {
   string entities_str;
-  if (!JSONWriter::WriteWithOptions(&entities,
-                                    JSONWriter::OPTIONS_PRETTY_PRINT,
+  if (!JSONWriter::WriteWithOptions(entities, JSONWriter::OPTIONS_PRETTY_PRINT,
                                     &entities_str)) {
     entities_str = "Could not convert FakeServer contents to string.";
   }
diff --git a/sync/tools/sync_client.cc b/sync/tools/sync_client.cc
index 8422d2e..1106460 100644
--- a/sync/tools/sync_client.cc
+++ b/sync/tools/sync_client.cc
@@ -122,7 +122,7 @@
 
 std::string ValueToString(const base::Value& value) {
   std::string str;
-  base::JSONWriter::Write(&value, &str);
+  base::JSONWriter::Write(value, &str);
   return str;
 }
 
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index 670524f70..5596e6b 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -17,64 +17,6 @@
       }
     ]
   },
-  "Cast Linux": {
-    "gtest_tests": [
-      {
-        "test": "base_unittests"
-      },
-      {
-        "test": "cacheinvalidation_unittests"
-      },
-      {
-        "test": "cast_base_unittests"
-      },
-      {
-        "test": "cast_media_unittests"
-      },
-      {
-        "test": "cast_shell_browser_test"
-      },
-      {
-        "test": "content_unittests"
-      },
-      {
-        "test": "crypto_unittests"
-      },
-      {
-        "test": "gpu_unittests"
-      },
-      {
-        "test": "ipc_tests"
-      },
-      {
-        "test": "jingle_unittests"
-      },
-      {
-        "test": "media_unittests"
-      },
-      {
-        "test": "midi_unittests"
-      },
-      {
-        "test": "net_unittests"
-      },
-      {
-        "test": "sandbox_linux_unittests"
-      },
-      {
-        "test": "sql_unittests"
-      },
-      {
-        "test": "sync_unit_tests"
-      },
-      {
-        "test": "ui_base_unittests"
-      },
-      {
-        "test": "url_unittests"
-      }
-    ]
-  },
   "Chromium Mac 10.10": {
     "gtest_tests": [
       {
diff --git a/testing/buildbot/chromium.linux.json b/testing/buildbot/chromium.linux.json
index c18aece..f0cfa3b 100644
--- a/testing/buildbot/chromium.linux.json
+++ b/testing/buildbot/chromium.linux.json
@@ -35,6 +35,64 @@
       }
     ]
   },
+  "Cast Linux": {
+    "gtest_tests": [
+      {
+        "test": "base_unittests"
+      },
+      {
+        "test": "cacheinvalidation_unittests"
+      },
+      {
+        "test": "cast_base_unittests"
+      },
+      {
+        "test": "cast_media_unittests"
+      },
+      {
+        "test": "cast_shell_browser_test"
+      },
+      {
+        "test": "content_unittests"
+      },
+      {
+        "test": "crypto_unittests"
+      },
+      {
+        "test": "gpu_unittests"
+      },
+      {
+        "test": "ipc_tests"
+      },
+      {
+        "test": "jingle_unittests"
+      },
+      {
+        "test": "media_unittests"
+      },
+      {
+        "test": "midi_unittests"
+      },
+      {
+        "test": "net_unittests"
+      },
+      {
+        "test": "sandbox_linux_unittests"
+      },
+      {
+        "test": "sql_unittests"
+      },
+      {
+        "test": "sync_unit_tests"
+      },
+      {
+        "test": "ui_base_unittests"
+      },
+      {
+        "test": "url_unittests"
+      }
+    ]
+  },
   "Linux Clang (dbg)": {
     "gtest_tests": [
       {
diff --git a/third_party/boringssl/BUILD.gn b/third_party/boringssl/BUILD.gn
index cd398de..8ce890d 100644
--- a/third_party/boringssl/BUILD.gn
+++ b/third_party/boringssl/BUILD.gn
@@ -25,7 +25,7 @@
 
 # Windows' assembly is built with Yasm. The other platforms use the platform
 # assembler.
-if (is_win) {
+if (is_win && !is_msan) {
   import("//third_party/yasm/yasm_assemble.gni")
   yasm_assemble("boringssl_asm") {
     if (current_cpu == "x64") {
@@ -70,7 +70,9 @@
     "src/crypto",
   ]
 
-  if (current_cpu == "x64") {
+  if (is_msan) {
+    defines += [ "OPENSSL_NO_ASM" ]
+  } else if (current_cpu == "x64") {
     if (is_mac || is_ios) {
       sources += gypi_values.boringssl_mac_x86_64_sources
     } else if (is_linux || is_android) {
diff --git a/third_party/boringssl/boringssl.gyp b/third_party/boringssl/boringssl.gyp
index f3a169d5..3079d0b6 100644
--- a/third_party/boringssl/boringssl.gyp
+++ b/third_party/boringssl/boringssl.gyp
@@ -26,7 +26,7 @@
             'BORINGSSL_SHARED_LIBRARY',
           ],
         }],
-        ['target_arch == "arm"', {
+        ['target_arch == "arm" and msan == 0', {
           'conditions': [
             ['OS == "linux" or OS == "android"', {
               'sources': [ '<@(boringssl_linux_arm_sources)' ],
@@ -35,7 +35,7 @@
             }],
           ],
         }],
-        ['target_arch == "arm64"', {
+        ['target_arch == "arm64" and msan == 0', {
           'conditions': [
             ['OS == "linux" or OS == "android"', {
               'sources': [ '<@(boringssl_linux_aarch64_sources)' ],
@@ -44,7 +44,7 @@
             }],
           ],
         }],
-        ['target_arch == "ia32"', {
+        ['target_arch == "ia32" and msan == 0', {
           'conditions': [
             ['OS == "mac" or OS == "ios"', {
               'sources': [ '<@(boringssl_mac_x86_sources)' ],
@@ -68,7 +68,7 @@
             }],
           ]
         }],
-        ['target_arch == "x64"', {
+        ['target_arch == "x64" and msan == 0', {
           'conditions': [
             ['OS == "mac" or OS == "ios"', {
               'sources': [ '<@(boringssl_mac_x86_64_sources)' ],
@@ -92,7 +92,7 @@
             }],
           ]
         }],
-        ['target_arch != "arm" and target_arch != "ia32" and target_arch != "x64" and target_arch != "arm64"', {
+        ['msan == 1 or (target_arch != "arm" and target_arch != "ia32" and target_arch != "x64" and target_arch != "arm64")', {
           'defines': [ 'OPENSSL_NO_ASM' ],
         }],
       ],
diff --git a/third_party/boringssl/boringssl_tests.gypi b/third_party/boringssl/boringssl_tests.gypi
index cec67805..58dc9ad 100644
--- a/third_party/boringssl/boringssl_tests.gypi
+++ b/third_party/boringssl/boringssl_tests.gypi
@@ -83,7 +83,7 @@
         'boringssl.gyp:boringssl',
       ],
       'sources': [
-        'src/crypto/cipher/cipher_test.c',
+        'src/crypto/cipher/cipher_test.cc',
         '<@(boringssl_test_support_sources)',
       ],
       # TODO(davidben): Fix size_t truncations in BoringSSL.
diff --git a/third_party/boringssl/err_data.c b/third_party/boringssl/err_data.c
index 68397e4bb..f09b1c2 100644
--- a/third_party/boringssl/err_data.c
+++ b/third_party/boringssl/err_data.c
@@ -79,202 +79,202 @@
     0xc3d0679,
     0xc3d8681,
     0xc3e068c,
-    0x103218ee,
-    0x10329905,
-    0x1033191e,
-    0x10339934,
-    0x10341944,
-    0x10349957,
-    0x10351965,
-    0x10359974,
-    0x10361994,
-    0x103699b3,
-    0x103719d0,
-    0x103799ed,
-    0x10381a02,
-    0x10389a24,
-    0x10391a43,
-    0x10399a62,
-    0x103a1a79,
-    0x103a9a90,
-    0x103b1a99,
-    0x103b9aa4,
-    0x103c1abe,
-    0x103c9ac6,
-    0x103d1ace,
-    0x103d9ad5,
-    0x103e1ae8,
-    0x103e9afa,
-    0x103f1b0d,
-    0x103f9b16,
+    0x1032191e,
+    0x10329935,
+    0x1033194e,
+    0x10339964,
+    0x10341974,
+    0x10349987,
+    0x10351995,
+    0x103599a4,
+    0x103619c4,
+    0x103699e3,
+    0x10371a00,
+    0x10379a1d,
+    0x10381a32,
+    0x10389a54,
+    0x10391a73,
+    0x10399a92,
+    0x103a1aa9,
+    0x103a9ac0,
+    0x103b1ac9,
+    0x103b9ad4,
+    0x103c1aee,
+    0x103c9af6,
+    0x103d1afe,
+    0x103d9b05,
+    0x103e1b18,
+    0x103e9b2a,
+    0x103f1b3d,
+    0x103f9b46,
     0x14320a2f,
     0x14328a3d,
     0x14330a49,
     0x14338a56,
-    0x183611d5,
-    0x18371203,
-    0x18379214,
-    0x1838122a,
-    0x1839124d,
-    0x18399262,
-    0x183a1274,
-    0x183c12b8,
-    0x183c92c6,
-    0x183d12d9,
-    0x183d92e9,
-    0x183e930f,
-    0x183f1322,
-    0x183f9331,
-    0x1840935b,
-    0x184113c7,
-    0x184193d8,
-    0x184213eb,
-    0x184293fd,
-    0x1843140f,
-    0x18439420,
-    0x18441431,
-    0x18449442,
-    0x18451453,
-    0x18459460,
-    0x18461482,
-    0x18469495,
-    0x184714a9,
-    0x184794b6,
-    0x184814c5,
-    0x184894d4,
-    0x184914e5,
-    0x18499501,
-    0x184a150f,
-    0x184a9520,
-    0x184b1531,
-    0x184b953f,
-    0x184c154f,
-    0x184c9575,
-    0x184d1584,
-    0x184d9594,
-    0x184e15a4,
-    0x184e95b3,
-    0x184f14f2,
-    0x184f9164,
-    0x18501107,
-    0x1850911f,
-    0x18511141,
-    0x18519153,
-    0x18521185,
-    0x1852919e,
-    0x185311af,
-    0x185391c5,
-    0x185411ea,
-    0x1854923b,
-    0x18551284,
-    0x18559299,
-    0x185612a6,
-    0x185692fe,
-    0x18571341,
-    0x1857934e,
-    0x1858136a,
-    0x1858937b,
-    0x1859138b,
-    0x1859939b,
-    0x185a13aa,
-    0x185a93b9,
-    0x185b146e,
+    0x18361205,
+    0x18371233,
+    0x18379244,
+    0x1838125a,
+    0x1839127d,
+    0x18399292,
+    0x183a12a4,
+    0x183c12e8,
+    0x183c92f6,
+    0x183d1309,
+    0x183d9319,
+    0x183e933f,
+    0x183f1352,
+    0x183f9361,
+    0x1840938b,
+    0x184113f7,
+    0x18419408,
+    0x1842141b,
+    0x1842942d,
+    0x1843143f,
+    0x18439450,
+    0x18441461,
+    0x18449472,
+    0x18451483,
+    0x18459490,
+    0x184614b2,
+    0x184694c5,
+    0x184714d9,
+    0x184794e6,
+    0x184814f5,
+    0x18489504,
+    0x18491515,
+    0x18499531,
+    0x184a153f,
+    0x184a9550,
+    0x184b1561,
+    0x184b956f,
+    0x184c157f,
+    0x184c95a5,
+    0x184d15b4,
+    0x184d95c4,
+    0x184e15d4,
+    0x184e95e3,
+    0x184f1522,
+    0x184f9194,
+    0x18501137,
+    0x1850914f,
+    0x18511171,
+    0x18519183,
+    0x185211b5,
+    0x185291ce,
+    0x185311df,
+    0x185391f5,
+    0x1854121a,
+    0x1854926b,
+    0x185512b4,
+    0x185592c9,
+    0x185612d6,
+    0x1856932e,
+    0x18571371,
+    0x1857937e,
+    0x1858139a,
+    0x185893ab,
+    0x185913bb,
+    0x185993cb,
+    0x185a13da,
+    0x185a93e9,
+    0x185b149e,
     0x1c320699,
     0x1c3286a5,
     0x1c3306b0,
     0x1c3386bc,
-    0x203215c7,
-    0x203295d2,
-    0x203315da,
-    0x203395e6,
-    0x243215f2,
-    0x24329600,
-    0x24331612,
-    0x24339621,
-    0x24341634,
-    0x24349647,
-    0x2435165e,
-    0x24359676,
-    0x24361684,
-    0x2436969c,
-    0x243716a5,
-    0x243796b7,
-    0x243816cb,
-    0x243896d8,
-    0x243916ee,
-    0x24399706,
-    0x243a171e,
-    0x243a9728,
-    0x243b173d,
-    0x243b974b,
-    0x243c1763,
-    0x243c977a,
-    0x243d1785,
-    0x243d9793,
+    0x203215f7,
+    0x20329602,
+    0x2033160a,
+    0x20339616,
+    0x24321622,
+    0x24329630,
+    0x24331642,
+    0x24339651,
+    0x24341664,
+    0x24349677,
+    0x2435168e,
+    0x243596a6,
+    0x243616b4,
+    0x243696cc,
+    0x243716d5,
+    0x243796e7,
+    0x243816fb,
+    0x24389708,
+    0x2439171e,
+    0x24399736,
+    0x243a174e,
+    0x243a9758,
+    0x243b176d,
+    0x243b977b,
+    0x243c1793,
+    0x243c97aa,
+    0x243d17b5,
+    0x243d97c3,
     0x28320a8f,
     0x28328a9e,
     0x28330aa9,
     0x28338aae,
     0x28340ab9,
-    0x2c322a70,
-    0x2c32aa7c,
-    0x2c332a8f,
-    0x2c33aaa0,
-    0x2c342ab9,
-    0x2c34aae1,
-    0x2c352af8,
-    0x2c35ab15,
-    0x2c362b32,
-    0x2c36ab4f,
-    0x2c372b68,
-    0x2c37ab81,
-    0x2c382b97,
-    0x2c38aba5,
-    0x2c392bb7,
-    0x2c39abd4,
-    0x2c3a2bf1,
-    0x2c3aabff,
-    0x2c3b2c1d,
-    0x2c3bac3b,
-    0x2c3c2c56,
-    0x2c3cac6a,
-    0x2c3d2c7c,
-    0x2c3dac8c,
-    0x2c3e2c9a,
-    0x2c3eacaa,
-    0x2c3f2cba,
-    0x2c3facd5,
-    0x2c402ce6,
-    0x2c40ad01,
-    0x2c412d15,
-    0x2c41ad28,
-    0x2c422d47,
-    0x2c42ad5b,
-    0x2c432d6e,
-    0x2c43ad7d,
-    0x2c442d8c,
-    0x2c44ada3,
-    0x2c452dbe,
-    0x2c45add6,
-    0x2c462dea,
-    0x2c46adfd,
-    0x2c472e0e,
-    0x2c47ae1f,
-    0x2c482e30,
-    0x2c48ae41,
-    0x2c492e50,
-    0x2c49ae5d,
-    0x2c4a2e6a,
-    0x2c4aae77,
-    0x2c4b2e80,
-    0x2c4bae94,
-    0x2c4c2ea3,
-    0x2c4caeb1,
-    0x2c4d2ed3,
-    0x2c4daee4,
-    0x2c4e2ef5,
-    0x2c4eaec0,
-    0x2c4f2ad2,
+    0x2c322aa0,
+    0x2c32aaac,
+    0x2c332abf,
+    0x2c33aad0,
+    0x2c342ae9,
+    0x2c34ab11,
+    0x2c352b28,
+    0x2c35ab45,
+    0x2c362b62,
+    0x2c36ab7f,
+    0x2c372b98,
+    0x2c37abb1,
+    0x2c382bc7,
+    0x2c38abd5,
+    0x2c392be7,
+    0x2c39ac04,
+    0x2c3a2c21,
+    0x2c3aac2f,
+    0x2c3b2c4d,
+    0x2c3bac6b,
+    0x2c3c2c86,
+    0x2c3cac9a,
+    0x2c3d2cac,
+    0x2c3dacbc,
+    0x2c3e2cca,
+    0x2c3eacda,
+    0x2c3f2cea,
+    0x2c3fad05,
+    0x2c402d16,
+    0x2c40ad31,
+    0x2c412d45,
+    0x2c41ad58,
+    0x2c422d77,
+    0x2c42ad8b,
+    0x2c432d9e,
+    0x2c43adad,
+    0x2c442dbc,
+    0x2c44add3,
+    0x2c452dee,
+    0x2c45ae06,
+    0x2c462e1a,
+    0x2c46ae2d,
+    0x2c472e3e,
+    0x2c47ae4f,
+    0x2c482e60,
+    0x2c48ae71,
+    0x2c492e80,
+    0x2c49ae8d,
+    0x2c4a2e9a,
+    0x2c4aaea7,
+    0x2c4b2eb0,
+    0x2c4baec4,
+    0x2c4c2ed3,
+    0x2c4caee1,
+    0x2c4d2f03,
+    0x2c4daf14,
+    0x2c4e2f25,
+    0x2c4eaef0,
+    0x2c4f2b02,
     0x30320000,
     0x30328018,
     0x3033002c,
@@ -351,239 +351,241 @@
     0x3c328ada,
     0x3c330af1,
     0x3c338b05,
-    0x3c340b20,
-    0x3c348b31,
-    0x3c350b3d,
-    0x3c358b51,
-    0x3c360b63,
-    0x3c368b8c,
-    0x3c370b99,
-    0x3c378ba6,
-    0x3c380bb4,
-    0x3c388bc1,
-    0x3c390bce,
-    0x3c398bf2,
-    0x3c3a0c02,
-    0x3c3a8c1a,
-    0x3c3b0c2f,
-    0x3c3b8c44,
-    0x3c3c0c51,
-    0x3c3c8c64,
-    0x3c3d0c77,
-    0x3c3d8c9b,
-    0x3c3e0cc3,
-    0x3c3e8cdc,
-    0x3c3f0cf2,
-    0x3c3f8cff,
-    0x3c400d12,
-    0x3c408d23,
-    0x3c410d34,
-    0x3c418d4d,
-    0x3c420d66,
-    0x3c428d7c,
-    0x3c430d99,
-    0x3c438daf,
-    0x3c440e33,
-    0x3c448e5a,
-    0x3c450e78,
-    0x3c458e92,
-    0x3c460eaa,
-    0x3c468ec2,
-    0x3c470eed,
-    0x3c478f18,
-    0x3c480f39,
-    0x3c488f62,
-    0x3c490f7d,
-    0x3c498fa6,
-    0x3c4a0fb3,
-    0x3c4a8fca,
-    0x3c4b0fe1,
-    0x3c4b900a,
-    0x3c4c101a,
-    0x3c4c9026,
-    0x3c4d103e,
-    0x3c4d9051,
-    0x3c4e1062,
-    0x3c4e9073,
-    0x3c4f1099,
+    0x3c340b37,
+    0x3c348b48,
+    0x3c350b54,
+    0x3c358b81,
+    0x3c360b93,
+    0x3c368bbc,
+    0x3c370bc9,
+    0x3c378bd6,
+    0x3c380be4,
+    0x3c388bf1,
+    0x3c390bfe,
+    0x3c398c22,
+    0x3c3a0c32,
+    0x3c3a8c4a,
+    0x3c3b0c5f,
+    0x3c3b8c74,
+    0x3c3c0c81,
+    0x3c3c8c94,
+    0x3c3d0ca7,
+    0x3c3d8ccb,
+    0x3c3e0cf3,
+    0x3c3e8d0c,
+    0x3c3f0d22,
+    0x3c3f8d2f,
+    0x3c400d42,
+    0x3c408d53,
+    0x3c410d64,
+    0x3c418d7d,
+    0x3c420d96,
+    0x3c428dac,
+    0x3c430dc9,
+    0x3c438ddf,
+    0x3c440e63,
+    0x3c448e8a,
+    0x3c450ea8,
+    0x3c458ec2,
+    0x3c460eda,
+    0x3c468ef2,
+    0x3c470f1d,
+    0x3c478f48,
+    0x3c480f69,
+    0x3c488f92,
+    0x3c490fad,
+    0x3c498fd6,
+    0x3c4a0fe3,
+    0x3c4a8ffa,
+    0x3c4b1011,
+    0x3c4b903a,
+    0x3c4c104a,
+    0x3c4c9056,
+    0x3c4d106e,
+    0x3c4d9081,
+    0x3c4e1092,
+    0x3c4e90a3,
+    0x3c4f10c9,
     0x3c4f8ac0,
-    0x3c500dcb,
-    0x3c508deb,
-    0x3c510e18,
-    0x3c518f98,
-    0x3c521083,
-    0x40321b21,
-    0x40329b3b,
-    0x40331b63,
-    0x40339b7b,
-    0x40341b99,
-    0x40349be0,
-    0x40351bf7,
-    0x40359c13,
-    0x40361c2f,
-    0x40369c49,
-    0x40371c68,
-    0x40379c87,
-    0x40381c9f,
-    0x40389cbc,
-    0x40391cdf,
-    0x40399cfc,
-    0x403a1d1a,
-    0x403a9d2a,
-    0x403b1d3f,
-    0x403b9d5b,
-    0x403c1d75,
-    0x403c9d80,
-    0x403d1da3,
-    0x403d9dc7,
-    0x403e1ddd,
-    0x403e9de7,
-    0x403f1df3,
-    0x403f9e04,
-    0x40401e1c,
-    0x40409e24,
-    0x40411e2d,
-    0x40419e36,
-    0x40421e5e,
-    0x40429e72,
-    0x40431e7d,
-    0x40439e89,
-    0x40441edd,
-    0x40449ee9,
-    0x40451ef6,
-    0x40459f09,
-    0x40461f21,
-    0x40469f39,
-    0x40471f4f,
-    0x40479f6a,
-    0x40481f85,
-    0x40489f99,
-    0x40491fb2,
-    0x40499fcb,
-    0x404a1fe5,
-    0x404a9fef,
-    0x404b1fff,
-    0x404ba020,
-    0x404c203b,
-    0x404ca049,
-    0x404d2056,
-    0x404da06a,
-    0x404e2082,
-    0x404ea090,
-    0x404f20ba,
-    0x404fa0d1,
-    0x405020e3,
-    0x4050a114,
-    0x40512145,
-    0x4051a15a,
-    0x4052216b,
-    0x4052a18b,
-    0x405321a6,
-    0x4053a1b6,
-    0x4054a1c2,
-    0x405521d8,
-    0x4055a1f6,
-    0x40562203,
-    0x4056a20d,
-    0x4057221b,
-    0x4057a236,
-    0x40582251,
-    0x4058a270,
-    0x40592285,
-    0x4059a29a,
-    0x405a22b7,
-    0x405aa2cb,
-    0x405b22e7,
-    0x405ba2fd,
-    0x405c231a,
-    0x405ca32c,
-    0x405d2343,
-    0x405da354,
-    0x405e2370,
-    0x405ea384,
-    0x405f2394,
-    0x405fa3b0,
-    0x406023c5,
-    0x4060a3db,
-    0x406123f8,
-    0x4061a411,
-    0x4062243b,
-    0x4062a444,
-    0x40632454,
-    0x4063a48d,
-    0x406424a3,
-    0x4064a4c1,
-    0x406524d6,
-    0x4065a4f3,
-    0x4066250a,
-    0x4066a528,
-    0x40672545,
-    0x4067a55c,
-    0x4068257a,
-    0x4068a591,
-    0x406925a9,
-    0x4069a5ba,
-    0x406a25cd,
-    0x406aa5e0,
-    0x406b25f4,
-    0x406ba618,
-    0x406c2633,
-    0x406ca654,
-    0x406d2678,
-    0x406da693,
-    0x406e26b4,
-    0x406ea6c9,
-    0x406f26e2,
-    0x406fa6ef,
-    0x407026fd,
-    0x4070a70a,
-    0x40712727,
-    0x4071a747,
-    0x40722762,
-    0x4072a77b,
-    0x40732792,
-    0x4073a7ac,
-    0x407427d0,
-    0x4074a7e6,
-    0x407527fa,
-    0x4075a80f,
-    0x40762829,
-    0x4076a83b,
-    0x40772850,
-    0x4077a876,
-    0x40782893,
-    0x4078a8b6,
-    0x407928dc,
-    0x4079a8f9,
-    0x407a291c,
-    0x407aa938,
-    0x407b2954,
-    0x407ba966,
-    0x407c2973,
-    0x407e2980,
-    0x407ea996,
-    0x407f29ae,
-    0x407fa9c1,
-    0x408029d6,
-    0x4080a9ef,
-    0x40812a0d,
-    0x4081aa2d,
-    0x40822a36,
-    0x4082aa52,
-    0x40832a5b,
-    0x4083a09f,
-    0x4084212e,
-    0x4084a0fe,
-    0x4085247c,
-    0x4085a460,
-    0x40861bb8,
-    0x40869bcb,
-    0x40871ebd,
-    0x40879ecc,
-    0x40881b47,
-    0x40889e46,
-    0x40891ea4,
-    0x4089a424,
+    0x3c500dfb,
+    0x3c508e1b,
+    0x3c510e48,
+    0x3c518fc8,
+    0x3c5210b3,
+    0x3c528b68,
+    0x3c530b20,
+    0x40321b51,
+    0x40329b6b,
+    0x40331b93,
+    0x40339bab,
+    0x40341bc9,
+    0x40349c10,
+    0x40351c27,
+    0x40359c43,
+    0x40361c5f,
+    0x40369c79,
+    0x40371c98,
+    0x40379cb7,
+    0x40381ccf,
+    0x40389cec,
+    0x40391d0f,
+    0x40399d2c,
+    0x403a1d4a,
+    0x403a9d5a,
+    0x403b1d6f,
+    0x403b9d8b,
+    0x403c1da5,
+    0x403c9db0,
+    0x403d1dd3,
+    0x403d9df7,
+    0x403e1e0d,
+    0x403e9e17,
+    0x403f1e23,
+    0x403f9e34,
+    0x40401e4c,
+    0x40409e54,
+    0x40411e5d,
+    0x40419e66,
+    0x40421e8e,
+    0x40429ea2,
+    0x40431ead,
+    0x40439eb9,
+    0x40441f0d,
+    0x40449f19,
+    0x40451f26,
+    0x40459f39,
+    0x40461f51,
+    0x40469f69,
+    0x40471f7f,
+    0x40479f9a,
+    0x40481fb5,
+    0x40489fc9,
+    0x40491fe2,
+    0x40499ffb,
+    0x404a2015,
+    0x404aa01f,
+    0x404b202f,
+    0x404ba050,
+    0x404c206b,
+    0x404ca079,
+    0x404d2086,
+    0x404da09a,
+    0x404e20b2,
+    0x404ea0c0,
+    0x404f20ea,
+    0x404fa101,
+    0x40502113,
+    0x4050a144,
+    0x40512175,
+    0x4051a18a,
+    0x4052219b,
+    0x4052a1bb,
+    0x405321d6,
+    0x4053a1e6,
+    0x4054a1f2,
+    0x40552208,
+    0x4055a226,
+    0x40562233,
+    0x4056a23d,
+    0x4057224b,
+    0x4057a266,
+    0x40582281,
+    0x4058a2a0,
+    0x405922b5,
+    0x4059a2ca,
+    0x405a22e7,
+    0x405aa2fb,
+    0x405b2317,
+    0x405ba32d,
+    0x405c234a,
+    0x405ca35c,
+    0x405d2373,
+    0x405da384,
+    0x405e23a0,
+    0x405ea3b4,
+    0x405f23c4,
+    0x405fa3e0,
+    0x406023f5,
+    0x4060a40b,
+    0x40612428,
+    0x4061a441,
+    0x4062246b,
+    0x4062a474,
+    0x40632484,
+    0x4063a4bd,
+    0x406424d3,
+    0x4064a4f1,
+    0x40652506,
+    0x4065a523,
+    0x4066253a,
+    0x4066a558,
+    0x40672575,
+    0x4067a58c,
+    0x406825aa,
+    0x4068a5c1,
+    0x406925d9,
+    0x4069a5ea,
+    0x406a25fd,
+    0x406aa610,
+    0x406b2624,
+    0x406ba648,
+    0x406c2663,
+    0x406ca684,
+    0x406d26a8,
+    0x406da6c3,
+    0x406e26e4,
+    0x406ea6f9,
+    0x406f2712,
+    0x406fa71f,
+    0x4070272d,
+    0x4070a73a,
+    0x40712757,
+    0x4071a777,
+    0x40722792,
+    0x4072a7ab,
+    0x407327c2,
+    0x4073a7dc,
+    0x40742800,
+    0x4074a816,
+    0x4075282a,
+    0x4075a83f,
+    0x40762859,
+    0x4076a86b,
+    0x40772880,
+    0x4077a8a6,
+    0x407828c3,
+    0x4078a8e6,
+    0x4079290c,
+    0x4079a929,
+    0x407a294c,
+    0x407aa968,
+    0x407b2984,
+    0x407ba996,
+    0x407c29a3,
+    0x407e29b0,
+    0x407ea9c6,
+    0x407f29de,
+    0x407fa9f1,
+    0x40802a06,
+    0x4080aa1f,
+    0x40812a3d,
+    0x4081aa5d,
+    0x40822a66,
+    0x4082aa82,
+    0x40832a8b,
+    0x4083a0cf,
+    0x4084215e,
+    0x4084a12e,
+    0x408524ac,
+    0x4085a490,
+    0x40861be8,
+    0x40869bfb,
+    0x40871eed,
+    0x40879efc,
+    0x40881b77,
+    0x40889e76,
+    0x40891ed4,
+    0x4089a454,
     0x4432042a,
     0x4432843c,
     0x44330445,
@@ -602,87 +604,87 @@
     0x44398522,
     0x443a052c,
     0x443a8536,
-    0x4c32179b,
-    0x4c3297aa,
-    0x4c3317b9,
-    0x4c3397d2,
-    0x4c3417ed,
-    0x4c349809,
-    0x4c35181b,
-    0x4c359829,
-    0x4c36183e,
-    0x4c36984f,
-    0x4c37185d,
-    0x4c37986b,
-    0x4c38187d,
-    0x4c38988d,
-    0x4c391897,
-    0x4c3998af,
-    0x4c3a18c7,
-    0x4c3a98da,
-    0x50322f06,
-    0x5032af1b,
-    0x50332f2c,
-    0x5033af3f,
-    0x50342f50,
-    0x5034af63,
-    0x50352f72,
-    0x5035af87,
-    0x50362f97,
-    0x5036afa6,
-    0x50372fb7,
-    0x5037afc7,
-    0x50382fd8,
-    0x5038afeb,
-    0x50392ffd,
-    0x5039b013,
-    0x503a3025,
-    0x503ab036,
-    0x503b3047,
-    0x503bb058,
-    0x503c3063,
-    0x503cb06f,
-    0x503d307a,
-    0x503db085,
-    0x503e3092,
-    0x503eb0a7,
-    0x503f30b5,
-    0x503fb0c9,
-    0x504030dc,
-    0x5040b0ed,
-    0x50413107,
-    0x5041b116,
-    0x5042311f,
-    0x5042b12e,
-    0x50433140,
-    0x5043b14c,
-    0x50443154,
-    0x5044b167,
-    0x50453178,
-    0x5045b18e,
-    0x5046319a,
-    0x5046b1ae,
-    0x504731bc,
-    0x5047b1d0,
-    0x504831ea,
-    0x5048b1fe,
-    0x50493214,
-    0x5049b22b,
-    0x504a323d,
-    0x504ab251,
-    0x504b3266,
-    0x504bb27d,
-    0x504c3291,
-    0x504cb29a,
-    0x504d32a2,
-    0x504db2b1,
-    0x504e32c1,
-    0x683210ba,
-    0x683290cb,
-    0x683310db,
-    0x683390e9,
-    0x683410f6,
-    0x6c3210a9,
+    0x4c3217cb,
+    0x4c3297da,
+    0x4c3317e9,
+    0x4c339802,
+    0x4c34181d,
+    0x4c349839,
+    0x4c35184b,
+    0x4c359859,
+    0x4c36186e,
+    0x4c36987f,
+    0x4c37188d,
+    0x4c37989b,
+    0x4c3818ad,
+    0x4c3898bd,
+    0x4c3918c7,
+    0x4c3998df,
+    0x4c3a18f7,
+    0x4c3a990a,
+    0x50322f36,
+    0x5032af4b,
+    0x50332f5c,
+    0x5033af6f,
+    0x50342f80,
+    0x5034af93,
+    0x50352fa2,
+    0x5035afb7,
+    0x50362fc7,
+    0x5036afd6,
+    0x50372fe7,
+    0x5037aff7,
+    0x50383008,
+    0x5038b01b,
+    0x5039302d,
+    0x5039b043,
+    0x503a3055,
+    0x503ab066,
+    0x503b3077,
+    0x503bb088,
+    0x503c3093,
+    0x503cb09f,
+    0x503d30aa,
+    0x503db0b5,
+    0x503e30c2,
+    0x503eb0d7,
+    0x503f30e5,
+    0x503fb0f9,
+    0x5040310c,
+    0x5040b11d,
+    0x50413137,
+    0x5041b146,
+    0x5042314f,
+    0x5042b15e,
+    0x50433170,
+    0x5043b17c,
+    0x50443184,
+    0x5044b197,
+    0x504531a8,
+    0x5045b1be,
+    0x504631ca,
+    0x5046b1de,
+    0x504731ec,
+    0x5047b200,
+    0x5048321a,
+    0x5048b22e,
+    0x50493244,
+    0x5049b25b,
+    0x504a326d,
+    0x504ab281,
+    0x504b3296,
+    0x504bb2ad,
+    0x504c32c1,
+    0x504cb2ca,
+    0x504d32d2,
+    0x504db2e1,
+    0x504e32f1,
+    0x683210ea,
+    0x683290fb,
+    0x6833110b,
+    0x68339119,
+    0x68341126,
+    0x6c3210d9,
     0x74320a6a,
     0x74328a7c,
     0x783206c9,
@@ -720,7 +722,7 @@
     0x784207a0,
     0x784287be,
     0x784307dc,
-    0x803215c2,
+    0x803215f2,
 };
 
 const size_t kOpenSSLFunctionValuesLen = sizeof(kOpenSSLFunctionValues) / sizeof(kOpenSSLFunctionValues[0]);
@@ -896,9 +898,11 @@
     "EC_GROUP_get_curve_GFp\0"
     "EC_GROUP_get_degree\0"
     "EC_GROUP_new_by_curve_name\0"
+    "EC_GROUP_new_curve_GFp\0"
     "EC_KEY_check_key\0"
     "EC_KEY_copy\0"
     "EC_KEY_generate_key\0"
+    "EC_KEY_new_by_curve_name\0"
     "EC_KEY_new_method\0"
     "EC_KEY_set_public_key_affine_coordinates\0"
     "EC_POINT_add\0"
diff --git a/third_party/closure_compiler/externs/file_manager_private.js b/third_party/closure_compiler/externs/file_manager_private.js
index 49d892d1..09affc9 100644
--- a/third_party/closure_compiler/externs/file_manager_private.js
+++ b/third_party/closure_compiler/externs/file_manager_private.js
@@ -60,6 +60,7 @@
  *   volumeId: string,
  *   fileSystemId: (string|undefined),
  *   extensionId: (string|undefined),
+ *   source: string,
  *   volumeLabel: (string|undefined),
  *   profile: ProfileInfo,
  *   sourcePath: (string|undefined),
@@ -69,6 +70,7 @@
  *   isParentDevice: (boolean|undefined),
  *   isReadOnly: boolean,
  *   hasMedia: boolean,
+ *   configurable: boolean,
  *   mountCondition: (string|undefined),
  *   mountContext: (string|undefined)
  * }}
@@ -613,8 +615,7 @@
  * @param {string} volumeId
  * @param {function()} callback
  */
-chrome.fileManagerPrivate.configureProvidedFileSystem =
-    function(volumeId, callback) {};
+chrome.fileManagerPrivate.configureVolume = function(volumeId, callback) {};
 
 /** @type {!ChromeEvent} */
 chrome.fileManagerPrivate.onMountCompleted;
diff --git a/tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp b/tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp
index 2d221d7..2d6eff256 100644
--- a/tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp
+++ b/tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp
@@ -17,6 +17,7 @@
 #include "clang/AST/RecursiveASTVisitor.h"
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Frontend/FrontendPluginRegistry.h"
+#include "clang/Sema/Sema.h"
 
 using namespace clang;
 using std::string;
@@ -144,6 +145,23 @@
     "[blink-gc] Class %0 which inherits from GarbageCollectedMixin must"
     " locally declare and override trace(Visitor*)";
 
+// Use a local RAV implementation to simply collect all FunctionDecls marked for
+// late template parsing. This happens with the flag -fdelayed-template-parsing,
+// which is on by default in MSVC-compatible mode.
+std::set<FunctionDecl*> GetLateParsedFunctionDecls(TranslationUnitDecl* decl) {
+  struct Visitor : public RecursiveASTVisitor<Visitor> {
+    bool VisitFunctionDecl(FunctionDecl* function_decl) {
+      if (function_decl->isLateTemplateParsed())
+        late_parsed_decls.insert(function_decl);
+      return true;
+    }
+
+    std::set<FunctionDecl*> late_parsed_decls;
+  } v;
+  v.TraverseDecl(decl);
+  return v.late_parsed_decls;
+}
+
 struct BlinkGCPluginOptions {
   BlinkGCPluginOptions()
     : enable_oilpan(false)
@@ -1017,6 +1035,8 @@
     if (diagnostic_.hasErrorOccurred())
       return;
 
+    ParseFunctionTemplates(context.getTranslationUnitDecl());
+
     CollectVisitor visitor;
     visitor.TraverseDecl(context.getTranslationUnitDecl());
 
@@ -1063,6 +1083,31 @@
     }
   }
 
+  void ParseFunctionTemplates(TranslationUnitDecl* decl) {
+    if (!instance_.getLangOpts().DelayedTemplateParsing)
+      return;  // Nothing to do.
+
+    std::set<FunctionDecl*> late_parsed_decls =
+        GetLateParsedFunctionDecls(decl);
+    clang::Sema& sema = instance_.getSema();
+
+    for (const FunctionDecl* fd : late_parsed_decls) {
+      assert(fd->isLateTemplateParsed());
+
+      if (!Config::IsTraceMethod(fd))
+        continue;
+
+      if (instance_.getSourceManager().isInSystemHeader(
+              instance_.getSourceManager().getSpellingLoc(fd->getLocation())))
+        continue;
+
+      // Force parsing and AST building of the yet-uninstantiated function
+      // template trace method bodies.
+      clang::LateParsedTemplate* lpt = sema.LateParsedTemplateMap[fd];
+      sema.LateTemplateParser(sema.OpaqueParser, *lpt);
+    }
+  }
+
   // Main entry for checking a record declaration.
   void CheckRecord(RecordInfo* info) {
     if (IsIgnored(info))
diff --git a/tools/clang/blink_gc_plugin/Config.h b/tools/clang/blink_gc_plugin/Config.h
index 02cbee9a..445952a 100644
--- a/tools/clang/blink_gc_plugin/Config.h
+++ b/tools/clang/blink_gc_plugin/Config.h
@@ -214,7 +214,7 @@
     TRACE_AFTER_DISPATCH_IMPL_METHOD
   };
 
-  static TraceMethodType GetTraceMethodType(clang::FunctionDecl* method) {
+  static TraceMethodType GetTraceMethodType(const clang::FunctionDecl* method) {
     if (method->getNumParams() != 1)
       return NOT_TRACE_METHOD;
 
@@ -244,7 +244,7 @@
     return NOT_TRACE_METHOD;
   }
 
-  static bool IsTraceMethod(clang::FunctionDecl* method) {
+  static bool IsTraceMethod(const clang::FunctionDecl* method) {
     return GetTraceMethodType(method) != NOT_TRACE_METHOD;
   }
 
diff --git a/tools/clang/blink_gc_plugin/tests/cycle_ptrs.txt b/tools/clang/blink_gc_plugin/tests/cycle_ptrs.txt
index 4d242a6..7ad6c48c 100644
--- a/tools/clang/blink_gc_plugin/tests/cycle_ptrs.txt
+++ b/tools/clang/blink_gc_plugin/tests/cycle_ptrs.txt
@@ -5,4 +5,3 @@
 ./cycle_ptrs.h:34:5: blink::B (m_c) => blink::C
 ./cycle_ptrs.h:39:5: blink::C (m_d) => blink::D
 ./cycle_ptrs.h:44:5: blink::D (m_es) => blink::E
-
diff --git a/tools/clang/blink_gc_plugin/tests/cycle_sub.txt b/tools/clang/blink_gc_plugin/tests/cycle_sub.txt
index b37907d..9c015c8 100644
--- a/tools/clang/blink_gc_plugin/tests/cycle_sub.txt
+++ b/tools/clang/blink_gc_plugin/tests/cycle_sub.txt
@@ -3,4 +3,3 @@
 ./cycle_sub.h:31:5:  blink::C (m_a) => blink::A
 ./cycle_sub.h:22:11: blink::A (<subclass>) => blink::B
 ./cycle_sub.h:26:5:  blink::B (m_c) => blink::C
-
diff --git a/tools/clang/blink_gc_plugin/tests/cycle_super.txt b/tools/clang/blink_gc_plugin/tests/cycle_super.txt
index 89b3675..374074b 100644
--- a/tools/clang/blink_gc_plugin/tests/cycle_super.txt
+++ b/tools/clang/blink_gc_plugin/tests/cycle_super.txt
@@ -2,4 +2,3 @@
 Found a potentially leaking cycle starting from a GC root:
 ./cycle_super.h:36:5: blink::D (m_c) => blink::C
 ./cycle_super.h:21:5: blink::C (blink::B <: blink::A <: m_d) => blink::D
-
diff --git a/tools/clang/blink_gc_plugin/tests/cycle_super_neg.txt b/tools/clang/blink_gc_plugin/tests/cycle_super_neg.txt
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/tools/clang/blink_gc_plugin/tests/cycle_super_neg.txt
@@ -0,0 +1 @@
+
diff --git a/tools/clang/blink_gc_plugin/tests/delayed_parsing.cpp b/tools/clang/blink_gc_plugin/tests/delayed_parsing.cpp
new file mode 100644
index 0000000..149d95e
--- /dev/null
+++ b/tools/clang/blink_gc_plugin/tests/delayed_parsing.cpp
@@ -0,0 +1,25 @@
+// 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 "heap/stubs.h"
+
+namespace blink {
+
+struct HeapObject : public GarbageCollected<HeapObject> {
+    void trace(Visitor*) { }
+};
+
+template<typename T>
+class TemplateBase
+    : public GarbageCollected<TemplateBase<T> > {
+public:
+    void trace(Visitor* visitor) { visitor->trace(m_obj); }
+private:
+    Member<HeapObject> m_obj;
+};
+
+class Subclass : public TemplateBase<Subclass> {
+};
+
+}
diff --git a/tools/clang/blink_gc_plugin/tests/delayed_parsing.flags b/tools/clang/blink_gc_plugin/tests/delayed_parsing.flags
new file mode 100644
index 0000000..94af50f
--- /dev/null
+++ b/tools/clang/blink_gc_plugin/tests/delayed_parsing.flags
@@ -0,0 +1 @@
+-fdelayed-template-parsing
diff --git a/tools/clang/blink_gc_plugin/tests/delayed_parsing.txt b/tools/clang/blink_gc_plugin/tests/delayed_parsing.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tools/clang/blink_gc_plugin/tests/delayed_parsing.txt
diff --git a/tools/clang/blink_gc_plugin/tests/register_weak_members_template.txt b/tools/clang/blink_gc_plugin/tests/register_weak_members_template.txt
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/tools/clang/blink_gc_plugin/tests/register_weak_members_template.txt
@@ -0,0 +1 @@
+
diff --git a/tools/clang/blink_gc_plugin/tests/test.py b/tools/clang/blink_gc_plugin/tests/test.py
index 5ade0323..acb7e74 100755
--- a/tools/clang/blink_gc_plugin/tests/test.py
+++ b/tools/clang/blink_gc_plugin/tests/test.py
@@ -4,20 +4,18 @@
 # found in the LICENSE file.
 
 
-import argparse
 import glob
 import os
 import subprocess
 import sys
 
 
-def run_test(test_base_name, cmd, reset_results):
+def run_test(test_base_name, cmd):
   """Run a test case.
 
   Args:
     test_base_name: The name for the test C++ source file without the extension.
     cmd: The actual command to run for the test.
-    reset_results: True if the results should be overwritten in place.
 
   Returns:
     None on pass, or a str with the description of the failure.
@@ -49,31 +47,31 @@
       # from a previous run.
       os.remove('%s.graph.json' % test_base_name)
 
+  # TODO(dcheng): Remove the rstrip() and just rebaseline the tests to match.
+  actual = actual.rstrip()
+
   # On Windows, clang emits CRLF as the end of line marker. Normalize it to LF
   # to match posix systems.
   actual = actual.replace('\r\n', '\n')
 
-  result_file = '%s.txt%s' % (
-      test_base_name, '' if reset_results else '.actual')
   try:
-    expected = open('%s.txt' % test_base_name).read()
+    expected = open('%s.txt' % test_base_name).read().rstrip()
   except IOError:
-    open(result_file, 'w').write(actual)
+    open('%s.txt.actual' % test_base_name, 'w').write(actual)
     return 'no expected file found'
 
   if expected != actual:
-    open(result_file, 'w').write(actual)
+    open('%s.txt.actual' % test_base_name, 'w').write(actual)
     return 'expected and actual differed'
 
 
-def run_tests(clang_path, plugin_path, reset_results):
+def run_tests(clang_path, plugin_path):
   """Runs the tests.
 
   Args:
     clang_path: The path to the clang binary to be tested.
     plugin_path: An optional path to the plugin to test. This may be None, if
                  plugin is built directly into clang, like on Windows.
-    reset_results: True if the results should be overwritten in place.
 
   Returns:
     (passing, failing): Two lists containing the base names of the passing and
@@ -103,7 +101,7 @@
       pass
     cmd.append(test)
 
-    failure_message = run_test(test_base_name, cmd, reset_results)
+    failure_message = run_test(test_base_name, cmd)
     if failure_message:
       print 'failed: %s' % failure_message
       failing.append(test_base_name)
@@ -115,23 +113,18 @@
 
 
 def main():
-  parser = argparse.ArgumentParser()
-  parser.add_argument(
-      '--reset-results', action='store_true',
-      help='If specified, overwrites the expected results in place.')
-  parser.add_argument('clang_path', help='The path to the clang binary.')
-  parser.add_argument('plugin_path', nargs='?',
-                      help='The path to the plugin library, if any.')
-  args = parser.parse_args()
+  if len(sys.argv) < 2:
+    print 'Usage: <path to clang>[ <path to plugin>]'
+    return -1
 
   os.chdir(os.path.dirname(os.path.realpath(__file__)))
 
-  print 'Using clang %s...' % args.clang_path
-  print 'Using plugin %s...' % args.plugin_path
+  clang_path = sys.argv[1]
+  plugin_path = sys.argv[2] if len(sys.argv) > 2 else None
+  print 'Using clang %s...' % clang_path
+  print 'Using plugin %s...' % plugin_path
 
-  passing, failing = run_tests(args.clang_path,
-                               args.plugin_path,
-                               args.reset_results)
+  passing, failing = run_tests(clang_path, plugin_path)
   print 'Ran %d tests: %d succeeded, %d failed' % (
       len(passing) + len(failing), len(passing), len(failing))
   for test in failing:
diff --git a/tools/clang/blink_gc_plugin/tests/trace_after_dispatch_impl.txt b/tools/clang/blink_gc_plugin/tests/trace_after_dispatch_impl.txt
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/tools/clang/blink_gc_plugin/tests/trace_after_dispatch_impl.txt
@@ -0,0 +1 @@
+
diff --git a/tools/clang/blink_gc_plugin/tests/traceimpl.txt b/tools/clang/blink_gc_plugin/tests/traceimpl.txt
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/tools/clang/blink_gc_plugin/tests/traceimpl.txt
@@ -0,0 +1 @@
+
diff --git a/tools/clang/blink_gc_plugin/tests/traceimpl_derived_from_templated_base.txt b/tools/clang/blink_gc_plugin/tests/traceimpl_derived_from_templated_base.txt
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/tools/clang/blink_gc_plugin/tests/traceimpl_derived_from_templated_base.txt
@@ -0,0 +1 @@
+
diff --git a/tools/clang/blink_gc_plugin/tests/traceimpl_omitted_trace.txt b/tools/clang/blink_gc_plugin/tests/traceimpl_omitted_trace.txt
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/tools/clang/blink_gc_plugin/tests/traceimpl_omitted_trace.txt
@@ -0,0 +1 @@
+
diff --git a/tools/clang/blink_gc_plugin/tests/traceimpl_overloaded.txt b/tools/clang/blink_gc_plugin/tests/traceimpl_overloaded.txt
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/tools/clang/blink_gc_plugin/tests/traceimpl_overloaded.txt
@@ -0,0 +1 @@
+
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index edb97af..27b3b10 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -605,6 +605,16 @@
   </summary>
 </histogram>
 
+<histogram name="Ash.AppList.TimeBetweenTaskSwitches" units="seconds">
+  <owner>bruthig@chromium.org</owner>
+  <owner>tdanderson@chromium.org</owner>
+  <summary>
+    The amount of time between selecting an item from the Ash app list. Not
+    recorded on the first time an item is selected from the app list after
+    startup.
+  </summary>
+</histogram>
+
 <histogram name="Ash.Dock.Action" enum="DockedAction">
   <owner>kuscher@google.com</owner>
   <owner>varkha@chromium.org</owner>
@@ -785,6 +795,16 @@
   <summary>The duration of mostly stationary long-duration touches.</summary>
 </histogram>
 
+<histogram name="Ash.Tab.TimeBetweenSwitchToExistingTabUserActions"
+    units="seconds">
+  <owner>bruthig@chromium.org</owner>
+  <owner>tdanderson@chromium.org</owner>
+  <summary>
+    The number of seconds between tab switches triggered by a user gesture (e.g.
+    Ctrl+T, Ctrl+1, tapping or clicking the tab strip, etc).
+  </summary>
+</histogram>
+
 <histogram name="Ash.TouchDuration" units="milliseconds">
   <obsolete>
     Deprecated 12/2013 in r239809, and replaced by Ash.TouchDuration2.
@@ -916,6 +936,16 @@
   </summary>
 </histogram>
 
+<histogram name="Ash.WindowCycleController.TimeBetweenTaskSwitches"
+    units="seconds">
+  <owner>tdanderson@google.com</owner>
+  <owner>bruthig@google.com</owner>
+  <summary>
+    The number of seconds between task switches triggered by the next window and
+    previous window accelerator keys (ie Alt+Tab, Alt+Shift+Tab).
+  </summary>
+</histogram>
+
 <histogram name="Ash.WindowSelector.ArrowKeyPresses">
   <owner>flackr@chromium.org</owner>
   <owner>tdanderson@chromium.org</owner>
@@ -996,11 +1026,25 @@
   </summary>
 </histogram>
 
+<histogram name="Ash.WindowSelector.TimeBetweenActiveWindowChanges"
+    units="seconds">
+  <owner>bruthig@chromium.org</owner>
+  <owner>tdanderson@chromium.org</owner>
+  <summary>
+    The amount of time between endings of overview mode sessions which were
+    caused by the user selecting a window which was not previously active. Only
+    recorded on the second and later times after startup that the user selected
+    a window which was not previously active.
+  </summary>
+</histogram>
+
 <histogram name="Ash.WindowSelector.TimeBetweenUse" units="milliseconds">
   <owner>flackr@chromium.org</owner>
   <owner>kuscher@google.com</owner>
   <summary>
-    The amount of time between uses of overview mode to switch between windows.
+    The amount of time between uses of overview mode, recorded when overview
+    mode is entered. Only recorded on the second and later times after startup
+    that the user entered overview mode.
   </summary>
 </histogram>
 
@@ -4098,14 +4142,14 @@
 </histogram>
 
 <histogram name="CrosFirstRun.DialogShown">
-  <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
+  <owner>dzhioev@chromium.org</owner>
   <summary>
     Records the number of times when first-run dialog was shown.
   </summary>
 </histogram>
 
 <histogram name="CrosFirstRun.FurthestStep">
-  <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
+  <owner>dzhioev@chromium.org</owner>
   <summary>
     Index of furthest step that was reached during tutorial. Since order of
     steps could change eventially and new steps could apear we use index here
@@ -4114,23 +4158,23 @@
 </histogram>
 
 <histogram name="CrosFirstRun.TimeSpent" units="ms">
-  <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
+  <owner>dzhioev@chromium.org</owner>
   <summary>The total time that user spent on first-run tutorial.</summary>
 </histogram>
 
 <histogram name="CrosFirstRun.TimeSpentOnStep" units="ms">
-  <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
+  <owner>dzhioev@chromium.org</owner>
   <summary>The time that user spent on some step of tutorial.</summary>
 </histogram>
 
 <histogram name="CrosFirstRun.TutorialCompletion"
     enum="CrosFirstRunTutorialCompletionType">
-  <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
+  <owner>dzhioev@chromium.org</owner>
   <summary>Tracks the way how user left tutorial.</summary>
 </histogram>
 
 <histogram name="CrosFirstRun.TutorialLaunched">
-  <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
+  <owner>dzhioev@chromium.org</owner>
   <summary>
     Records the number of times when first-run tutorial has been launched.
   </summary>
@@ -4298,6 +4342,41 @@
   </summary>
 </histogram>
 
+<histogram name="DataReductionProxy.ConfigFetchLostBytesCL">
+  <owner>jeremyim@chromium.org</owner>
+  <owner>bengr@chromium.org</owner>
+  <summary>
+    Size of the response body. This is the actual number of bytes received,
+    which usually agrees with but is not necessarily the same as the size
+    specified by the Content-Length header. Only recorded if the request is sent
+    while a simulated Data Reduction Proxy configuration fetch is taking place.
+  </summary>
+</histogram>
+
+<histogram name="DataReductionProxy.ConfigFetchLostBytesDiff">
+  <owner>jeremyim@chromium.org</owner>
+  <owner>bengr@chromium.org</owner>
+  <summary>
+    The difference between the size specified in the X-Original-Content-Length
+    header and the size of the response body. Only recorded if the request is
+    sent while a simulated Data Reduction Proxy configuration fetch is taking
+    place. Only positive values are logged, so if X-Original-Content-Length is
+    not specified or if it equals or exceeds the content length, it is not
+    logged.
+  </summary>
+</histogram>
+
+<histogram name="DataReductionProxy.ConfigFetchLostBytesOCL">
+  <owner>jeremyim@chromium.org</owner>
+  <owner>bengr@chromium.org</owner>
+  <summary>
+    Size specified in the X-Original-Content-Length header. If this header is
+    not present in the response, the size of the response body is used. Only
+    recorded if the request is sent while a simulated Data Reduction Proxy
+    configuration fetch is taking place.
+  </summary>
+</histogram>
+
 <histogram
     name="DataReductionProxy.ConfigService.FetchFailedAttemptsBeforeSuccess">
   <owner>jeremyim@chromium.org</owner>
@@ -13638,7 +13717,10 @@
 
 <histogram name="interstitial.decision" enum="SecurityInterstitialDecision">
   <owner>felt@chromium.org</owner>
-  <summary>User decision when presented with a security interstitial.</summary>
+  <summary>
+    User decision when presented with a security interstitial. As of M44,
+    subresource interstitials were split into their own entries.
+  </summary>
 </histogram>
 
 <histogram name="interstitial.decision.repeat_visit"
@@ -13646,14 +13728,18 @@
   <owner>felt@chromium.org</owner>
   <summary>
     User decision when presented with a security interstitial, on a site that
-    the user had previously visited.
+    the user had previously visited.  As of M44, subresource interstitials were
+    split into their own entries.
   </summary>
 </histogram>
 
 <histogram name="interstitial.interaction"
     enum="SecurityInterstitialInteraction">
   <owner>felt@chromium.org</owner>
-  <summary>User interactions with a security interstitial.</summary>
+  <summary>
+    User interactions with a security interstitial.  As of M44, subresource
+    interstitials were split into their own entries.
+  </summary>
 </histogram>
 
 <histogram name="interstitial.ssl" enum="SSLResponseTypesV2">
@@ -14362,6 +14448,20 @@
   </summary>
 </histogram>
 
+<histogram name="Login.NewUserPriorityPrefsSyncResult"
+    enum="NewUserPriorityPrefsSyncResult">
+  <owner>dzhioev@chromeos.org</owner>
+  <summary>Records whether a new user's priority prefs sync timed out.</summary>
+</histogram>
+
+<histogram name="Login.NewUserPriorityPrefsSyncTime" units="milliseconds">
+  <owner>dzhioev@chromeos.org</owner>
+  <summary>
+    Time spent waiting for priority preferences to sync after new user sign in.
+    The operation will time out after 10s.
+  </summary>
+</histogram>
+
 <histogram name="Login.PolicyFilesStatePerBoot" enum="LoginPolicyFilesState">
   <owner>cmasone@chromium.org</owner>
   <summary>The state of Chrome OS owner key and device policy files.</summary>
@@ -20206,6 +20306,14 @@
   </summary>
 </histogram>
 
+<histogram name="Net.PrefProxyConfig.GooglezipProxyRemovalCount">
+  <owner>sclittle@chromium.org</owner>
+  <summary>
+    Records how many *.googlezip.net Data Reduction Proxies were removed from
+    the effective proxy configuration when a proxy reconfiguration occurs.
+  </summary>
+</histogram>
+
 <histogram name="Net.Priority_High_Latency" units="milliseconds">
   <obsolete>
     Replaced by Net.Priority_High_Latency_b.
@@ -22120,6 +22228,22 @@
   <summary>Time to complete a certificate verification (error case).</summary>
 </histogram>
 
+<histogram name="Net.SSLFallbackErrorCode" enum="NetErrorCodes">
+  <owner>davidben@chromium.org</owner>
+  <summary>
+    For each successful HTTPS request which used the TLS version fallback, the
+    error code of the last failed attempt.
+  </summary>
+</histogram>
+
+<histogram name="Net.SSLFallbackFailureState" enum="SSLFailureState">
+  <owner>davidben@chromium.org</owner>
+  <summary>
+    For each successful HTTPS request which used the TLS version fallback, the
+    type of handshake failure of the last failed attempt.
+  </summary>
+</histogram>
+
 <histogram name="Net.SSLHostInfoDNSLookup" units="milliseconds">
   <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
   <summary>Time to complete a DNS lookup for a DNS CAA record.</summary>
@@ -26417,6 +26541,17 @@
   </summary>
 </histogram>
 
+<histogram name="PasswordManager.EmptyUsernames.TextAndPasswordFieldCount">
+  <owner>msramek@chromium.org</owner>
+  <owner>vasilii@chromium.org</owner>
+  <summary>
+    The total number of text and password fields for password forms that do not
+    have a username field. This is recorded every time such a password form is
+    successfully parsed. Note that the parsing is attempted when the form is
+    encountered (i.e when the document is loaded) and also when it is submitted.
+  </summary>
+</histogram>
+
 <histogram name="PasswordManager.EmptyUsernames.WithoutCorrespondingNonempty">
   <owner>msramek@chromium.org</owner>
   <owner>vasilii@chromium.org</owner>
@@ -36107,6 +36242,14 @@
   </summary>
 </histogram>
 
+<histogram name="ServiceWorker.UnhandledEventRatio" units="percent">
+  <owner>kinuko@chromium.org</owner>
+  <summary>
+    Records the ratio of unhandled events to all events that are dispatched to
+    each ServiceWorker.  Recorded when each ServiceWorkerVersion is destructed.
+  </summary>
+</histogram>
+
 <histogram name="ServiceWorkerCache.Cache" units="milliseconds">
   <owner>dmurph@chromium.org</owner>
   <summary>
@@ -41677,6 +41820,36 @@
   </summary>
 </histogram>
 
+<histogram name="Sync.MemoryPressureWarningBeforeCleanShutdown" units="count">
+  <owner>gangwu@chromium.org</owner>
+  <summary>
+    Counts the number of times a user's sync service received a
+    MEMORY_PRESSURE_LEVEL_CRITICAL warning before the sync service shut down
+    cleanly. The sync service emits this number the next time the user's sync
+    service is started, which will likely happen the next time the user's
+    profile is opened after a Chrome restart.  This count is emitted once per
+    user/profile. Things like browser crashes that implicitly bring down all
+    users' sync services will cause unclean shutdown tags to appear on all open
+    profiles, meaning that there will be multiple emissions to this histogram as
+    those profiles are re-opened.
+  </summary>
+</histogram>
+
+<histogram name="Sync.MemoryPressureWarningBeforeUncleanShutdown" units="count">
+  <owner>gangwu@chromium.org</owner>
+  <summary>
+    Counts the number of times a user's sync service received a
+    MEMORY_PRESSURE_LEVEL_CRITICAL warning before the sync service shut down
+    uncleanly. The sync service emits this number the next time the user's sync
+    service is started, which will likely happen the next time the user's
+    profile is opened after a Chrome restart.  This count is emitted once per
+    user/profile. Things like browser crashes that implicitly bring down all
+    users' sync services will cause unclean shutdown tags to appear on all open
+    profiles, meaning that there will be multiple emissions to this histogram as
+    those profiles are re-opened.
+  </summary>
+</histogram>
+
 <histogram name="Sync.NigoriMigrationState" enum="SyncNigoriMigrationState">
   <owner>zea@chromium.org</owner>
   <summary>Breakdown of sync's nigori node keystore migration state.</summary>
@@ -52314,7 +52487,7 @@
   <int value="1007" label="DEVELOPERPRIVATE_SHOWOPTIONS"/>
   <int value="1008" label="DEVELOPERPRIVATE_SHOWPATH"/>
   <int value="1009" label="FILEMANAGERPRIVATE_ADDPROVIDEDFILESYSTEM"/>
-  <int value="1010" label="FILEMANAGERPRIVATE_CONFIGUREPROVIDEDFILESYSTEM"/>
+  <int value="1010" label="FILEMANAGERPRIVATE_CONFIGUREVOLUME"/>
   <int value="1011" label="SEARCHENGINESPRIVATE_GETSEARCHENGINES"/>
   <int value="1012" label="SEARCHENGINESPRIVATE_SETSELECTEDSEARCHENGINE"/>
   <int value="1013" label="AUTOFILLPRIVATE_SAVEADDRESS"/>
@@ -52345,6 +52518,7 @@
   <int value="1037" label="PASSWORDSPRIVATE_REMOVESAVEDPASSWORD"/>
   <int value="1038" label="PASSWORDSPRIVATE_REMOVEPASSWORDEXCEPTION"/>
   <int value="1039" label="PASSWORDSPRIVATE_GETPLAINTEXTPASSWORD"/>
+  <int value="1040" label="LAUNCHERPAGE_HIDE"/>
 </enum>
 
 <enum name="ExtensionInstallCause" type="int">
@@ -56484,6 +56658,7 @@
   <int value="-1835975804" label="disable-offline-auto-reload"/>
   <int value="-1833149810" label="enable-accessibility-tab-switcher"/>
   <int value="-1832575380" label="show-saved-copy"/>
+  <int value="-1832221649" label="disable-out-of-process-pac"/>
   <int value="-1821058653" label="enable-delay-agnostic-aec"/>
   <int value="-1767470652" label="out-of-process-pdf"/>
   <int value="-1751928267" label="disable-icon-ntp"/>
@@ -56600,6 +56775,7 @@
   <int value="-649956990" label="enable-harfbuzz-rendertext"/>
   <int value="-641719457" label="disable-compositor-touch-hit-testing"/>
   <int value="-622685174" label="enable-pdf-material-ui"/>
+  <int value="-610411643" label="enable-printer-app-search"/>
   <int value="-604814313" label="enable-pinch"/>
   <int value="-601384286" label="disable-contextual-search"/>
   <int value="-579192400" label="disable-input-view"/>
@@ -58826,6 +59002,11 @@
   <int value="6" label="URL blocked for supervised user"/>
 </enum>
 
+<enum name="NewUserPriorityPrefsSyncResult" type="int">
+  <int value="0" label="Succeeded"/>
+  <int value="1" label="Timed out"/>
+</enum>
+
 <enum name="NotificationActionType" type="int">
   <int value="0" label="Unknown"/>
   <int value="1" label="Notification added"/>
@@ -62034,6 +62215,7 @@
   <int value="63" label="IDC_WRITING_DIRECTION_DEFAULT"/>
   <int value="64" label="IDC_WRITING_DIRECTION_LTR"/>
   <int value="65" label="IDC_WRITING_DIRECTION_RTL"/>
+  <int value="66" label="IDC_CONTENT_CONTEXT_SHOW_ORIGINAL_IMAGE"/>
 </enum>
 
 <enum name="ReportProcessingResult" type="int">
@@ -64084,6 +64266,16 @@
   <int value="9" label="UNKNOWN"/>
 </enum>
 
+<enum name="SSLFailureState" type="int">
+  <int value="0" label="No failure"/>
+  <int value="1" label="Unknown failure"/>
+  <int value="2" label="Failed to process ClientHello"/>
+  <int value="3" label="Buggy AES-GCM"/>
+  <int value="4" label="Failed with client authentication"/>
+  <int value="5" label="Session version mismatch"/>
+  <int value="6" label="Failed with Next Proto Negotiation"/>
+</enum>
+
 <enum name="SSLGoodCertSeenEvent" type="int">
   <int value="0" label="NO_PREVIOUS_EXCEPTION"/>
   <int value="1" label="HAD_PREVIOUS_EXCEPTION"/>
@@ -66644,6 +66836,22 @@
   <affected-histogram name="DataReductionProxy.BypassedBytes"/>
 </histogram_suffixes>
 
+<histogram_suffixes name="DataReductionProxyConfigFetchLostBytes" separator="_">
+  <suffix name="0" label="Bucket 0 for gathering multiple data points."/>
+  <suffix name="1" label="Bucket 1 for gathering multiple data points."/>
+  <suffix name="2" label="Bucket 2 for gathering multiple data points."/>
+  <suffix name="3" label="Bucket 3 for gathering multiple data points."/>
+  <suffix name="4" label="Bucket 4 for gathering multiple data points."/>
+  <suffix name="5" label="Bucket 5 for gathering multiple data points."/>
+  <suffix name="6" label="Bucket 6 for gathering multiple data points."/>
+  <suffix name="7" label="Bucket 7 for gathering multiple data points."/>
+  <suffix name="8" label="Bucket 8 for gathering multiple data points."/>
+  <suffix name="9" label="Bucket 9 for gathering multiple data points."/>
+  <affected-histogram name="DataReductionProxy.ConfigFetchLostBytesCL"/>
+  <affected-histogram name="DataReductionProxy.ConfigFetchLostBytesDiff"/>
+  <affected-histogram name="DataReductionProxy.ConfigFetchLostBytesOCL"/>
+</histogram_suffixes>
+
 <histogram_suffixes name="DataReductionProxyMissingViaHeaderBytes"
     separator=".">
   <suffix name="4xx" label="Response with 4xx response code"/>
@@ -69945,8 +70153,11 @@
     ordering="prefix">
   <suffix name="bad_clock"/>
   <suffix name="harmful"/>
+  <suffix name="harmful_subresource"/>
   <suffix name="malware"/>
+  <suffix name="malware_subresource"/>
   <suffix name="phishing"/>
+  <suffix name="phishing_subresource"/>
   <suffix name="ssl_nonoverridable"/>
   <suffix name="ssl_overridable"/>
   <affected-histogram name="interstitial.decision"/>
diff --git a/tools/perf/benchmarks/blink_perf.py b/tools/perf/benchmarks/blink_perf.py
index 8720aa7..3c31e9b 100644
--- a/tools/perf/benchmarks/blink_perf.py
+++ b/tools/perf/benchmarks/blink_perf.py
@@ -167,7 +167,8 @@
     return CreatePageSetFromPath(path, SKIPPED_FILE)
 
 
-@benchmark.Disabled('win')  # crbug.com/455796
+@benchmark.Disabled('win',   # http://crbug.com/488493
+                    'linux') # http://crbug.com/488059
 class BlinkPerfCanvas(benchmark.Benchmark):
   tag = 'canvas'
   test = _BlinkPerfMeasurement
diff --git a/tools/perf/benchmarks/thread_times.py b/tools/perf/benchmarks/thread_times.py
index 1cdbe931..812cbca70 100644
--- a/tools/perf/benchmarks/thread_times.py
+++ b/tools/perf/benchmarks/thread_times.py
@@ -94,3 +94,17 @@
   def Name(cls):
     return 'thread_times.polymer'
 
+@benchmark.Enabled('android')
+class ThreadTimesKeyIdlePowerCases(_ThreadTimes):
+  """Measures timeline metrics for sites that should be idle in foreground
+  and background scenarios. The metrics are per-second rather than per-frame."""
+  page_set = page_sets.KeyIdlePowerCasesPageSet
+
+  @classmethod
+  def Name(cls):
+    return 'thread_times.key_idle_power_cases'
+
+  @classmethod
+  def ValueCanBeAddedPredicate(cls, value, _):
+    # Only report per-second metrics.
+    return 'per_frame' not in value.name and 'mean_frame' not in value.name
diff --git a/tools/perf/page_sets/android_screen_restoration_shared_state.py b/tools/perf/page_sets/android_screen_restoration_shared_state.py
new file mode 100644
index 0000000..3de3c2e
--- /dev/null
+++ b/tools/perf/page_sets/android_screen_restoration_shared_state.py
@@ -0,0 +1,29 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+import logging
+
+from telemetry.page import shared_page_state
+
+
+class AndroidScreenRestorationSharedState(shared_page_state.SharedPageState):
+  """ Ensures the screen is on before and after each user story is run. """
+
+  def WillRunUserStory(self, page):
+    super(AndroidScreenRestorationSharedState, self).WillRunUserStory(page)
+    self._EnsureScreenOn()
+
+  def DidRunUserStory(self, results):
+    try:
+      super(AndroidScreenRestorationSharedState, self).DidRunUserStory(results)
+    finally:
+      self._EnsureScreenOn()
+
+  def CanRunOnBrowser(self, browser_info):
+    if not browser_info.browser_type.startswith('android'):
+      logging.warning('Browser is non-Android, skipping test')
+      return False
+    return True
+
+  def _EnsureScreenOn(self):
+    self.platform.android_action_runner.EnsureScreenOn()
diff --git a/tools/perf/page_sets/key_idle_power_cases.py b/tools/perf/page_sets/key_idle_power_cases.py
new file mode 100644
index 0000000..207a1e3
--- /dev/null
+++ b/tools/perf/page_sets/key_idle_power_cases.py
@@ -0,0 +1,66 @@
+# 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.
+from page_sets import android_screen_restoration_shared_state
+
+from telemetry.page import page as page_module
+from telemetry.page import page_set as page_set_module
+
+
+class KeyIdlePowerPage(page_module.Page):
+
+  def __init__(self, url, page_set, turn_screen_off):
+    super(KeyIdlePowerPage, self).__init__(
+        url=url,
+        page_set=page_set,
+        shared_page_state_class=(android_screen_restoration_shared_state
+            .AndroidScreenRestorationSharedState))
+    self.user_agent_type = 'mobile'
+    self._turn_screen_off = turn_screen_off
+
+  def RunNavigateSteps(self, action_runner):
+    super(KeyIdlePowerPage, self).RunNavigateSteps(action_runner)
+    action_runner.Wait(2)
+    if self._turn_screen_off:
+      # TODO(jdduke): Remove this API violation after the shared page state is
+      # exposed here, crbug.com/470147.
+      # pylint: disable=protected-access
+      action_runner._tab.browser.platform.android_action_runner.TurnScreenOff()
+      # We're not interested in tracking activity that occurs immediately after
+      # the screen is turned off. Several seconds should be enough time for the
+      # browser to "settle down" into an idle state.
+      action_runner.Wait(2)
+
+  def RunPageInteractions(self, action_runner):
+    # The page interaction is simply waiting in an idle state.
+    action_runner.Wait(20)
+
+
+class KeyIdlePowerCasesPageSet(page_set_module.PageSet):
+
+  """ Key idle power cases """
+
+  def __init__(self):
+    super(KeyIdlePowerCasesPageSet, self).__init__(user_agent_type='mobile')
+
+    foreground_urls_list = [
+      # Why: Ensure minimal activity for static, empty pages in the foreground.
+      'file://key_idle_power_cases/blank.html',
+    ]
+
+    for url in foreground_urls_list:
+      self.AddUserStory(KeyIdlePowerPage(url, self, False))
+
+    background_urls_list = [
+      # Why: Ensure animated GIFs aren't processed when Chrome is backgrounded.
+      'file://key_idle_power_cases/animated-gif.html',
+      # Why: Ensure CSS animations aren't processed when Chrome is backgrounded.
+      'file://key_idle_power_cases/css-animation.html',
+      # Why: Ensure rAF is suppressed when Chrome is backgrounded.
+      'file://key_idle_power_cases/request-animation-frame.html',
+      # Why: Ensure setTimeout is throttled when Chrome is backgrounded.
+      'file://key_idle_power_cases/set-timeout.html',
+    ]
+
+    for url in background_urls_list:
+      self.AddUserStory(KeyIdlePowerPage(url, self, True))
diff --git a/tools/perf/page_sets/key_idle_power_cases/animated-gif.html b/tools/perf/page_sets/key_idle_power_cases/animated-gif.html
new file mode 100644
index 0000000..b37f244
--- /dev/null
+++ b/tools/perf/page_sets/key_idle_power_cases/animated-gif.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Animated GIF Test</title>
+</head>
+<body>
+<img src="animated-10color.gif">
+</body>
+</html>
diff --git a/tools/perf/page_sets/key_idle_power_cases/blank.html b/tools/perf/page_sets/key_idle_power_cases/blank.html
new file mode 100644
index 0000000..3ac80b70
--- /dev/null
+++ b/tools/perf/page_sets/key_idle_power_cases/blank.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>Blank Test</title>
+</head>
+<body>
+</body>
+</html>
diff --git a/tools/perf/page_sets/key_idle_power_cases/css-animation.html b/tools/perf/page_sets/key_idle_power_cases/css-animation.html
new file mode 100644
index 0000000..d8457ac
--- /dev/null
+++ b/tools/perf/page_sets/key_idle_power_cases/css-animation.html
@@ -0,0 +1,171 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>CSS Animation Test</title>
+    <meta name="viewport" content="initial-scale=0.60, minimum-scale=0.60, maximum-scale=0.60">
+    <style type="text/css">
+
+      #stage {
+        margin: 150px auto;
+        width: 600px;
+        height: 400px;
+        /*
+
+        Setting the perspective of the contents of the stage
+        but not the stage itself
+
+        */
+        -webkit-perspective: 800;
+      }
+
+      #rotate {
+        margin: 0 auto;
+        width: 600px;
+        height: 400px;
+        /* Ensure that we're in 3D space */
+        -webkit-transform-style: preserve-3d;
+        /*
+        Make the whole set of rows use the x-axis spin animation
+        for a duration of 7 seconds, running infinitely and linearly
+        */
+        -webkit-animation-name: x-spin;
+        -webkit-animation-duration: 7s;
+        -webkit-animation-iteration-count: infinite;
+        -webkit-animation-timing-function: linear;
+      }
+
+      .ring {
+        margin: 0 auto;
+        height: 110px;
+        width: 600px;
+        -webkit-transform-style: preserve-3d;
+        -webkit-animation-iteration-count: infinite;
+        -webkit-animation-timing-function: linear;
+      }
+
+      .ring > :nth-child(odd) {
+        background-color: #995C7F;
+      }
+
+      .ring > :nth-child(even) {
+        background-color: #835A99;
+      }
+
+      .poster {
+        position: absolute;
+        left: 250px;
+        width: 100px;
+        height: 100px;
+        opacity: 0.7;
+        color: rgba(0,0,0,0.9);
+        -webkit-border-radius: 10px;
+      }
+
+      .poster > p {
+        font-family: 'Georgia', serif;
+        font-size: 36px;
+        font-weight: bold;
+        text-align: center;
+        margin-top: 28px;
+      }
+
+      /*
+      Set up each row to have a different animation duration
+      and alternating y-axis rotation directions.
+      */
+      #ring-1 {
+        -webkit-animation-name: y-spin;
+        -webkit-animation-duration: 5s;
+      }
+
+      #ring-2 {
+        -webkit-animation-name: back-y-spin;
+        -webkit-animation-duration: 4s;
+      }
+
+      #ring-3 {
+        -webkit-animation-name: y-spin;
+        -webkit-animation-duration: 3s;
+      }
+
+      /*
+
+      Here we define each of the three individual animations that
+      we will be using to have our 3D rotation effect. The first
+      animation will perform a full rotation on the x-axis, we'll
+      use that on the whole set of objects. The second and third
+      animations will perform a full rotation on the y-axis in
+      opposite directions, alternating directions between rows.
+
+      Note that you currently have to specify an intermediate step
+      for rotations even when you are using individual transformation
+      constructs.
+
+      */
+      @-webkit-keyframes x-spin {
+        0%    { -webkit-transform: rotateX(0deg); }
+        50%   { -webkit-transform: rotateX(180deg); }
+        100%  { -webkit-transform: rotateX(360deg); }
+      }
+
+      @-webkit-keyframes y-spin {
+        0%    { -webkit-transform: rotateY(0deg); }
+        50%   { -webkit-transform: rotateY(180deg); }
+        100%  { -webkit-transform: rotateY(360deg); }
+      }
+
+      @-webkit-keyframes back-y-spin {
+        0%    { -webkit-transform: rotateY(360deg); }
+        50%   { -webkit-transform: rotateY(180deg); }
+        100%  { -webkit-transform: rotateY(0deg); }
+      }
+    </style>
+
+    <script type="text/javascript">
+
+      const POSTERS_PER_ROW = 12;
+      const RING_RADIUS = 200;
+
+      function setup_posters (row)
+      {
+        var posterAngle = 360 / POSTERS_PER_ROW;
+        for (var i = 0; i < POSTERS_PER_ROW; i ++) {
+          var poster = document.createElement('div');
+          poster.className = 'poster';
+          // compute and assign the transform for this poster
+          var transform = 'rotateY(' + (posterAngle * i) + 'deg) translateZ(' + RING_RADIUS + 'px)';
+          poster.style.webkitTransform = transform;
+          // setup the number to show inside the poster
+          var content = poster.appendChild(document.createElement('p'));
+          content.textContent = i;
+          // add the poster to the row
+          row.appendChild(poster);
+        }
+
+      }
+
+      function init ()
+      {
+        setup_posters(document.getElementById('ring-1'));
+        setup_posters(document.getElementById('ring-2'));
+        setup_posters(document.getElementById('ring-3'));
+      }
+
+      // call init once the document is fully loaded
+      window.addEventListener('load', init, false);
+
+    </script>
+  </head>
+
+  <body>
+    <div id="stage">
+      <div id="rotate">
+        <div id="ring-1" class="ring"></div>
+        <div id="ring-2" class="ring"></div>
+        <div id="ring-3" class="ring"></div>
+      </div>
+    </div>
+
+  </body>
+
+</html>
diff --git a/tools/perf/page_sets/key_idle_power_cases/request-animation-frame.html b/tools/perf/page_sets/key_idle_power_cases/request-animation-frame.html
new file mode 100644
index 0000000..05b01c6
--- /dev/null
+++ b/tools/perf/page_sets/key_idle_power_cases/request-animation-frame.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0">
+  <title>requestAnimationFrame Test</title>
+  <style type="text/css">
+  html, body {
+    height: 100%;
+    padding: 0px;
+    margin: 0px;
+  }
+  #container {
+    width: 100%;
+    height: 100%;
+    background: rgb(128, 128, 128);
+  }
+  </style>
+</head>
+<body>
+  <div id="container"></div>
+  <script type="text/javascript">
+  var container = document.getElementById('container');
+  var c = 128;
+  tick();
+  function tick() {
+    ++c;
+    c %= 256;
+    container.style.backgroundColor = "rgb("+c+","+c+","+c+")";
+    requestAnimationFrame(tick);
+  };
+  </script>
+</body>
+</html>
diff --git a/tools/perf/page_sets/key_idle_power_cases/set-timeout.html b/tools/perf/page_sets/key_idle_power_cases/set-timeout.html
new file mode 100644
index 0000000..df04bbfa
--- /dev/null
+++ b/tools/perf/page_sets/key_idle_power_cases/set-timeout.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0">
+  <title>setTimeout Test</title>
+  <style type="text/css">
+  html, body {
+    height: 100%;
+    padding: 0px;
+    margin: 0px;
+  }
+  #container {
+    width: 100%;
+    height: 100%;
+    background: rgb(128, 128, 128);
+  }
+  </style>
+</head>
+<body>
+  <div id="container"></div>
+  <script type="text/javascript">
+  var container = document.getElementById('container');
+  var c = 128;
+  tick();
+  function tick() {
+    ++c;
+    c %= 256;
+    container.style.backgroundColor = "rgb("+c+","+c+","+c+")";
+    setTimeout(tick, 16.66666);
+  };
+  </script>
+</body>
+</html>
diff --git a/tools/perf/record_wpr b/tools/perf/record_wpr
index e12055f..c579adf 100755
--- a/tools/perf/record_wpr
+++ b/tools/perf/record_wpr
@@ -11,7 +11,7 @@
 _telemetry_path = os.path.join(_perf_dir, os.pardir, 'telemetry')
 sys.path.append(_telemetry_path)
 
-from telemetry.page import record_wpr
+from telemetry import record_wpr
 
 if __name__ == '__main__':
   sys.exit(record_wpr.Main(_perf_dir))
diff --git a/tools/telemetry/telemetry/TELEMETRY_DEPS b/tools/telemetry/telemetry/TELEMETRY_DEPS
index 1cfc34c..1bf6493 100644
--- a/tools/telemetry/telemetry/TELEMETRY_DEPS
+++ b/tools/telemetry/telemetry/TELEMETRY_DEPS
@@ -46,6 +46,7 @@
     "build/android/android_no_jni_exports.lst",
     "build/android/ant/apk-package.xml",
     "build/android/ant/chromium-debug.keystore",
+    "build/android/apkbuilder_action.gypi",
     "build/android/asan_symbolize.py",
     "build/android/avd.py",
     "build/android/bb_run_sharded_steps.py",
@@ -134,6 +135,7 @@
     "build/android/native_app_dependencies.gypi",
     "build/android/ndk.gyp",
     "build/android/pack_arm_relocations.gypi",
+    "build/android/package_resources_action.gypi",
     "build/android/provision_devices.py",
     "build/android/push_libraries.gypi",
     "build/android/rezip.gyp",
diff --git a/tools/telemetry/telemetry/core/backends/chrome_inspector/inspector_websocket_unittest.py b/tools/telemetry/telemetry/core/backends/chrome_inspector/inspector_websocket_unittest.py
index 397f7ee..0db7face 100644
--- a/tools/telemetry/telemetry/core/backends/chrome_inspector/inspector_websocket_unittest.py
+++ b/tools/telemetry/telemetry/core/backends/chrome_inspector/inspector_websocket_unittest.py
@@ -112,6 +112,7 @@
     self.assertEqual(1, len(results))
     self.assertEqual('Test2.foo', results[0]['method'])
 
+  @decorators.Disabled('chromeos')  # crbug.com/483212
   def testUnregisterDomainWithUnregisteredDomain(self):
     inspector = inspector_websocket.InspectorWebsocket()
     with self.assertRaises(AssertionError):
diff --git a/tools/telemetry/telemetry/core/browser_info.py b/tools/telemetry/telemetry/core/browser_info.py
index df85029..94cb1543 100644
--- a/tools/telemetry/telemetry/core/browser_info.py
+++ b/tools/telemetry/telemetry/core/browser_info.py
@@ -53,3 +53,7 @@
     branch_num = (
         self._browser._browser_backend.devtools_client.GetChromeBranchNumber())
     return branch_num >= 2332
+
+  @property
+  def browser_type(self):
+    return self._browser.browser_type
diff --git a/tools/telemetry/telemetry/core/platform/android_action_runner.py b/tools/telemetry/telemetry/core/platform/android_action_runner.py
index 8728c9f..c2f79b4 100644
--- a/tools/telemetry/telemetry/core/platform/android_action_runner.py
+++ b/tools/telemetry/telemetry/core/platform/android_action_runner.py
@@ -116,15 +116,28 @@
     """
     self._platform_backend.adb.RunShellCommand('input roll %s %s' % (dx, dy))
 
+  def EnsureScreenOn(self):
+    """If device screen is off, turn screen on.
+    If the screen is already on, return immediately.
+
+    Raises:
+      Timeout: If the screen is off and device fails to turn screen on.
+    """
+    if self._platform_backend.IsScreenOn():
+      return
+
+    self._ToggleScreenOn()
+    util.WaitFor(self._platform_backend.IsScreenOn, 5)
+
   def TurnScreenOn(self):
     """If device screen is off, turn screen on.
-    If the screen is already on, this method returns immediately.
+    If the screen is already on, log a warning and return immediately.
 
     Raises:
       Timeout: If the screen is off and device fails to turn screen on.
     """
     if not self._platform_backend.IsScreenOn():
-      self._platform_backend.adb.RunShellCommand('input keyevent 26')
+      self._ToggleScreenOn()
     else:
       logging.warning('Screen on when expected off.')
       return
@@ -133,7 +146,7 @@
 
   def TurnScreenOff(self):
     """If device screen is on, turn screen off.
-    If the screen is already off, this method returns immediately.
+    If the screen is already off, log a warning and return immediately.
 
     Raises:
       Timeout: If the screen is on and device fails to turn screen off.
@@ -142,8 +155,7 @@
       return not self._platform_backend.IsScreenOn()
 
     if self._platform_backend.IsScreenOn():
-      self._platform_backend.adb.RunShellCommand(
-          'input keyevent 26')
+      self._ToggleScreenOn()
     else:
       logging.warning('Screen off when expected on.')
       return
@@ -152,7 +164,7 @@
 
   def UnlockScreen(self):
     """If device screen is locked, unlocks it.
-    If the device is not locked, this method returns immediately.
+    If the device is not locked, log a warning and return immediately.
 
     Raises:
       Timeout: If device fails to unlock screen.
@@ -167,3 +179,6 @@
       return
 
     util.WaitFor(is_screen_unlocked, 5)
+
+  def _ToggleScreenOn(self):
+    self._platform_backend.adb.RunShellCommand('input keyevent 26')
diff --git a/tools/telemetry/telemetry/core/user_agent_unittest.py b/tools/telemetry/telemetry/core/user_agent_unittest.py
index b5160b0..d0539fa1 100644
--- a/tools/telemetry/telemetry/core/user_agent_unittest.py
+++ b/tools/telemetry/telemetry/core/user_agent_unittest.py
@@ -2,6 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+from telemetry import decorators
 from telemetry.core import user_agent
 from telemetry.unittest_util import tab_test_case
 
@@ -11,6 +12,7 @@
   def CustomizeBrowserOptions(cls, options):
     options.browser_user_agent_type = 'mobile'
 
+  @decorators.Disabled('chromeos')  # crbug.com/483212
   def testUserAgent(self):
     ua = self._tab.EvaluateJavaScript('window.navigator.userAgent')
     self.assertEquals(ua, user_agent.UA_TYPE_MAPPING['mobile'])
@@ -20,6 +22,7 @@
   def CustomizeBrowserOptions(cls, options):
     options.browser_user_agent_type = 'tablet'
 
+  @decorators.Disabled('chromeos')  # crbug.com/483212
   def testUserAgent(self):
     ua = self._tab.EvaluateJavaScript('window.navigator.userAgent')
     self.assertEquals(ua, user_agent.UA_TYPE_MAPPING['tablet'])
@@ -29,6 +32,7 @@
   def CustomizeBrowserOptions(cls, options):
     options.browser_user_agent_type = 'desktop'
 
+  @decorators.Disabled('chromeos')  # crbug.com/483212
   def testUserAgent(self):
     ua = self._tab.EvaluateJavaScript('window.navigator.userAgent')
     self.assertEquals(ua, user_agent.UA_TYPE_MAPPING['desktop'])
diff --git a/tools/telemetry/telemetry/page/record_wpr.py b/tools/telemetry/telemetry/record_wpr.py
similarity index 67%
rename from tools/telemetry/telemetry/page/record_wpr.py
rename to tools/telemetry/telemetry/record_wpr.py
index 6d0ecbf..8ce1974 100644
--- a/tools/telemetry/telemetry/page/record_wpr.py
+++ b/tools/telemetry/telemetry/record_wpr.py
@@ -2,6 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import argparse
 import logging
 import sys
 
@@ -16,7 +17,8 @@
 from telemetry.page import test_expectations
 from telemetry.results import results_options
 
-class RecorderPageTest(page_test.PageTest):  # pylint: disable=W0223
+
+class RecorderPageTest(page_test.PageTest):
   def __init__(self):
     super(RecorderPageTest, self).__init__()
     self.page_test = None
@@ -68,14 +70,43 @@
       super(RecorderPageTest, self).RunNavigateSteps(page, tab)
 
 
+def _GetSubclasses(base_dir, cls):
+  """ Return all subclasses of |cls| in |base_dir|.
+  Args:
+    cls: a class
+  Returns:
+
+  """
+  return discover.DiscoverClasses(base_dir, base_dir, cls,
+                                  index_by_class_name=True)
+
+
 def _MaybeGetInstanceOfClass(target, base_dir, cls):
   if isinstance(target, cls):
     return target
-  classes = discover.DiscoverClasses(base_dir, base_dir, cls,
-                                     index_by_class_name=True)
+  classes = _GetSubclasses(base_dir, cls)
   return classes[target]() if target in classes else None
 
 
+def _PrintAllBenchmarks(base_dir, output_stream):
+  # TODO: reuse the logic of finding supported benchmarks in benchmark_runner.py
+  # so this only prints out benchmarks that are supported by the recording
+  # platform.
+  classes = _GetSubclasses(base_dir, benchmark.Benchmark)
+  output_stream.write('Available benchmarks\' names:\n\n')
+  for k in classes:
+    output_stream.write('%s\n' % k)
+
+
+def _PrintAllUserStories(base_dir, output_stream):
+  output_stream.write('Available page sets\' names:\n\n')
+  # TODO: actually print all user stories once record_wpr support general
+  # user stories recording.
+  classes = _GetSubclasses(base_dir, page_set.PageSet)
+  for k in classes:
+    output_stream.write('%s\n' % k)
+
+
 class WprRecorder(object):
 
   def __init__(self, base_dir, target, args=None):
@@ -84,7 +115,7 @@
 
     self._benchmark = _MaybeGetInstanceOfClass(target, base_dir,
                                                benchmark.Benchmark)
-    self._parser = self._options.CreateParser(usage='%prog <PageSet|Benchmark>')
+    self._parser = self._options.CreateParser(usage='See %prog --help')
     self._AddCommandLineArgs()
     self._ParseArgs(args)
     self._ProcessCommandLineArgs()
@@ -166,22 +197,43 @@
         upload_to_cloud_storage)
 
 
+# TODO(nednguyen): use benchmark.Environment instead of base_dir for discovering
+# benchmark & user story classes.
 def Main(base_dir):
-  quick_args = []
-  upload_to_cloud_storage = False
 
-  for a in sys.argv[1:]:
-    if not a.startswith('-'):
-      quick_args.append(a)
-    elif a == '--upload':
-      upload_to_cloud_storage = True
+  parser = argparse.ArgumentParser(
+      usage='Record a benchmark or a user story (page set).')
+  parser.add_argument(
+      'benchmark', type=str,
+      help=('benchmark name. This argument is optional. If both benchmark name '
+            'and user story name are specified, this takes precedence as the '
+            'target of the recording.'),
+      nargs='?')
+  parser.add_argument('--story', dest='story', type=str,
+                      help='user story (page set) name')
+  parser.add_argument('--list-stories', dest='list_stories',
+                      action='store_true', help='list all user story names.')
+  parser.add_argument('--list-benchmarks', dest='list_benchmarks',
+                      action='store_true', help='list all benchmark names.')
+  parser.add_argument('--upload', action='store_true',
+                      help='upload to cloud storage.')
+  args, extra_args = parser.parse_known_args()
 
-  if len(quick_args) != 1:
-    print >> sys.stderr, 'Usage: record_wpr <PageSet|Benchmark> [--upload]\n'
-    sys.exit(1)
-  target = quick_args.pop()
-  wpr_recorder = WprRecorder(base_dir, target)
+  if args.list_benchmarks:
+    _PrintAllBenchmarks(base_dir, sys.stderr)
+  elif args.list_stories:
+    _PrintAllUserStories(base_dir, sys.stderr)
+
+  target = args.benchmark or args.story
+
+  if not target:
+    return 0
+
+  # TODO(nednguyen): update WprRecorder so that it handles the difference
+  # between recording a benchmark vs recording a user story better based on
+  # the distinction between args.benchmark & args.story
+  wpr_recorder = WprRecorder(base_dir, target, extra_args)
   results = wpr_recorder.CreateResults()
   wpr_recorder.Record(results)
-  wpr_recorder.HandleResults(results, upload_to_cloud_storage)
+  wpr_recorder.HandleResults(results, args.upload)
   return min(255, len(results.failures))
diff --git a/tools/telemetry/telemetry/page/record_wpr_unittest.py b/tools/telemetry/telemetry/record_wpr_unittest.py
similarity index 99%
rename from tools/telemetry/telemetry/page/record_wpr_unittest.py
rename to tools/telemetry/telemetry/record_wpr_unittest.py
index 367461c..c0ba943 100644
--- a/tools/telemetry/telemetry/page/record_wpr_unittest.py
+++ b/tools/telemetry/telemetry/record_wpr_unittest.py
@@ -6,13 +6,13 @@
 import sys
 
 from telemetry import benchmark
+from telemetry import record_wpr
 from telemetry.core import util
 from telemetry.core import wpr_modes
 from telemetry import decorators
 from telemetry.page import page as page_module
 from telemetry.page import page_set as page_set_module
 from telemetry.page import page_test
-from telemetry.page import record_wpr
 from telemetry.unittest_util import tab_test_case
 
 
diff --git a/tools/valgrind/gtest_exclude/browser_tests.gtest-drmemory.txt b/tools/valgrind/gtest_exclude/browser_tests.gtest-drmemory.txt
index 9e10b47..6823027 100644
--- a/tools/valgrind/gtest_exclude/browser_tests.gtest-drmemory.txt
+++ b/tools/valgrind/gtest_exclude/browser_tests.gtest-drmemory.txt
@@ -35,8 +35,3 @@
 
 # https://crbug.com/480721
 OutOfProcessProxyResolverBrowserTest.Verify
-
-# https://crbug.com/484910
-PasswordAutofillAgentTest.ClearPreviewWithInlineAutocompletedUsername
-PasswordAutofillAgentTest.InlineAutocomplete
-PasswordAutofillAgentTest.RememberLastNonEmptyUsernameAndPasswordOnSubmit_UserCleared
diff --git a/tools/valgrind/gtest_exclude/net_unittests.gtest-drmemory_win-xp.txt b/tools/valgrind/gtest_exclude/net_unittests.gtest-drmemory_win-xp.txt
deleted file mode 100644
index 9d77b20..0000000
--- a/tools/valgrind/gtest_exclude/net_unittests.gtest-drmemory_win-xp.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-# https://github.com/DynamoRIO/drmemory/issues/842
-# Failing and then crashing.
-HttpNetworkTransationSpdy21Test.HttpsProxySpdy*
diff --git a/ui/android/java/src/org/chromium/ui/picker/DateTimePickerDialog.java b/ui/android/java/src/org/chromium/ui/picker/DateTimePickerDialog.java
index c9dde077..8a0ff359 100644
--- a/ui/android/java/src/org/chromium/ui/picker/DateTimePickerDialog.java
+++ b/ui/android/java/src/org/chromium/ui/picker/DateTimePickerDialog.java
@@ -99,6 +99,7 @@
     private void tryNotifyDateTimeSet() {
         if (mCallBack != null) {
             mDatePicker.clearFocus();
+            mTimePicker.clearFocus();
             mCallBack.onDateTimeSet(mDatePicker, mTimePicker, mDatePicker.getYear(),
                     mDatePicker.getMonth(), mDatePicker.getDayOfMonth(),
                     mTimePicker.getCurrentHour(), mTimePicker.getCurrentMinute());
diff --git a/ui/android/java/src/org/chromium/ui/picker/MultiFieldTimePickerDialog.java b/ui/android/java/src/org/chromium/ui/picker/MultiFieldTimePickerDialog.java
index f8647ec..43cee0e8 100644
--- a/ui/android/java/src/org/chromium/ui/picker/MultiFieldTimePickerDialog.java
+++ b/ui/android/java/src/org/chromium/ui/picker/MultiFieldTimePickerDialog.java
@@ -247,12 +247,12 @@
     }
 
     private void notifyDateSet() {
-        int hour = mHourSpinner.getValue();
-        int minute = mMinuteSpinner.getValue();
-        int sec = mSecSpinner.getValue();
-        int milli = mMilliSpinner.getValue() * mStep + mBaseMilli;
+        int hour = getPickerValue(mHourSpinner);
+        int minute = getPickerValue(mMinuteSpinner);
+        int sec = getPickerValue(mSecSpinner);
+        int milli = getPickerValue(mMilliSpinner) * mStep + mBaseMilli;
         if (!mIs24hourFormat) {
-            int ampm = mAmPmSpinner.getValue();
+            int ampm = getPickerValue(mAmPmSpinner);
             if (hour == 12) {
                 hour = 0;
             }
@@ -261,6 +261,15 @@
         mListener.onTimeSet(hour, minute, sec, milli);
     }
 
+    /**
+     * Clear focus before retrieving so that values inserted with
+     * keyboard are taken into account.
+    */
+    private int getPickerValue(NumberPicker picker) {
+        picker.clearFocus();
+        return picker.getValue();
+    }
+
     private static class NumberFormatter implements NumberPicker.Formatter {
         private final String mFormat;
 
diff --git a/ui/base/cocoa/nsview_additions.h b/ui/base/cocoa/nsview_additions.h
index 467c04fa..62043b2a 100644
--- a/ui/base/cocoa/nsview_additions.h
+++ b/ui/base/cocoa/nsview_additions.h
@@ -37,7 +37,12 @@
 
 // Draw using ancestorView's drawRect function into this view's rect. Do any
 // required translating or flipping to transform between the two coordinate
-// systems.
+// systems, and optionally clip to the ancestor view's bounds.
+- (void)cr_drawUsingAncestor:(NSView*)ancestorView inRect:(NSRect)dirtyRect
+     clippedToAncestorBounds:(BOOL)clipToAncestorBounds;
+
+// Same as cr_drawUsingAncestor:inRect:clippedToAncestorBounds: except always
+// clips to the ancestor view's bounds.
 - (void)cr_drawUsingAncestor:(NSView*)ancestorView inRect:(NSRect)dirtyRect;
 
 // Used by ancestorView in the above draw call, to look up the child view that
diff --git a/ui/base/cocoa/nsview_additions.mm b/ui/base/cocoa/nsview_additions.mm
index 49f18b0..1bfd3a5 100644
--- a/ui/base/cocoa/nsview_additions.mm
+++ b/ui/base/cocoa/nsview_additions.mm
@@ -75,7 +75,8 @@
 static NSView* g_ancestorBeingDrawnFrom = nil;
 static NSView* g_childBeingDrawnTo = nil;
 
-- (void)cr_drawUsingAncestor:(NSView*)ancestorView inRect:(NSRect)dirtyRect {
+- (void)cr_drawUsingAncestor:(NSView*)ancestorView inRect:(NSRect)dirtyRect
+     clippedToAncestorBounds:(BOOL)clipToAncestorBounds {
   gfx::ScopedNSGraphicsContextSaveGState scopedGSState;
   NSRect frame = [self convertRect:[self bounds] toView:ancestorView];
   NSAffineTransform* transform = [NSAffineTransform transform];
@@ -91,13 +92,21 @@
   DCHECK(!g_ancestorBeingDrawnFrom && !g_childBeingDrawnTo);
   g_ancestorBeingDrawnFrom = ancestorView;
   g_childBeingDrawnTo = self;
-  [ancestorView drawRect:NSIntersectionRect(
-                             [ancestorView bounds],
-                             [self convertRect:dirtyRect toView:ancestorView])];
+  NSRect drawRect = [self convertRect:dirtyRect toView:ancestorView];
+  if (clipToAncestorBounds) {
+    drawRect = NSIntersectionRect([ancestorView bounds], drawRect);
+  }
+  [ancestorView drawRect:drawRect];
   g_childBeingDrawnTo = nil;
   g_ancestorBeingDrawnFrom = nil;
 }
 
+- (void)cr_drawUsingAncestor:(NSView*)ancestorView inRect:(NSRect)dirtyRect {
+  [self cr_drawUsingAncestor:ancestorView
+                      inRect:dirtyRect
+     clippedToAncestorBounds:YES];
+}
+
 - (NSView*)cr_viewBeingDrawnTo {
   if (!g_ancestorBeingDrawnFrom)
     return self;
diff --git a/ui/compositor/layer.cc b/ui/compositor/layer.cc
index c1347c4e..a46c6b9 100644
--- a/ui/compositor/layer.cc
+++ b/ui/compositor/layer.cc
@@ -796,7 +796,7 @@
   void AppendAsTraceFormat(std::string* out) const override {
     base::DictionaryValue dictionary;
     dictionary.SetString("layer_name", name_);
-    base::JSONWriter::Write(&dictionary, out);
+    base::JSONWriter::Write(dictionary, out);
   }
 
  private:
diff --git a/ui/events/event_unittest.cc b/ui/events/event_unittest.cc
index 0ac9335..38ad283 100644
--- a/ui/events/event_unittest.cc
+++ b/ui/events/event_unittest.cc
@@ -351,7 +351,7 @@
   ASSERT_EQ(kDomCodeForSpace,
             ui::KeycodeConverter::CodeStringToDomCode(kCodeForSpace));
   const uint16 kNativeCodeSpace =
-      ui::KeycodeConverter::CodeToNativeKeycode(kCodeForSpace);
+      ui::KeycodeConverter::DomCodeToNativeKeycode(kDomCodeForSpace);
   ASSERT_NE(ui::KeycodeConverter::InvalidNativeKeycode(), kNativeCodeSpace);
   ASSERT_EQ(kNativeCodeSpace,
             ui::KeycodeConverter::DomCodeToNativeKeycode(kDomCodeForSpace));
@@ -433,8 +433,10 @@
 
 #if defined(USE_X11) || defined(OS_WIN)
 TEST(EventTest, AutoRepeat) {
-  const uint16 kNativeCodeA = ui::KeycodeConverter::CodeToNativeKeycode("KeyA");
-  const uint16 kNativeCodeB = ui::KeycodeConverter::CodeToNativeKeycode("KeyB");
+  const uint16 kNativeCodeA =
+      ui::KeycodeConverter::DomCodeToNativeKeycode(DomCode::KEY_A);
+  const uint16 kNativeCodeB =
+      ui::KeycodeConverter::DomCodeToNativeKeycode(DomCode::KEY_B);
 #if defined(USE_X11)
   ScopedXI2Event native_event_a_pressed;
   native_event_a_pressed.InitKeyEvent(ET_KEY_PRESSED, VKEY_A, kNativeCodeA);
diff --git a/ui/events/keycodes/dom/keycode_converter.cc b/ui/events/keycodes/dom/keycode_converter.cc
index c77b8aba..c438a66 100644
--- a/ui/events/keycodes/dom/keycode_converter.cc
+++ b/ui/events/keycodes/dom/keycode_converter.cc
@@ -69,18 +69,6 @@
 }
 
 // static
-const char* KeycodeConverter::NativeKeycodeToCode(int native_keycode) {
-  for (size_t i = 0; i < kKeycodeMapEntries; ++i) {
-    if (usb_keycode_map[i].native_keycode == native_keycode) {
-      if (usb_keycode_map[i].code != NULL)
-        return usb_keycode_map[i].code;
-      break;
-    }
-  }
-  return "";
-}
-
-// static
 DomCode KeycodeConverter::NativeKeycodeToDomCode(int native_keycode) {
   for (size_t i = 0; i < kKeycodeMapEntries; ++i) {
     if (usb_keycode_map[i].native_keycode == native_keycode) {
@@ -93,20 +81,6 @@
 }
 
 // static
-int KeycodeConverter::CodeToNativeKeycode(const char* code) {
-  if (!code || !*code)
-    return InvalidNativeKeycode();
-
-  for (size_t i = 0; i < kKeycodeMapEntries; ++i) {
-    if (usb_keycode_map[i].code &&
-        strcmp(usb_keycode_map[i].code, code) == 0) {
-      return usb_keycode_map[i].native_keycode;
-    }
-  }
-  return InvalidNativeKeycode();
-}
-
-// static
 int KeycodeConverter::DomCodeToNativeKeycode(DomCode code) {
   return UsbKeycodeToNativeKeycode(static_cast<uint32_t>(code));
 }
@@ -129,7 +103,14 @@
 
 // static
 const char* KeycodeConverter::DomCodeToCodeString(DomCode dom_code) {
-  return UsbKeycodeToCode(static_cast<uint32_t>(dom_code));
+  for (size_t i = 0; i < kKeycodeMapEntries; ++i) {
+    if (usb_keycode_map[i].usb_keycode == static_cast<uint32_t>(dom_code)) {
+      if (usb_keycode_map[i].code)
+        return usb_keycode_map[i].code;
+      break;
+    }
+  }
+  return "";
 }
 
 // static
@@ -239,18 +220,6 @@
 }
 
 // static
-const char* KeycodeConverter::UsbKeycodeToCode(uint32_t usb_keycode) {
-  for (size_t i = 0; i < kKeycodeMapEntries; ++i) {
-    if (usb_keycode_map[i].usb_keycode == usb_keycode) {
-      if (usb_keycode_map[i].code)
-        return usb_keycode_map[i].code;
-      break;
-    }
-  }
-  return "";
-}
-
-// static
 DomCode KeycodeConverter::UsbKeycodeToDomCode(uint32_t usb_keycode) {
   for (size_t i = 0; i < kKeycodeMapEntries; ++i) {
     if (usb_keycode_map[i].usb_keycode == usb_keycode)
@@ -260,6 +229,15 @@
 }
 
 // static
+uint32_t KeycodeConverter::DomCodeToUsbKeycode(DomCode dom_code) {
+  for (size_t i = 0; i < kKeycodeMapEntries; ++i) {
+    if (usb_keycode_map[i].usb_keycode == static_cast<uint32_t>(dom_code))
+      return usb_keycode_map[i].usb_keycode;
+  }
+  return InvalidUsbKeycode();
+}
+
+// static
 uint32_t KeycodeConverter::CodeToUsbKeycode(const char* code) {
   if (!code || !*code)
     return InvalidUsbKeycode();
diff --git a/ui/events/keycodes/dom/keycode_converter.h b/ui/events/keycodes/dom/keycode_converter.h
index 1f1fed0d..fb1ac041 100644
--- a/ui/events/keycodes/dom/keycode_converter.h
+++ b/ui/events/keycodes/dom/keycode_converter.h
@@ -45,16 +45,9 @@
   // Return the value that identifies an invalid native keycode.
   static int InvalidNativeKeycode();
 
-  // Convert a native (Mac/Win/Linux) keycode into the |code| string.
-  // The returned pointer references a static global string.
-  static const char* NativeKeycodeToCode(int native_keycode);
-
   // Convert a native (Mac/Win/Linux) keycode into a DomCode.
   static DomCode NativeKeycodeToDomCode(int native_keycode);
 
-  // Convert a UI Events |code| string value into a native keycode.
-  static int CodeToNativeKeycode(const char* code);
-
   // Convert a DomCode into a native keycode.
   static int DomCodeToNativeKeycode(DomCode code);
 
@@ -88,13 +81,12 @@
   // Convert a platform native keycode into an equivalent USB keycode.
   static uint32_t NativeKeycodeToUsbKeycode(int native_keycode);
 
-  // Convert a USB keycode into the string with the DOM3 |code| value.
-  // The returned pointer references a static global string.
-  static const char* UsbKeycodeToCode(uint32_t usb_keycode);
-
   // Convert a USB keycode into a DomCode.
   static DomCode UsbKeycodeToDomCode(uint32_t usb_keycode);
 
+  // Convert a DomCode into a USB keycode.
+  static uint32_t DomCodeToUsbKeycode(DomCode dom_code);
+
   // Convert a DOM3 Event |code| string into a USB keycode value.
   static uint32_t CodeToUsbKeycode(const char* code);
 
diff --git a/ui/events/keycodes/dom/keycode_converter_unittest.cc b/ui/events/keycodes/dom/keycode_converter_unittest.cc
index c3149ce..f5da9a092 100644
--- a/ui/events/keycodes/dom/keycode_converter_unittest.cc
+++ b/ui/events/keycodes/dom/keycode_converter_unittest.cc
@@ -38,7 +38,7 @@
   EXPECT_EQ(ui::KeycodeConverter::InvalidNativeKeycode(),
             keycode_map[0].native_keycode);
   EXPECT_EQ(ui::KeycodeConverter::InvalidNativeKeycode(),
-            ui::KeycodeConverter::CodeToNativeKeycode("Unidentified"));
+            ui::KeycodeConverter::DomCodeToNativeKeycode(ui::DomCode::NONE));
 
   // Verify that there are no duplicate entries in the mapping.
   std::map<uint32_t, uint16_t> usb_to_native;
@@ -55,17 +55,14 @@
         entry->native_keycode,
         ui::KeycodeConverter::UsbKeycodeToNativeKeycode(entry->usb_keycode));
 
-    // Verify CodeToNativeKeycode and NativeKeycodeToCode work correctly.
+    // Verify DomCodeToNativeKeycode works correctly.
+    ui::DomCode dom_code =
+        ui::KeycodeConverter::CodeStringToDomCode(entry->code);
     if (entry->code) {
       EXPECT_EQ(entry->native_keycode,
-                ui::KeycodeConverter::CodeToNativeKeycode(entry->code));
-      EXPECT_STREQ(
-          entry->code,
-          ui::KeycodeConverter::NativeKeycodeToCode(entry->native_keycode));
-    }
-    else {
-      EXPECT_EQ(ui::KeycodeConverter::InvalidNativeKeycode(),
-                ui::KeycodeConverter::CodeToNativeKeycode(entry->code));
+                ui::KeycodeConverter::DomCodeToNativeKeycode(dom_code));
+    } else {
+      EXPECT_EQ(ui::DomCode::NONE, dom_code);
     }
 
     // Verify that the USB or native codes aren't duplicated.
diff --git a/ui/events/latency_info.cc b/ui/events/latency_info.cc
index 96fe74c1..d815790 100644
--- a/ui/events/latency_info.cc
+++ b/ui/events/latency_info.cc
@@ -108,7 +108,7 @@
 
 void LatencyInfoTracedValue::AppendAsTraceFormat(std::string* out) const {
   std::string tmp;
-  base::JSONWriter::Write(value_.get(), &tmp);
+  base::JSONWriter::Write(*value_, &tmp);
   *out += tmp;
 }
 
@@ -296,7 +296,7 @@
       }
 
       TRACE_EVENT_COPY_ASYNC_BEGIN_WITH_TIMESTAMP0(
-          "benchmark",
+          "benchmark,latencyInfo",
           trace_name.c_str(),
           TRACE_ID_DONT_MANGLE(trace_id),
           ts);
@@ -332,7 +332,7 @@
     terminated = true;
 
     if (*benchmark_enabled) {
-      TRACE_EVENT_COPY_ASYNC_END1("benchmark",
+      TRACE_EVENT_COPY_ASYNC_END1("benchmark,latencyInfo",
                                   trace_name.c_str(),
                                   TRACE_ID_DONT_MANGLE(trace_id),
                                   "data", AsTraceableData(*this));
diff --git a/ui/file_manager/file_manager/background/js/volume_manager.js b/ui/file_manager/file_manager/background/js/volume_manager.js
index ac7a4505..0c0e6c8 100644
--- a/ui/file_manager/file_manager/background/js/volume_manager.js
+++ b/ui/file_manager/file_manager/background/js/volume_manager.js
@@ -27,6 +27,7 @@
  * @param {boolean} hasMedia When true the volume has been identified
  *     as containing media such as photos or videos.
  * @param {boolean} configurable When true, then the volume can be configured.
+ * @param {VolumeManagerCommon.Source} source Source of the volume's data.
  */
 function VolumeInfo(
     volumeType,
@@ -40,7 +41,8 @@
     label,
     extensionId,
     hasMedia,
-    configurable) {
+    configurable,
+    source) {
   this.volumeType_ = volumeType;
   this.volumeId_ = volumeId;
   this.fileSystem_ = fileSystem;
@@ -83,6 +85,7 @@
   this.extensionId_ = extensionId;
   this.hasMedia_ = hasMedia;
   this.configurable_ = configurable;
+  this.source_ = source;
 }
 
 VolumeInfo.prototype = /** @struct */ {
@@ -170,6 +173,12 @@
    */
   get configurable() {
     return this.configurable_;
+  },
+  /**
+   * @return {VolumeManagerCommon.Source} Source of the volume's data.
+   */
+  get source() {
+    return this.source_;
   }
 };
 
@@ -254,124 +263,104 @@
   }
 
   console.debug('Requesting file system.');
-  var configurable = false;
-
   return new Promise(
       function(resolve, reject) {
-        if (volumeMetadata.volumeType !==
-            VolumeManagerCommon.VolumeType.PROVIDED) {
-          resolve();
-        }
-
-        chrome.fileManagerPrivate.getProvidingExtensions(
-            function(extensions) {
-              if (chrome.runtime.lastError) {
+        chrome.fileSystem.requestFileSystem(
+            {
+              volumeId: volumeMetadata.volumeId,
+              writable: !volumeMetadata.isReadOnly
+            },
+            function(isolatedFileSystem) {
+              if (chrome.runtime.lastError)
                 reject(chrome.runtime.lastError.message);
-                return;
-              }
-              configurable = extensions.some(function(extension) {
-                return extension.extensionId === volumeMetadata.extensionId &&
-                    extension.configurable;
-              });
-              resolve();
+              else
+                resolve(isolatedFileSystem);
             });
       })
-      .then(
-          function() {
-            return new Promise(function(resolve, reject) {
-              chrome.fileSystem.requestFileSystem(
-                  {
-                    volumeId: volumeMetadata.volumeId,
-                    writable: !volumeMetadata.isReadOnly
-                  },
-                  function(isolatedFileSystem) {
-                    if (chrome.runtime.lastError)
-                      reject(chrome.runtime.lastError.message);
-                    else
-                      resolve(isolatedFileSystem);
-                  });
-            });
-          })
-      .then(
-          /**
-           * @param {!FileSystem} isolatedFileSystem
-           */
-          function(isolatedFileSystem) {
-            // Since File System API works on isolated entries only, we need to
-            // convert it back to external one.
-            // TODO(mtomasz): Make Files app work on isolated entries.
-            return new Promise(function(resolve, reject) {
-              chrome.fileManagerPrivate.resolveIsolatedEntries(
-                  [isolatedFileSystem.root],
-                  function(entries) {
-                    if (chrome.runtime.lastError)
-                      reject(chrome.runtime.lastError.message);
-                    else if (!entries[0])
-                      reject('Resolving for external context failed.');
-                    else
-                      resolve(entries[0].filesystem);
-                  });
+  .then(
+      /**
+       * @param {!FileSystem} isolatedFileSystem
+       */
+      function(isolatedFileSystem) {
+        // Since File System API works on isolated entries only, we need to
+        // convert it back to external one.
+        // TODO(mtomasz): Make Files app work on isolated entries.
+        return new Promise(function(resolve, reject) {
+          chrome.fileManagerPrivate.resolveIsolatedEntries(
+              [isolatedFileSystem.root],
+              function(entries) {
+                if (chrome.runtime.lastError)
+                  reject(chrome.runtime.lastError.message);
+                else if (!entries[0])
+                  reject('Resolving for external context failed.');
+                else
+                  resolve(entries[0].filesystem);
               });
-           })
-      .then(
-          /**
-           * @param {!FileSystem} fileSystem
-           */
-          function(fileSystem) {
-            console.debug('File system obtained: ' + volumeMetadata.volumeId);
-              if (volumeMetadata.volumeType ===
-                  VolumeManagerCommon.VolumeType.DRIVE) {
-                // After file system is mounted, we "read" drive grand root
-                // entry at first. This triggers full feed fetch on background.
-                // Note: we don't need to handle errors here, because even if
-                // it fails, accessing to some path later will just become
-                // a fast-fetch and it re-triggers full-feed fetch.
-                fileSystem.root.createReader().readEntries(
-                    function() { /* do nothing */ },
-                    function(error) {
-                      console.error(
-                          'Triggering full feed fetch is failed: ' +
-                          error.name);
-                    });
-              }
-              return new VolumeInfo(
-                  /** @type {VolumeManagerCommon.VolumeType} */
-                  (volumeMetadata.volumeType),
-                  volumeMetadata.volumeId,
-                  fileSystem,
-                  volumeMetadata.mountCondition,
-                  volumeMetadata.deviceType,
-                  volumeMetadata.devicePath,
-                  volumeMetadata.isReadOnly,
-                  volumeMetadata.profile,
-                  localizedLabel,
-                  volumeMetadata.extensionId,
-                  volumeMetadata.hasMedia,
-                  configurable);
-      })
-      .catch(
-          /**
-           * @param {*} error
-           */
-          function(error) {
-            console.error('Failed to mount a file system: ' +
-                volumeMetadata.volumeId + ' because of: ' +
-                (error.stack || error));
-            return new VolumeInfo(
-                /** @type {VolumeManagerCommon.VolumeType} */
-                (volumeMetadata.volumeType),
-                volumeMetadata.volumeId,
-                null,  // File system is not found.
-                volumeMetadata.mountCondition,
-                volumeMetadata.deviceType,
-                volumeMetadata.devicePath,
-                volumeMetadata.isReadOnly,
-                volumeMetadata.profile,
-                localizedLabel,
-                volumeMetadata.extensionId,
-                volumeMetadata.hasMedia,
-                configurable);
           });
+       })
+  .then(
+      /**
+       * @param {!FileSystem} fileSystem
+       */
+      function(fileSystem) {
+        console.debug('File system obtained: ' + volumeMetadata.volumeId);
+        if (volumeMetadata.volumeType ===
+            VolumeManagerCommon.VolumeType.DRIVE) {
+          // After file system is mounted, we "read" drive grand root
+          // entry at first. This triggers full feed fetch on background.
+          // Note: we don't need to handle errors here, because even if
+          // it fails, accessing to some path later will just become
+          // a fast-fetch and it re-triggers full-feed fetch.
+          fileSystem.root.createReader().readEntries(
+              function() { /* do nothing */ },
+              function(error) {
+                console.error(
+                    'Triggering full feed fetch is failed: ' +
+                    error.name);
+              });
+        }
+        return new VolumeInfo(
+            /** @type {VolumeManagerCommon.VolumeType} */
+            (volumeMetadata.volumeType),
+            volumeMetadata.volumeId,
+            fileSystem,
+            volumeMetadata.mountCondition,
+            volumeMetadata.deviceType,
+            volumeMetadata.devicePath,
+            volumeMetadata.isReadOnly,
+            volumeMetadata.profile,
+            localizedLabel,
+            volumeMetadata.extensionId,
+            volumeMetadata.hasMedia,
+            volumeMetadata.configurable,
+            /** @type {VolumeManagerCommon.Source} */
+            (volumeMetadata.source));
+  })
+  .catch(
+      /**
+       * @param {*} error
+       */
+      function(error) {
+        console.error('Failed to mount a file system: ' +
+            volumeMetadata.volumeId + ' because of: ' +
+            (error.stack || error));
+        return new VolumeInfo(
+            /** @type {VolumeManagerCommon.VolumeType} */
+            (volumeMetadata.volumeType),
+            volumeMetadata.volumeId,
+            null,  // File system is not found.
+            volumeMetadata.mountCondition,
+            volumeMetadata.deviceType,
+            volumeMetadata.devicePath,
+            volumeMetadata.isReadOnly,
+            volumeMetadata.profile,
+            localizedLabel,
+            volumeMetadata.extensionId,
+            volumeMetadata.hasMedia,
+            volumeMetadata.configurable,
+            /** @type {VolumeManagerCommon.Source} */
+            (volumeMetadata.source));
+      });
 };
 
 /**
@@ -863,7 +852,7 @@
 };
 
 /**
- * Unmounts volume.
+ * Unmounts a volume.
  * @param {!VolumeInfo} volumeInfo Volume to be unmounted.
  * @param {function()} successCallback Success callback.
  * @param {function(VolumeManagerCommon.VolumeError)} errorCallback Error
@@ -877,6 +866,25 @@
   this.startRequest_(requestKey, successCallback, errorCallback);
 };
 
+/**
+ * Configures a volume.
+ * @param {!VolumeInfo} volumeInfo Volume to be configured.
+ * @return {!Promise} Fulfilled on success, otherwise rejected with an error
+ *     message.
+ */
+VolumeManager.prototype.configure = function(volumeInfo) {
+  return new Promise(function(fulfill, reject) {
+    chrome.fileManagerPrivate.configureVolume(
+        volumeInfo.volumeId,
+        function() {
+          if (chrome.runtime.lastError)
+            reject(chrome.runtime.lastError.message);
+          else
+            fulfill();
+        });
+  });
+};
+
 /** @override */
 VolumeManager.prototype.getVolumeInfo = function(entry) {
   return this.volumeInfoList.findByEntry(entry);
diff --git a/ui/file_manager/file_manager/background/js/volume_manager_unittest.js b/ui/file_manager/file_manager/background/js/volume_manager_unittest.js
index d2d4c4f..30cb335 100644
--- a/ui/file_manager/file_manager/background/js/volume_manager_unittest.js
+++ b/ui/file_manager/file_manager/background/js/volume_manager_unittest.js
@@ -91,14 +91,18 @@
       volumeLabel: '',
       volumeType: VolumeManagerCommon.VolumeType.DOWNLOADS,
       isReadOnly: false,
-      profile: getMockProfile()
+      profile: getMockProfile(),
+      configurable: false,
+      source: VolumeManagerCommon.Source.SYSTEM
     },
     {
       volumeId: 'drive:drive-foobar%40chromium.org-hash',
       volumeLabel: '',
       volumeType: VolumeManagerCommon.VolumeType.DRIVE,
       isReadOnly: false,
-      profile: getMockProfile()
+      profile: getMockProfile(),
+      configurable: false,
+      source: VolumeManagerCommon.Source.NETWORK
     }
   ];
   chrome.fileManagerPrivate.fileSystemMap_ = {
@@ -185,7 +189,9 @@
           volumeType: VolumeManagerCommon.VolumeType.ARCHIVE,
           isReadOnly: true,
           sourcePath: mountSourcePath,
-          profile: getMockProfile()
+          profile: getMockProfile(),
+          configurable: false,
+          source: VolumeManagerCommon.Source.FILE
         }
       });
     }).then(function(result) {
@@ -255,7 +261,8 @@
       /* label */ null,
       /* extensionid */ null,
       /* hasMedia */ false,
-      /* configurable */ false);
+      /* configurable */ false,
+      /* source */ VolumeManagerCommon.Source.FILE);
   list.add(volumeInfo);
   var promiseAfterAdd = list.whenVolumeInfoReady('volumeId');
   reportPromise(Promise.all([promiseBeforeAdd, promiseAfterAdd]).then(
diff --git a/ui/file_manager/file_manager/common/js/volume_manager_common.js b/ui/file_manager/file_manager/common/js/volume_manager_common.js
index 7dfc38c..46a1a07 100644
--- a/ui/file_manager/file_manager/common/js/volume_manager_common.js
+++ b/ui/file_manager/file_manager/common/js/volume_manager_common.js
@@ -125,6 +125,18 @@
 };
 
 /**
+ * Source of each volume's data.
+ * @enum {string}
+ * @const
+ */
+VolumeManagerCommon.Source = {
+  FILE: 'file',
+  DEVICE: 'device',
+  NETWORK: 'network',
+  SYSTEM: 'system'
+};
+
+/**
  * Returns if the volume is linux native file system or not. Non-native file
  * system does not support few operations (e.g. load unpacked extension).
  * @param {VolumeManagerCommon.VolumeType} type
diff --git a/ui/file_manager/file_manager/foreground/js/file_manager_commands.js b/ui/file_manager/file_manager/foreground/js/file_manager_commands.js
index 674d53c..a57a79b 100644
--- a/ui/file_manager/file_manager/foreground/js/file_manager_commands.js
+++ b/ui/file_manager/file_manager/foreground/js/file_manager_commands.js
@@ -1375,10 +1375,8 @@
      */
     execute: function(event, fileManager) {
       var volumeInfo = this.getCommandVolumeInfo_(event, fileManager);
-      if (volumeInfo && volumeInfo.configurable) {
-        fileManager.providersModel.requestConfigure(
-            assert(volumeInfo.extensionId));
-      }
+      if (volumeInfo && volumeInfo.configurable)
+        fileManager.volumeManager.configure(volumeInfo);
     },
 
     /**
diff --git a/ui/file_manager/file_manager/foreground/js/providers_model.js b/ui/file_manager/file_manager/foreground/js/providers_model.js
index 49f3fe4..9b4a937c 100644
--- a/ui/file_manager/file_manager/foreground/js/providers_model.js
+++ b/ui/file_manager/file_manager/foreground/js/providers_model.js
@@ -145,15 +145,3 @@
             console.error(chrome.runtime.lastError.message);
       });
 };
-
-/**
- * @param {string} extensionId
- */
-ProvidersModel.prototype.requestConfigure = function(extensionId) {
-  chrome.fileManagerPrivate.configureProvidedFileSystem(
-      assert(extensionId),
-      function() {
-        if (chrome.runtime.lastError)
-            console.error(chrome.runtime.lastError.message);
-      });
-};
diff --git a/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js b/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js
index 109d481b..455a8410 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js
@@ -369,11 +369,11 @@
 
   // Sets up context menu of the item.
   if (tree.contextMenuForSubitems)
-    item.setContextMenu(tree.contextMenuForSubitems);
+    item.setContextMenu_(tree.contextMenuForSubitems);
   // Adds handler for future change.
   tree.addEventListener(
       'contextMenuForSubitemsChange',
-      function(e) { item.setContextMenu(e.newValue); });
+      function(e) { item.setContextMenu_(e.newValue); });
 
   // Populates children now if needed.
   if (parentDirItem.expanded)
@@ -393,8 +393,9 @@
 /**
  * Sets the context menu for directory tree.
  * @param {!cr.ui.Menu} menu Menu to be set.
+ * @private
  */
-SubDirectoryItem.prototype.setContextMenu = function(menu) {
+SubDirectoryItem.prototype.setContextMenu_ = function(menu) {
   var tree = this.parentTree_ || this;  // If no parent, 'this' itself is tree.
   var locationInfo = tree.volumeManager_.getLocationInfo(this.entry);
   if (locationInfo && locationInfo.isEligibleForFolderShortcut)
@@ -433,14 +434,17 @@
 
   item.modelItem_ = modelItem;
   item.volumeInfo_ = modelItem.volumeInfo;
-
-  // Sets up icons of the item.
   item.setupIcon_(item.querySelector('.icon'), item.volumeInfo_);
-  item.setupEjectButton_(item.rowElement);
+
+  // Attach the "eject" icon if the volume is ejectable.
+  if (modelItem.volumeInfo_.source === VolumeManagerCommon.Source.DEVICE ||
+      modelItem.volumeInfo_.source === VolumeManagerCommon.Source.FILE) {
+    item.setupEjectButton_(item.rowElement);
+  }
 
   // Sets up context menu of the item.
   if (tree.contextMenuForRootItems)
-    item.setContextMenu(tree.contextMenuForRootItems);
+    item.setContextMenu_(tree.contextMenuForRootItems);
 
   // Populate children of this volume using resolved display root.
   item.volumeInfo_.resolveDisplayRoot(function(displayRoot) {
@@ -477,10 +481,10 @@
 /**
  * Sets the context menu for volume items.
  * @param {!cr.ui.Menu} menu Menu to be set.
+ * @private
  */
-VolumeItem.prototype.setContextMenu = function(menu) {
-  if (this.isRemovable_())
-    cr.ui.contextMenuHandler.setContextMenu(this, menu);
+VolumeItem.prototype.setContextMenu_ = function(menu) {
+  cr.ui.contextMenuHandler.setContextMenu(this, menu);
 };
 
 /**
@@ -509,17 +513,6 @@
 };
 
 /**
- * @return {boolean} True if this volume can be removed by user operation.
- * @private
- */
-VolumeItem.prototype.isRemovable_ = function() {
-  var volumeType = this.volumeInfo_.volumeType;
-  return volumeType === VolumeManagerCommon.VolumeType.ARCHIVE ||
-         volumeType === VolumeManagerCommon.VolumeType.REMOVABLE ||
-         volumeType === VolumeManagerCommon.VolumeType.PROVIDED;
-};
-
-/**
  * Set up icon of this volume item.
  * @param {Element} icon Icon element to be setup.
  * @param {VolumeInfo} volumeInfo VolumeInfo determines the icon type.
@@ -548,31 +541,29 @@
  * @private
  */
 VolumeItem.prototype.setupEjectButton_ = function(rowElement) {
-  if (this.isRemovable_()) {
-    var ejectButton = cr.doc.createElement('div');
-    // Block other mouse handlers.
-    ejectButton.addEventListener(
-        'mouseup', function(event) { event.stopPropagation() });
-    ejectButton.addEventListener(
-        'mousedown', function(event) { event.stopPropagation() });
-    ejectButton.className = 'root-eject';
-    ejectButton.setAttribute('aria-label', str('UNMOUNT_DEVICE_BUTTON_LABEL'));
-    ejectButton.addEventListener('click', function(event) {
-      event.stopPropagation();
-      var unmountCommand = cr.doc.querySelector('command#unmount');
-      // Let's make sure 'canExecute' state of the command is properly set for
-      // the root before executing it.
-      unmountCommand.canExecuteChange(this);
-      unmountCommand.execute(this);
-    }.bind(this));
-    rowElement.appendChild(ejectButton);
+  var ejectButton = cr.doc.createElement('div');
+  // Block other mouse handlers.
+  ejectButton.addEventListener(
+      'mouseup', function(event) { event.stopPropagation() });
+  ejectButton.addEventListener(
+      'mousedown', function(event) { event.stopPropagation() });
+  ejectButton.className = 'root-eject';
+  ejectButton.setAttribute('aria-label', str('UNMOUNT_DEVICE_BUTTON_LABEL'));
+  ejectButton.addEventListener('click', function(event) {
+    event.stopPropagation();
+    var unmountCommand = cr.doc.querySelector('command#unmount');
+    // Let's make sure 'canExecute' state of the command is properly set for
+    // the root before executing it.
+    unmountCommand.canExecuteChange(this);
+    unmountCommand.execute(this);
+  }.bind(this));
+  rowElement.appendChild(ejectButton);
 
-    // Add paper-ripple effect on the eject button.
-    var ripple = cr.doc.createElement('paper-ripple');
-    ripple.setAttribute('fit', '');
-    ripple.className = 'circle recenteringTouch';
-    ejectButton.appendChild(ripple);
-  }
+  // Add paper-ripple effect on the eject button.
+  var ripple = cr.doc.createElement('paper-ripple');
+  ripple.setAttribute('fit', '');
+  ripple.className = 'circle recenteringTouch';
+  ejectButton.appendChild(ripple);
 };
 
 
@@ -716,7 +707,7 @@
   icon.setAttribute('volume-type-icon', VolumeManagerCommon.VolumeType.DRIVE);
 
   if (tree.contextMenuForRootItems)
-    item.setContextMenu(tree.contextMenuForRootItems);
+    item.setContextMenu_(tree.contextMenuForRootItems);
 
   item.label = modelItem.entry.name;
   return item;
@@ -773,8 +764,9 @@
 /**
  * Sets the context menu for shortcut items.
  * @param {!cr.ui.Menu} menu Menu to be set.
+ * @private
  */
-ShortcutItem.prototype.setContextMenu = function(menu) {
+ShortcutItem.prototype.setContextMenu_ = function(menu) {
   cr.ui.contextMenuHandler.setContextMenu(this, menu);
 };
 
diff --git a/ui/file_manager/file_manager/foreground/js/volume_manager_wrapper.js b/ui/file_manager/file_manager/foreground/js/volume_manager_wrapper.js
index 38e3e44..7b4f53a3 100644
--- a/ui/file_manager/file_manager/foreground/js/volume_manager_wrapper.js
+++ b/ui/file_manager/file_manager/foreground/js/volume_manager_wrapper.js
@@ -323,6 +323,24 @@
 };
 
 /**
+ * Requests configuring of the specified volume.
+ * @param {!VolumeInfo} volumeInfo Volume to be configured.
+ * @return {!Promise} Fulfilled on success, otherwise rejected with an error
+ *     message.
+ */
+VolumeManagerWrapper.prototype.configure = function(volumeInfo) {
+  if (this.pendingTasks_) {
+    return new Promise(function(fulfill, reject) {
+      this.pendingTasks_.push(function() {
+        return this.volumeManager_.configure(volumeInfo).then(fulfill, reject);
+      }.bind(this));
+    }.bind(this));
+  }
+
+  return this.volumeManager_.configure(volumeInfo);
+};
+
+/**
  * Filters volume info by referring nonNativeEnabled.
  *
  * @param {VolumeInfo} volumeInfo Volume info.
diff --git a/ui/keyboard/keyboard_controller.cc b/ui/keyboard/keyboard_controller.cc
index a085c53..351cf57 100644
--- a/ui/keyboard/keyboard_controller.cc
+++ b/ui/keyboard/keyboard_controller.cc
@@ -211,6 +211,7 @@
   input_method_ = proxy_->GetInputMethod();
   input_method_->AddObserver(this);
   window_bounds_observer_.reset(new WindowBoundsChangeObserver());
+  proxy_->SetController(this);
 }
 
 KeyboardController::~KeyboardController() {
@@ -222,6 +223,7 @@
   if (input_method_)
     input_method_->RemoveObserver(this);
   ResetWindowInsets();
+  proxy_->SetController(nullptr);
 }
 
 // static
diff --git a/ui/keyboard/keyboard_controller_proxy.h b/ui/keyboard/keyboard_controller_proxy.h
index 2c91446..f927849e 100644
--- a/ui/keyboard/keyboard_controller_proxy.h
+++ b/ui/keyboard/keyboard_controller_proxy.h
@@ -31,6 +31,8 @@
 
 namespace keyboard {
 
+class KeyboardController;
+
 // A proxy used by the KeyboardController to get access to the virtual
 // keyboard window.
 class KEYBOARD_EXPORT KeyboardControllerProxy : public aura::WindowObserver {
@@ -101,6 +103,11 @@
   // provide one.
   virtual void ReloadKeyboardIfNeeded();
 
+  // KeyboardController owns KeyboardControllerProxy so KeyboardControllerProxy
+  // or its subclasses should not take ownership of the |controller|.
+  // |controller| can be null when KeyboardController is destroying.
+  virtual void SetController(KeyboardController* controller) {}
+
  protected:
   // The implementation can choose to setup the WebContents before the virtual
   // keyboard page is loaded (e.g. install a WebContentsObserver).
diff --git a/ui/ozone/platform/caca/caca_window_manager.cc b/ui/ozone/platform/caca/caca_window_manager.cc
index 3e11ad2..2b5a5d22 100644
--- a/ui/ozone/platform/caca/caca_window_manager.cc
+++ b/ui/ozone/platform/caca/caca_window_manager.cc
@@ -118,16 +118,19 @@
 }
 
 CacaWindowManager::~CacaWindowManager() {
+  DCHECK(thread_checker_.CalledOnValidThread());
 }
 
 bool CacaWindowManager::LoadEGLGLES2Bindings(
     AddGLLibraryCallback add_gl_library,
     SetGLGetProcAddressProcCallback set_gl_get_proc_address) {
+  DCHECK(thread_checker_.CalledOnValidThread());
   return false;
 }
 
 scoped_ptr<ui::SurfaceOzoneCanvas> CacaWindowManager::CreateCanvasForWidget(
     gfx::AcceleratedWidget widget) {
+  DCHECK(thread_checker_.CalledOnValidThread());
   CacaWindow* window = windows_.Lookup(widget);
   DCHECK(window);
 
diff --git a/ui/ozone/platform/caca/caca_window_manager.h b/ui/ozone/platform/caca/caca_window_manager.h
index 4f51a7f..31134965 100644
--- a/ui/ozone/platform/caca/caca_window_manager.h
+++ b/ui/ozone/platform/caca/caca_window_manager.h
@@ -7,6 +7,7 @@
 
 #include "base/id_map.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/threading/thread_checker.h"
 #include "ui/ozone/public/surface_factory_ozone.h"
 
 namespace gfx {
@@ -37,6 +38,7 @@
 
  private:
   IDMap<CacaWindow> windows_;
+  base::ThreadChecker thread_checker_;
 
   DISALLOW_COPY_AND_ASSIGN(CacaWindowManager);
 };
diff --git a/ui/ozone/platform/drm/BUILD.gn b/ui/ozone/platform/drm/BUILD.gn
index d124da2..20cf79a 100644
--- a/ui/ozone/platform/drm/BUILD.gn
+++ b/ui/ozone/platform/drm/BUILD.gn
@@ -47,8 +47,6 @@
     "gpu/drm_vsync_provider.h",
     "gpu/drm_window.cc",
     "gpu/drm_window.h",
-    "gpu/gpu_lock.cc",
-    "gpu/gpu_lock.h",
     "gpu/hardware_display_controller.cc",
     "gpu/hardware_display_controller.h",
     "gpu/hardware_display_plane.cc",
diff --git a/ui/ozone/platform/drm/drm.gypi b/ui/ozone/platform/drm/drm.gypi
index 532f62e..bc1c86c7 100644
--- a/ui/ozone/platform/drm/drm.gypi
+++ b/ui/ozone/platform/drm/drm.gypi
@@ -69,8 +69,6 @@
         'gpu/drm_vsync_provider.h',
         'gpu/drm_window.cc',
         'gpu/drm_window.h',
-        'gpu/gpu_lock.cc',
-        'gpu/gpu_lock.h',
         'gpu/hardware_display_controller.cc',
         'gpu/hardware_display_controller.h',
         'gpu/hardware_display_plane.cc',
diff --git a/ui/ozone/platform/drm/drm_surface_factory.cc b/ui/ozone/platform/drm/drm_surface_factory.cc
index 6fbf260..ccbbf2b 100644
--- a/ui/ozone/platform/drm/drm_surface_factory.cc
+++ b/ui/ozone/platform/drm/drm_surface_factory.cc
@@ -25,12 +25,14 @@
 
 scoped_ptr<ui::SurfaceOzoneCanvas> DrmSurfaceFactory::CreateCanvasForWidget(
     gfx::AcceleratedWidget widget) {
+  DCHECK(thread_checker_.CalledOnValidThread());
   return make_scoped_ptr(new DrmSurface(screen_manager_->GetWindow(widget)));
 }
 
 bool DrmSurfaceFactory::LoadEGLGLES2Bindings(
     AddGLLibraryCallback add_gl_library,
     SetGLGetProcAddressProcCallback set_gl_get_proc_address) {
+  DCHECK(thread_checker_.CalledOnValidThread());
   return false;
 }
 
diff --git a/ui/ozone/platform/drm/drm_surface_factory.h b/ui/ozone/platform/drm/drm_surface_factory.h
index 1dfdf1a..3baa1754 100644
--- a/ui/ozone/platform/drm/drm_surface_factory.h
+++ b/ui/ozone/platform/drm/drm_surface_factory.h
@@ -6,6 +6,7 @@
 #define UI_OZONE_PLATFORM_DRM_DRM_SURFACE_FACTORY_H_
 
 #include "base/memory/scoped_ptr.h"
+#include "base/threading/thread_checker.h"
 #include "ui/ozone/public/surface_factory_ozone.h"
 
 namespace ui {
@@ -30,6 +31,7 @@
 
  protected:
   ScreenManager* screen_manager_;  // Not owned.
+  base::ThreadChecker thread_checker_;
 
   DISALLOW_COPY_AND_ASSIGN(DrmSurfaceFactory);
 };
diff --git a/ui/ozone/platform/drm/gbm_surface_factory.cc b/ui/ozone/platform/drm/gbm_surface_factory.cc
index afe8d2c..f81d746 100644
--- a/ui/ozone/platform/drm/gbm_surface_factory.cc
+++ b/ui/ozone/platform/drm/gbm_surface_factory.cc
@@ -78,6 +78,7 @@
 }
 
 GbmSurfaceFactory::~GbmSurfaceFactory() {
+  DCHECK(thread_checker_.CalledOnValidThread());
 }
 
 void GbmSurfaceFactory::InitializeGpu(DrmDeviceManager* drm_device_manager,
@@ -87,11 +88,13 @@
 }
 
 intptr_t GbmSurfaceFactory::GetNativeDisplay() {
+  DCHECK(thread_checker_.CalledOnValidThread());
   return EGL_DEFAULT_DISPLAY;
 }
 
 const int32* GbmSurfaceFactory::GetEGLSurfaceProperties(
     const int32* desired_list) {
+  DCHECK(thread_checker_.CalledOnValidThread());
   static const int32 kConfigAttribs[] = {EGL_BUFFER_SIZE,
                                          32,
                                          EGL_ALPHA_SIZE,
@@ -114,17 +117,20 @@
 bool GbmSurfaceFactory::LoadEGLGLES2Bindings(
     AddGLLibraryCallback add_gl_library,
     SetGLGetProcAddressProcCallback set_gl_get_proc_address) {
+  DCHECK(thread_checker_.CalledOnValidThread());
   return LoadDefaultEGLGLES2Bindings(add_gl_library, set_gl_get_proc_address);
 }
 
 scoped_ptr<SurfaceOzoneCanvas> GbmSurfaceFactory::CreateCanvasForWidget(
     gfx::AcceleratedWidget widget) {
+  DCHECK(thread_checker_.CalledOnValidThread());
   LOG(FATAL) << "Software rendering mode is not supported with GBM platform";
   return nullptr;
 }
 
 scoped_ptr<SurfaceOzoneEGL> GbmSurfaceFactory::CreateEGLSurfaceForWidget(
     gfx::AcceleratedWidget widget) {
+  DCHECK(thread_checker_.CalledOnValidThread());
   scoped_refptr<GbmDevice> gbm = GetGbmDevice(widget);
   DCHECK(gbm);
 
@@ -139,6 +145,7 @@
 scoped_ptr<SurfaceOzoneEGL>
 GbmSurfaceFactory::CreateSurfacelessEGLSurfaceForWidget(
     gfx::AcceleratedWidget widget) {
+  DCHECK(thread_checker_.CalledOnValidThread());
   if (!allow_surfaceless_)
     return nullptr;
 
@@ -171,6 +178,7 @@
 
 OverlayCandidatesOzone* GbmSurfaceFactory::GetOverlayCandidates(
     gfx::AcceleratedWidget w) {
+  DCHECK(thread_checker_.CalledOnValidThread());
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kOzoneTestSingleOverlaySupport))
     return new SingleOverlay();
@@ -184,6 +192,7 @@
     scoped_refptr<NativePixmap> buffer,
     const gfx::Rect& display_bounds,
     const gfx::RectF& crop_rect) {
+  DCHECK(thread_checker_.CalledOnValidThread());
   scoped_refptr<GbmPixmap> pixmap = static_cast<GbmPixmap*>(buffer.get());
   if (!pixmap.get()) {
     LOG(ERROR) << "ScheduleOverlayPlane passed NULL buffer.";
@@ -196,10 +205,12 @@
 }
 
 bool GbmSurfaceFactory::CanShowPrimaryPlaneAsOverlay() {
+  DCHECK(thread_checker_.CalledOnValidThread());
   return allow_surfaceless_;
 }
 
 bool GbmSurfaceFactory::CanCreateNativePixmap(BufferUsage usage) {
+  DCHECK(thread_checker_.CalledOnValidThread());
   switch (usage) {
     case MAP:
       return false;
diff --git a/ui/ozone/platform/drm/gpu/gpu_lock.cc b/ui/ozone/platform/drm/gpu/gpu_lock.cc
deleted file mode 100644
index bcb287d..0000000
--- a/ui/ozone/platform/drm/gpu/gpu_lock.cc
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/ozone/platform/drm/gpu/gpu_lock.h"
-
-#include <sys/file.h>
-#include <unistd.h>
-
-#include "base/logging.h"
-#include "base/posix/eintr_wrapper.h"
-
-namespace ui {
-
-namespace {
-const char kGpuLockFile[] = "/run/frecon";
-}
-
-GpuLock::GpuLock() {
-  fd_ = open(kGpuLockFile, O_RDWR);
-  if (fd_ < 0) {
-    PLOG(ERROR) << "Failed to open lock file '" << kGpuLockFile << "'";
-    return;
-  }
-
-  VLOG(1) << "Taking write lock on '" << kGpuLockFile << "'";
-  if (HANDLE_EINTR(flock(fd_, LOCK_EX)))
-    PLOG(ERROR) << "Error while trying to get lock on '" << kGpuLockFile << "'";
-
-  VLOG(1) << "Done trying to take write lock on '" << kGpuLockFile << "'";
-}
-
-GpuLock::~GpuLock() {
-  // Failed to open the lock file, so nothing to do here.
-  if (fd_ < 0)
-    return;
-
-  VLOG(1) << "Releasing write lock on '" << kGpuLockFile << "'";
-  close(fd_);
-}
-
-}  // namespace ui
diff --git a/ui/ozone/platform/drm/gpu/gpu_lock.h b/ui/ozone/platform/drm/gpu/gpu_lock.h
deleted file mode 100644
index 72a093e..0000000
--- a/ui/ozone/platform/drm/gpu/gpu_lock.h
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_OZONE_PLATFORM_DRM_GPU_GPU_LOCK_H_
-#define UI_OZONE_PLATFORM_DRM_GPU_GPU_LOCK_H_
-
-#include "base/macros.h"
-
-namespace ui {
-
-// Used to synchronize with Frecon and make sure the GPU process isn't trying to
-// access the DRM resources before Frecon finishes drawing.
-class GpuLock {
- public:
-  GpuLock();
-  ~GpuLock();
-
- private:
-  int fd_;
-
-  DISALLOW_COPY_AND_ASSIGN(GpuLock);
-};
-
-}  // namespace ui
-
-#endif  // UI_OZONE_PLATFORM_DRM_GPU_GPU_LOCK_H_
diff --git a/ui/ozone/platform/drm/gpu/screen_manager.cc b/ui/ozone/platform/drm/gpu/screen_manager.cc
index 3dc6c4f..120de8c3 100644
--- a/ui/ozone/platform/drm/gpu/screen_manager.cc
+++ b/ui/ozone/platform/drm/gpu/screen_manager.cc
@@ -182,13 +182,6 @@
       controllers_.push_back(controller);
     }
 
-    if (!controller->IsDisabled()) {
-      // Workaround for driver bug that does not release the buffer on null
-      // modeset.
-      ModesetDisplayController(controller, controller->origin(),
-                               controller->get_mode(), false);
-    }
-
     controller->Disable();
     UpdateControllerToWindowMapping();
     return true;
diff --git a/ui/ozone/platform/drm/host/drm_device_handle.cc b/ui/ozone/platform/drm/host/drm_device_handle.cc
index 36d5a837..8d9fc0c 100644
--- a/ui/ozone/platform/drm/host/drm_device_handle.cc
+++ b/ui/ozone/platform/drm/host/drm_device_handle.cc
@@ -30,7 +30,8 @@
 }
 
 DrmDeviceHandle::~DrmDeviceHandle() {
-  base::ThreadRestrictions::AssertIOAllowed();
+  if (file_.is_valid())
+    base::ThreadRestrictions::AssertIOAllowed();
 }
 
 bool DrmDeviceHandle::Initialize(const base::FilePath& path) {
@@ -63,15 +64,8 @@
   return file_.is_valid();
 }
 
-base::ScopedFD DrmDeviceHandle::Duplicate() {
-  DCHECK(file_.is_valid());
-  int fd = dup(file_.get());
-  if (fd < 0) {
-    PLOG(ERROR) << "Failed to dup";
-    return base::ScopedFD();
-  }
-
-  return base::ScopedFD(fd);
+base::ScopedFD DrmDeviceHandle::PassFD() {
+  return file_.Pass();
 }
 
 }  // namespace ui
diff --git a/ui/ozone/platform/drm/host/drm_device_handle.h b/ui/ozone/platform/drm/host/drm_device_handle.h
index 7b65d97b..b360837 100644
--- a/ui/ozone/platform/drm/host/drm_device_handle.h
+++ b/ui/ozone/platform/drm/host/drm_device_handle.h
@@ -23,7 +23,7 @@
   bool Initialize(const base::FilePath& path);
 
   bool IsValid() const;
-  base::ScopedFD Duplicate();
+  base::ScopedFD PassFD();
 
  private:
   base::ScopedFD file_;
diff --git a/ui/ozone/platform/drm/host/drm_display_host_manager.cc b/ui/ozone/platform/drm/host/drm_display_host_manager.cc
index 2feb1f4ba..d2275271 100644
--- a/ui/ozone/platform/drm/host/drm_display_host_manager.cc
+++ b/ui/ozone/platform/drm/host/drm_display_host_manager.cc
@@ -48,14 +48,6 @@
       FROM_HERE, base::Bind(callback, path, base::Passed(handle.Pass())));
 }
 
-void CloseDeviceOnWorkerThread(
-    scoped_ptr<DrmDeviceHandle> handle,
-    const scoped_refptr<base::TaskRunner>& reply_runner,
-    const base::Closure& callback) {
-  handle.reset();
-  reply_runner->PostTask(FROM_HERE, callback);
-}
-
 base::FilePath GetPrimaryDisplayCardPath() {
   struct drm_mode_card_res res;
   for (int i = 0; /* end on first card# that does not exist */; i++) {
@@ -111,39 +103,29 @@
     // synchronously since the GPU process will need it to initialize the
     // graphics state.
     base::ThreadRestrictions::ScopedAllowIO allow_io;
-    scoped_ptr<DrmDeviceHandle> handle(new DrmDeviceHandle());
-    if (!handle->Initialize(primary_graphics_card_path_)) {
+    primary_drm_device_handle_.reset(new DrmDeviceHandle());
+    if (!primary_drm_device_handle_->Initialize(primary_graphics_card_path_)) {
       LOG(FATAL) << "Failed to open primary graphics card";
       return;
     }
-    drm_devices_.add(primary_graphics_card_path_, handle.Pass());
+    drm_devices_.insert(primary_graphics_card_path_);
   }
 
   device_manager_->AddObserver(this);
   proxy_->RegisterHandler(this);
 
-  DrmDeviceHandle* handle = drm_devices_.get(primary_graphics_card_path_);
   ScopedVector<HardwareDisplayControllerInfo> display_infos =
-      GetAvailableDisplayControllerInfos(handle->fd());
+      GetAvailableDisplayControllerInfos(primary_drm_device_handle_->fd());
   has_dummy_display_ = !display_infos.empty();
   for (size_t i = 0; i < display_infos.size(); ++i) {
     displays_.push_back(new DisplaySnapshotProxy(CreateDisplaySnapshotParams(
-        display_infos[i], handle->fd(), i, gfx::Point())));
+        display_infos[i], primary_drm_device_handle_->fd(), i, gfx::Point())));
   }
 }
 
 DrmDisplayHostManager::~DrmDisplayHostManager() {
   device_manager_->RemoveObserver(this);
   proxy_->UnregisterHandler(this);
-
-  for (auto it = drm_devices_.begin(); it != drm_devices_.end(); ++it) {
-    base::WorkerPool::PostTask(FROM_HERE,
-                               base::Bind(&CloseDeviceOnWorkerThread,
-                                          base::Passed(drm_devices_.take(it)),
-                                          base::ThreadTaskRunnerHandle::Get(),
-                                          base::Bind(&base::DoNothing)),
-                               false /* task_is_slow */);
-  }
 }
 
 DisplaySnapshot* DrmDisplayHostManager::GetDisplay(int64_t display_id) {
@@ -268,16 +250,11 @@
             << "Removing primary graphics card";
         auto it = drm_devices_.find(event.path);
         if (it != drm_devices_.end()) {
-          task_pending_ = base::WorkerPool::PostTask(
+          task_pending_ = base::ThreadTaskRunnerHandle::Get()->PostTask(
               FROM_HERE,
-              base::Bind(
-                  &CloseDeviceOnWorkerThread,
-                  base::Passed(drm_devices_.take_and_erase(it)),
-                  base::ThreadTaskRunnerHandle::Get(),
-                  base::Bind(&DrmDisplayHostManager::OnRemoveGraphicsDevice,
-                             weak_ptr_factory_.GetWeakPtr(), event.path)),
-              false /* task_is_slow */);
-          return;
+              base::Bind(&DrmDisplayHostManager::OnRemoveGraphicsDevice,
+                         weak_ptr_factory_.GetWeakPtr(), event.path));
+          drm_devices_.erase(it);
         }
         break;
     }
@@ -288,10 +265,9 @@
     const base::FilePath& path,
     scoped_ptr<DrmDeviceHandle> handle) {
   if (handle->IsValid()) {
-    base::ScopedFD file = handle->Duplicate();
-    drm_devices_.add(path, handle.Pass());
+    drm_devices_.insert(path);
     proxy_->Send(new OzoneGpuMsg_AddGraphicsDevice(
-        path, base::FileDescriptor(file.Pass())));
+        path, base::FileDescriptor(handle->PassFD())));
     NotifyDisplayDelegate();
   }
 
@@ -316,19 +292,20 @@
     int host_id,
     scoped_refptr<base::SingleThreadTaskRunner> send_runner,
     const base::Callback<void(IPC::Message*)>& send_callback) {
-  auto it = drm_devices_.find(primary_graphics_card_path_);
-  DCHECK(it != drm_devices_.end());
+  drm_devices_.clear();
+  drm_devices_.insert(primary_graphics_card_path_);
+  scoped_ptr<DrmDeviceHandle> handle = primary_drm_device_handle_.Pass();
+  if (!handle) {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
+    handle.reset(new DrmDeviceHandle());
+    if (!handle->Initialize(primary_graphics_card_path_))
+      LOG(FATAL) << "Failed to open primary graphics card";
+  }
+
   // Send the primary device first since this is used to initialize graphics
   // state.
   proxy_->Send(new OzoneGpuMsg_AddGraphicsDevice(
-      it->first, base::FileDescriptor(it->second->Duplicate())));
-
-  for (auto pair : drm_devices_) {
-    if (pair.second->IsValid() && pair.first != primary_graphics_card_path_) {
-      proxy_->Send(new OzoneGpuMsg_AddGraphicsDevice(
-          pair.first, base::FileDescriptor(pair.second->Duplicate())));
-    }
-  }
+      primary_graphics_card_path_, base::FileDescriptor(handle->PassFD())));
 
   device_manager_->ScanDevices(this);
   NotifyDisplayDelegate();
diff --git a/ui/ozone/platform/drm/host/drm_display_host_manager.h b/ui/ozone/platform/drm/host/drm_display_host_manager.h
index fbebd17..f5ae2b8 100644
--- a/ui/ozone/platform/drm/host/drm_display_host_manager.h
+++ b/ui/ozone/platform/drm/host/drm_display_host_manager.h
@@ -7,8 +7,8 @@
 
 #include <map>
 #include <queue>
+#include <set>
 
-#include "base/containers/scoped_ptr_hash_map.h"
 #include "base/files/file.h"
 #include "base/files/file_path.h"
 #include "base/macros.h"
@@ -132,8 +132,11 @@
   bool task_pending_;
 
   // Keeps track of all the active DRM devices.
-  base::ScopedPtrHashMap<base::FilePath, scoped_ptr<DrmDeviceHandle>>
-      drm_devices_;
+  std::set<base::FilePath> drm_devices_;
+
+  // This is used to cache the primary DRM device until the channel is
+  // established.
+  scoped_ptr<DrmDeviceHandle> primary_drm_device_handle_;
 
   base::WeakPtrFactory<DrmDisplayHostManager> weak_ptr_factory_;
 
diff --git a/ui/ozone/platform/drm/ozone_platform_drm.cc b/ui/ozone/platform/drm/ozone_platform_drm.cc
index 6cc4fed..fb22bdcb 100644
--- a/ui/ozone/platform/drm/ozone_platform_drm.cc
+++ b/ui/ozone/platform/drm/ozone_platform_drm.cc
@@ -20,7 +20,6 @@
 #include "ui/ozone/platform/drm/gpu/drm_gpu_display_manager.h"
 #include "ui/ozone/platform/drm/gpu/drm_gpu_platform_support.h"
 #include "ui/ozone/platform/drm/gpu/drm_window.h"
-#include "ui/ozone/platform/drm/gpu/gpu_lock.h"
 #include "ui/ozone/platform/drm/gpu/screen_manager.h"
 #include "ui/ozone/platform/drm/host/drm_cursor.h"
 #include "ui/ozone/platform/drm/host/drm_display_host_manager.h"
@@ -88,9 +87,6 @@
         new DrmNativeDisplayDelegate(display_manager_.get()));
   }
   void InitializeUI() override {
-#if defined(OS_CHROMEOS)
-    gpu_lock_.reset(new GpuLock());
-#endif
     drm_device_manager_.reset(new DrmDeviceManager(
         scoped_ptr<DrmDeviceGenerator>(new DrmDeviceGenerator())));
     window_manager_.reset(new DrmWindowHostManager());
@@ -125,7 +121,6 @@
 
  private:
   // Objects in the "GPU" process.
-  scoped_ptr<GpuLock> gpu_lock_;
   scoped_ptr<DrmDeviceManager> drm_device_manager_;
   scoped_ptr<DrmBufferGenerator> buffer_generator_;
   scoped_ptr<ScreenManager> screen_manager_;
diff --git a/ui/ozone/platform/drm/ozone_platform_gbm.cc b/ui/ozone/platform/drm/ozone_platform_gbm.cc
index 75f93c586..3f5bd7b 100644
--- a/ui/ozone/platform/drm/ozone_platform_gbm.cc
+++ b/ui/ozone/platform/drm/ozone_platform_gbm.cc
@@ -24,7 +24,6 @@
 #include "ui/ozone/platform/drm/gpu/gbm_buffer.h"
 #include "ui/ozone/platform/drm/gpu/gbm_device.h"
 #include "ui/ozone/platform/drm/gpu/gbm_surface.h"
-#include "ui/ozone/platform/drm/gpu/gpu_lock.h"
 #include "ui/ozone/platform/drm/gpu/scanout_buffer.h"
 #include "ui/ozone/platform/drm/gpu/screen_manager.h"
 #include "ui/ozone/platform/drm/host/drm_cursor.h"
@@ -170,9 +169,6 @@
   }
 
   void InitializeGPU() override {
-#if defined(OS_CHROMEOS)
-    gpu_lock_.reset(new GpuLock());
-#endif
     gl_api_loader_.reset(new GlApiLoader());
     drm_device_manager_.reset(new DrmDeviceManager(
         scoped_ptr<DrmDeviceGenerator>(new GbmDeviceGenerator())));
@@ -195,7 +191,6 @@
   scoped_ptr<GbmSurfaceFactory> surface_factory_ozone_;
 
   // Objects in the GPU process.
-  scoped_ptr<GpuLock> gpu_lock_;
   scoped_ptr<GlApiLoader> gl_api_loader_;
   scoped_ptr<DrmDeviceManager> drm_device_manager_;
   scoped_ptr<GbmBufferGenerator> buffer_generator_;
diff --git a/ui/ozone/platform/egltest/ozone_platform_egltest.cc b/ui/ozone/platform/egltest/ozone_platform_egltest.cc
index 42ce0a8..adfadf99 100644
--- a/ui/ozone/platform/egltest/ozone_platform_egltest.cc
+++ b/ui/ozone/platform/egltest/ozone_platform_egltest.cc
@@ -9,6 +9,7 @@
 #include "base/environment.h"
 #include "base/files/file_path.h"
 #include "base/path_service.h"
+#include "base/threading/thread_checker.h"
 #include "library_loaders/libeglplatform_shim.h"
 #include "third_party/khronos/EGL/egl.h"
 #include "ui/events/devices/device_data_manager.h"
@@ -240,7 +241,9 @@
  public:
   SurfaceFactoryEgltest(LibeglplatformShimLoader* eglplatform_shim)
       : eglplatform_shim_(eglplatform_shim) {}
-  ~SurfaceFactoryEgltest() override {}
+  ~SurfaceFactoryEgltest() override {
+    DCHECK(thread_checker_.CalledOnValidThread());
+  }
 
   // SurfaceFactoryOzone:
   intptr_t GetNativeDisplay() override;
@@ -253,14 +256,17 @@
 
  private:
   LibeglplatformShimLoader* eglplatform_shim_;
+  base::ThreadChecker thread_checker_;
 };
 
 intptr_t SurfaceFactoryEgltest::GetNativeDisplay() {
+  DCHECK(thread_checker_.CalledOnValidThread());
   return eglplatform_shim_->ShimGetNativeDisplay();
 }
 
 scoped_ptr<SurfaceOzoneEGL> SurfaceFactoryEgltest::CreateEGLSurfaceForWidget(
     gfx::AcceleratedWidget widget) {
+  DCHECK(thread_checker_.CalledOnValidThread());
   return make_scoped_ptr<SurfaceOzoneEGL>(
       new SurfaceOzoneEgltest(widget, eglplatform_shim_));
 }
@@ -268,6 +274,7 @@
 bool SurfaceFactoryEgltest::LoadEGLGLES2Bindings(
     AddGLLibraryCallback add_gl_library,
     SetGLGetProcAddressProcCallback set_gl_get_proc_address) {
+  DCHECK(thread_checker_.CalledOnValidThread());
   const char* egl_soname = eglplatform_shim_->ShimQueryString(SHIM_EGL_LIBRARY);
   const char* gles_soname =
       eglplatform_shim_->ShimQueryString(SHIM_GLES_LIBRARY);
@@ -282,6 +289,7 @@
 
 const int32* SurfaceFactoryEgltest::GetEGLSurfaceProperties(
     const int32* desired_list) {
+  DCHECK(thread_checker_.CalledOnValidThread());
   static const int32 broken_props[] = {
       EGL_RENDERABLE_TYPE,
       EGL_OPENGL_ES2_BIT,
diff --git a/ui/ozone/platform/test/test_window_manager.cc b/ui/ozone/platform/test/test_window_manager.cc
index 3ff3a47..cd48bf3 100644
--- a/ui/ozone/platform/test/test_window_manager.cc
+++ b/ui/ozone/platform/test/test_window_manager.cc
@@ -69,6 +69,7 @@
 }
 
 TestWindowManager::~TestWindowManager() {
+  DCHECK(thread_checker_.CalledOnValidThread());
 }
 
 void TestWindowManager::Initialize() {
@@ -96,6 +97,7 @@
 
 scoped_ptr<SurfaceOzoneCanvas> TestWindowManager::CreateCanvasForWidget(
     gfx::AcceleratedWidget widget) {
+  DCHECK(thread_checker_.CalledOnValidThread());
   TestWindow* window = windows_.Lookup(widget);
   DCHECK(window);
   return make_scoped_ptr<SurfaceOzoneCanvas>(new FileSurface(window->path()));
@@ -104,6 +106,7 @@
 bool TestWindowManager::LoadEGLGLES2Bindings(
     AddGLLibraryCallback add_gl_library,
     SetGLGetProcAddressProcCallback set_gl_get_proc_address) {
+  DCHECK(thread_checker_.CalledOnValidThread());
   return false;
 }
 
diff --git a/ui/ozone/platform/test/test_window_manager.h b/ui/ozone/platform/test/test_window_manager.h
index 69be81d9..b651207e 100644
--- a/ui/ozone/platform/test/test_window_manager.h
+++ b/ui/ozone/platform/test/test_window_manager.h
@@ -8,6 +8,7 @@
 #include "base/files/file_path.h"
 #include "base/id_map.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/threading/thread_checker.h"
 #include "ui/gfx/native_widget_types.h"
 #include "ui/ozone/platform/test/test_window.h"
 #include "ui/ozone/public/surface_factory_ozone.h"
@@ -42,6 +43,7 @@
   base::FilePath location_;
 
   IDMap<TestWindow> windows_;
+  base::ThreadChecker thread_checker_;
 
   DISALLOW_COPY_AND_ASSIGN(TestWindowManager);
 };
diff --git a/ui/ozone/public/surface_factory_ozone.h b/ui/ozone/public/surface_factory_ozone.h
index e73813d..0fbf9e89 100644
--- a/ui/ozone/public/surface_factory_ozone.h
+++ b/ui/ozone/public/surface_factory_ozone.h
@@ -129,6 +129,7 @@
   // Create a single native buffer to be used for overlay planes or zero copy
   // for |widget| representing a particular display controller or default
   // display controller for kNullAcceleratedWidget.
+  // It can be called on any thread.
   virtual scoped_refptr<NativePixmap> CreateNativePixmap(
       gfx::AcceleratedWidget widget,
       gfx::Size size,
diff --git a/ui/touch_selection/touch_selection_controller.cc b/ui/touch_selection/touch_selection_controller.cc
index ad010c38..34cc30a 100644
--- a/ui/touch_selection/touch_selection_controller.cc
+++ b/ui/touch_selection/touch_selection_controller.cc
@@ -491,8 +491,14 @@
 }
 
 void TouchSelectionController::ForceNextUpdateIfInactive() {
-  if (active_status_ == INACTIVE)
+  // Only force the update if the reported selection is non-empty but still
+  // considered "inactive", i.e., it wasn't preceded by a user gesture or
+  // the handles have since been explicitly hidden.
+  if (active_status_ == INACTIVE &&
+      start_.type() != SelectionBound::EMPTY &&
+      end_.type() != SelectionBound::EMPTY) {
     force_next_update_ = true;
+  }
 }
 
 gfx::Vector2dF TouchSelectionController::GetStartLineOffset() const {
diff --git a/ui/touch_selection/touch_selection_controller_unittest.cc b/ui/touch_selection/touch_selection_controller_unittest.cc
index c78a5d5..8125c50 100644
--- a/ui/touch_selection/touch_selection_controller_unittest.cc
+++ b/ui/touch_selection/touch_selection_controller_unittest.cc
@@ -575,6 +575,27 @@
   EXPECT_EQ(gfx::PointF(), GetLastEventStart());
 }
 
+TEST_F(TouchSelectionControllerTest, SelectionAllowsEmptyUpdateAfterLongPress) {
+  gfx::RectF start_rect(5, 5, 0, 10);
+  gfx::RectF end_rect(50, 5, 0, 10);
+  bool visible = true;
+
+  OnLongPressEvent();
+  EXPECT_THAT(GetAndResetEvents(), IsEmpty());
+
+  // There may be several empty updates after a longpress due to the
+  // asynchronous response. These empty updates should not prevent the selection
+  // handles from (eventually) activating.
+  ClearSelection();
+  EXPECT_THAT(GetAndResetEvents(), IsEmpty());
+
+  ClearSelection();
+  EXPECT_THAT(GetAndResetEvents(), IsEmpty());
+
+  ChangeSelection(start_rect, visible, end_rect, visible);
+  EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_SHOWN));
+}
+
 TEST_F(TouchSelectionControllerTest, SelectionRepeatedLongPress) {
   gfx::RectF start_rect(5, 5, 0, 10);
   gfx::RectF end_rect(50, 5, 0, 10);
diff --git a/ui/webui/resources/cr_elements/v0_8/demo_element.html b/ui/webui/resources/cr_elements/v0_8/demo_element.html
new file mode 100644
index 0000000..5a3810b
--- /dev/null
+++ b/ui/webui/resources/cr_elements/v0_8/demo_element.html
@@ -0,0 +1,49 @@
+<link rel="import" href="chrome://resources/polymer/v0_8/polymer/polymer.html">
+<link rel="import" href="chrome://resources/cr_elements/v0_8/cr_button/cr_button.html">
+<link rel="import" href="chrome://resources/cr_elements/v0_8/cr_checkbox/cr_checkbox.html">
+<link rel="import" href="chrome://resources/cr_elements/v0_8/cr_collapse/cr_collapse.html">
+<link rel="import" href="chrome://resources/cr_elements/v0_8/cr_input/cr_input.html">
+<link rel="import" href="chrome://resources/cr_elements/v0_8/cr_network_icon/cr_network_icon.html">
+<link rel="import" href="chrome://resources/cr_elements/v0_8/cr_toggle_button/cr_toggle_button.html">
+
+<dom-module id="cr-demo-element">
+  <template>
+    <div>
+      <h3>cr-button</h3>
+      <cr-button>Button</cr-button>
+      <cr-button raised>Raised Button</cr-button>
+    </div>
+    <div>
+      <h3>cr-checkbox</h3>
+      <cr-checkbox checked="{{checkboxChecked}}">Checkbox</cr-checkbox>
+    </div>
+    <div>
+      <h3>cr-collapse</h3>
+      <paper-toggle-button checked="{{collapseOpened}}">
+        Toggle Collapse
+      </paper-toggle-button>
+      <cr-collapse opened="{{collapseOpened}}">
+        <div>
+          <span>Collapsable section</span>
+        </div>
+      </cr-collapse>
+    </div>
+    <div>
+      <h3>cr-input</h3>
+      <cr-input label="Input" value="{{inputValue}}"></cr-input>
+      <span>Input.value=</span><span>{{inputValue}}</span>
+    </div>
+    <div>
+      <h3>cr-network-icon</h3>
+      <cr-network-icon></cr-network-icon>
+    </div>
+    <div>
+      <h3>cr-toggle-button</h3>
+      <div horizontal layout>
+        <span>Toggle Button</span>
+        <cr-toggle-button></cr-toggle-button>
+      </div>
+    </div>
+  </template>
+  <script src="demo_element.js"></script>
+</dom-module>
diff --git a/ui/webui/resources/cr_elements/v0_8/demo_element.js b/ui/webui/resources/cr_elements/v0_8/demo_element.js
new file mode 100644
index 0000000..0b3e9ce
--- /dev/null
+++ b/ui/webui/resources/cr_elements/v0_8/demo_element.js
@@ -0,0 +1,42 @@
+// 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.
+
+/**
+ * @fileoverview Polymer element for UI wrapping a list of cr- elements.
+ */
+Polymer({
+  is: 'cr-demo-element',
+
+  properties: {
+    checkboxChecked: {
+      type: Boolean,
+      value: true,
+      observer: 'checkboxCheckedChanged_'
+    },
+
+    collapseOpened: {
+      type: Boolean,
+      value: true,
+      observer: 'collapseOpenedChanged_'
+    },
+
+    inputValue: {
+      type: String,
+      value: '',
+      observer: 'inputValueChanged_'
+    },
+  },
+
+  checkboxCheckedChanged_: function() {
+    console.log('checkboxCheckedChanged=' + this.checkboxChecked);
+  },
+
+  collapseOpenedChanged_: function() {
+    console.log('collapseOpened=' + this.collapseOpened);
+  },
+
+  inputValueChanged_: function() {
+    console.log('inputValue=' + this.inputValue);
+  }
+});
diff --git a/ui/webui/resources/cr_elements/v0_8/demo_page.html b/ui/webui/resources/cr_elements/v0_8/demo_page.html
new file mode 100644
index 0000000..f918666
--- /dev/null
+++ b/ui/webui/resources/cr_elements/v0_8/demo_page.html
@@ -0,0 +1,19 @@
+<!doctype html>
+
+<!-- Demo page for cr-elements. Add new elements to demo_elements.html to -->
+<!-- view them and test their interactions with other elements. -->
+<!-- To view this page, navigate to: -->
+<!-- chrome://resources/cr_elements/v0_8/demo_page.html -->
+
+<html>
+
+<head>
+  <link href="demo_element.html" rel="import" >
+</head>
+
+<body>
+  <h1>cr-elements</h1>
+  <cr-demo-element></cr-demo-element>
+</body>
+
+</html>
diff --git a/ui/webui/resources/cr_elements_resources.grdp b/ui/webui/resources/cr_elements_resources.grdp
index 6bbe17c9..bc5ac369 100644
--- a/ui/webui/resources/cr_elements_resources.grdp
+++ b/ui/webui/resources/cr_elements_resources.grdp
@@ -105,6 +105,15 @@
 
   <!-- Polymer 0.8 Elements -->
   <if expr="enable_polymer_v08">
+    <structure name="IDR_CR_ELEMENTS_08_CR_DEMO_ELEMENT_HTML"
+               file="../../webui/resources/cr_elements/v0_8/demo_element.html"
+               type="chrome_html" />
+    <structure name="IDR_CR_ELEMENTS_08_CR_DEMO_ELEMENT_JS"
+               file="../../webui/resources/cr_elements/v0_8/demo_element.js"
+               type="chrome_html" />
+    <structure name="IDR_CR_ELEMENTS_08_CR_DEMO_PAGE_HTML"
+               file="../../webui/resources/cr_elements/v0_8/demo_page.html"
+               type="chrome_html" />
     <structure name="IDR_CR_ELEMENTS_08_CR_BUTTON_CSS"
                file="../../webui/resources/cr_elements/v0_8/cr_button/cr_button.css"
                type="chrome_html" />