Update from https://crrev.com/304418

Review URL: https://codereview.chromium.org/734063004
diff --git a/.clang-format b/.clang-format
index a543137..a7d210d 100644
--- a/.clang-format
+++ b/.clang-format
@@ -16,4 +16,5 @@
 AllowShortBlocksOnASingleLine: false
 AllowShortFunctionsOnASingleLine: None
 AllowShortIfStatementsOnASingleLine: true
+BreakBeforeBinaryOperators: NonAssignment
 Cpp11BracedListStyle: false  # but see http://llvm.org/PR21457
diff --git a/DEPS b/DEPS
index 3056c08..e4efdd4 100644
--- a/DEPS
+++ b/DEPS
@@ -22,23 +22,23 @@
   'libcxx_revision': '48198f9110397fff47fe7c37cbfa296be7d44d3d',
   'libcxxabi_revision': '4ad1009ab3a59fa7a6896d74d5e4de5885697f95',
   'sfntly_revision': '1bdaae8fc788a5ac8936d68bf24f37d977a13dac',
-  'skia_revision': 'bc97c9378bf8b89cc17280a2a04a5c3a9405e6ab',
+  'skia_revision': '0a81f1ee0edff6542a3a1579277780b67669c782',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and V8 without interference from each other.
-  'v8_revision': '43ced1bd1528ea8b4d9299d2c8f7c6a81921457b',
+  'v8_revision': '9a15b3ade98f52c91e2b42b22bf0d29b97f001f7',
   # 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": "560eef1627abdef65f71021b906e57dc609f47fa",
+  "angle_revision": "e1425d95ba0ab095c5d64536bbeb3f78adcbf79f",
   # 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.
-  'buildtools_revision': 'c27f95bd1d9baaef70c879dea375090dd1496147',
+  'buildtools_revision': '6ea835db27479b9a5742e48b5e4466af7c2534ff',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': '173f919d0ec99a1a973c9d3a82b474f761d5bce1',
+  'pdfium_revision': '56ba90c35c31c77be3f3249fcf2ecf26f6efc62f',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
@@ -78,7 +78,7 @@
    Var('chromium_git') + '/angle/angle.git' + '@' +  Var('angle_revision'),
 
   'src/third_party/icu':
-   Var('chromium_git') + '/chromium/deps/icu52.git' + '@' + 'd8b2a9d7b0039a4950ee008c5b1d998902c44c60', # from svn revision 292476
+   Var('chromium_git') + '/chromium/deps/icu52.git' + '@' + '6242e2fbb36f486f2c0addd1c3cef67fc4ed33fb', # from svn revision 292476
 
   'src/third_party/libc++/trunk':
    Var('chromium_git') + '/chromium/llvm-project/libcxx.git' + '@' +  Var('libcxx_revision'),
diff --git a/base/BUILD.gn b/base/BUILD.gn
index a0cdf66..2fc232d 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -399,6 +399,7 @@
     "metrics/histogram_delta_serialization.cc",
     "metrics/histogram_delta_serialization.",
     "metrics/histogram_flattener.h",
+    "metrics/histogram_macros.h",
     "metrics/histogram_samples.cc",
     "metrics/histogram_samples.h",
     "metrics/histogram_snapshot_manager.cc",
diff --git a/base/OWNERS b/base/OWNERS
index 92844b6..03c20e7 100644
--- a/base/OWNERS
+++ b/base/OWNERS
@@ -45,3 +45,8 @@
 per-file callback_unittest.h=ajwong@chromium.org
 per-file callback_unittest.nc=ajwong@chromium.org
 per-file security_unittest.cc=jln@chromium.org
+
+# For Android-specific changes:
+per-file *android*=nyquist@chromium.org
+per-file *android*=rmcilroy@chromium.org
+per-file *android*=yfriedman@chromium.org
diff --git a/base/base.gypi b/base/base.gypi
index 416a7e5..39bb08b 100644
--- a/base/base.gypi
+++ b/base/base.gypi
@@ -393,6 +393,7 @@
           'metrics/histogram_delta_serialization.cc',
           'metrics/histogram_delta_serialization.h',
           'metrics/histogram_flattener.h',
+          'metrics/histogram_macros.h',
           'metrics/histogram_samples.cc',
           'metrics/histogram_samples.h',
           'metrics/histogram_snapshot_manager.cc',
diff --git a/base/cancelable_callback.h b/base/cancelable_callback.h
index 159100f..91eb046 100644
--- a/base/cancelable_callback.h
+++ b/base/cancelable_callback.h
@@ -55,13 +55,13 @@
 template <typename Sig>
 class CancelableCallback;
 
-template <>
-class CancelableCallback<void(void)> {
+template <typename... A>
+class CancelableCallback<void(A...)> {
  public:
   CancelableCallback() : weak_factory_(this) {}
 
   // |callback| must not be null.
-  explicit CancelableCallback(const base::Callback<void(void)>& callback)
+  explicit CancelableCallback(const base::Callback<void(A...)>& callback)
       : weak_factory_(this),
         callback_(callback) {
     DCHECK(!callback.is_null());
@@ -84,7 +84,7 @@
 
   // Sets |callback| as the closure that may be cancelled. |callback| may not
   // be null. Outstanding and any previously wrapped callbacks are cancelled.
-  void Reset(const base::Callback<void(void)>& callback) {
+  void Reset(const base::Callback<void(A...)>& callback) {
     DCHECK(!callback.is_null());
 
     // Outstanding tasks (e.g., posted to a message loop) must not be called.
@@ -97,173 +97,36 @@
   }
 
   // Returns a callback that can be disabled by calling Cancel().
-  const base::Callback<void(void)>& callback() const {
+  const base::Callback<void(A...)>& callback() const {
     return forwarder_;
   }
 
  private:
-  void Forward() {
-    callback_.Run();
+  void Forward(A... args) const {
+    callback_.Run(args...);
   }
 
   // Helper method to bind |forwarder_| using a weak pointer from
   // |weak_factory_|.
   void InitializeForwarder() {
-    forwarder_ = base::Bind(&CancelableCallback<void(void)>::Forward,
+    forwarder_ = base::Bind(&CancelableCallback<void(A...)>::Forward,
                             weak_factory_.GetWeakPtr());
   }
 
   // Used to ensure Forward() is not run when this object is destroyed.
-  base::WeakPtrFactory<CancelableCallback<void(void)> > weak_factory_;
+  // TODO(ckehoe): This should be the last class member.
+  // Move it there when crbug.com/433583 is fixed.
+  base::WeakPtrFactory<CancelableCallback<void(A...)> > weak_factory_;
 
   // The wrapper closure.
-  base::Callback<void(void)> forwarder_;
+  base::Callback<void(A...)> forwarder_;
 
   // The stored closure that may be cancelled.
-  base::Callback<void(void)> callback_;
+  base::Callback<void(A...)> callback_;
 
   DISALLOW_COPY_AND_ASSIGN(CancelableCallback);
 };
 
-template <typename A1>
-class CancelableCallback<void(A1)> {
- public:
-  CancelableCallback() : weak_factory_(this) {}
-
-  // |callback| must not be null.
-  explicit CancelableCallback(const base::Callback<void(A1)>& callback)
-      : weak_factory_(this),
-        callback_(callback) {
-    DCHECK(!callback.is_null());
-    InitializeForwarder();
-  }
-
-  ~CancelableCallback() {}
-
-  // Cancels and drops the reference to the wrapped callback.
-  void Cancel() {
-    weak_factory_.InvalidateWeakPtrs();
-    forwarder_.Reset();
-    callback_.Reset();
-  }
-
-  // Returns true if the wrapped callback has been cancelled.
-  bool IsCancelled() const {
-    return callback_.is_null();
-  }
-
-  // Sets |callback| as the closure that may be cancelled. |callback| may not
-  // be null. Outstanding and any previously wrapped callbacks are cancelled.
-  void Reset(const base::Callback<void(A1)>& callback) {
-    DCHECK(!callback.is_null());
-
-    // Outstanding tasks (e.g., posted to a message loop) must not be called.
-    Cancel();
-
-    // |forwarder_| is no longer valid after Cancel(), so re-bind.
-    InitializeForwarder();
-
-    callback_ = callback;
-  }
-
-  // Returns a callback that can be disabled by calling Cancel().
-  const base::Callback<void(A1)>& callback() const {
-    return forwarder_;
-  }
-
- private:
-  void Forward(A1 a1) const {
-    callback_.Run(a1);
-  }
-
-  // Helper method to bind |forwarder_| using a weak pointer from
-  // |weak_factory_|.
-  void InitializeForwarder() {
-    forwarder_ = base::Bind(&CancelableCallback<void(A1)>::Forward,
-                            weak_factory_.GetWeakPtr());
-  }
-
-  // Used to ensure Forward() is not run when this object is destroyed.
-  base::WeakPtrFactory<CancelableCallback<void(A1)> > weak_factory_;
-
-  // The wrapper closure.
-  base::Callback<void(A1)> forwarder_;
-
-  // The stored closure that may be cancelled.
-  base::Callback<void(A1)> callback_;
-
-  DISALLOW_COPY_AND_ASSIGN(CancelableCallback);
-};
-
-template <typename A1, typename A2>
-class CancelableCallback<void(A1, A2)> {
- public:
-  CancelableCallback() : weak_factory_(this) {}
-
-  // |callback| must not be null.
-  explicit CancelableCallback(const base::Callback<void(A1, A2)>& callback)
-      : weak_factory_(this),
-        callback_(callback) {
-    DCHECK(!callback.is_null());
-    InitializeForwarder();
-  }
-
-  ~CancelableCallback() {}
-
-  // Cancels and drops the reference to the wrapped callback.
-  void Cancel() {
-    weak_factory_.InvalidateWeakPtrs();
-    forwarder_.Reset();
-    callback_.Reset();
-  }
-
-  // Returns true if the wrapped callback has been cancelled.
-  bool IsCancelled() const {
-    return callback_.is_null();
-  }
-
-  // Sets |callback| as the closure that may be cancelled. |callback| may not
-  // be null. Outstanding and any previously wrapped callbacks are cancelled.
-  void Reset(const base::Callback<void(A1, A2)>& callback) {
-    DCHECK(!callback.is_null());
-
-    // Outstanding tasks (e.g., posted to a message loop) must not be called.
-    Cancel();
-
-    // |forwarder_| is no longer valid after Cancel(), so re-bind.
-    InitializeForwarder();
-
-    callback_ = callback;
-  }
-
-  // Returns a callback that can be disabled by calling Cancel().
-  const base::Callback<void(A1, A2)>& callback() const {
-    return forwarder_;
-  }
-
- private:
-  void Forward(A1 a1, A2 a2) const {
-    callback_.Run(a1, a2);
-  }
-
-  // Helper method to bind |forwarder_| using a weak pointer from
-  // |weak_factory_|.
-  void InitializeForwarder() {
-    forwarder_ = base::Bind(&CancelableCallback<void(A1, A2)>::Forward,
-                            weak_factory_.GetWeakPtr());
-  }
-
-  // The wrapper closure.
-  base::Callback<void(A1, A2)> forwarder_;
-
-  // The stored closure that may be cancelled.
-  base::Callback<void(A1, A2)> callback_;
-
-  // Used to ensure Forward() is not run when this object is destroyed.
-  base::WeakPtrFactory<CancelableCallback<void(A1, A2)> > weak_factory_;
-  DISALLOW_COPY_AND_ASSIGN(CancelableCallback);
-};
-
 typedef CancelableCallback<void(void)> CancelableClosure;
 
 }  // namespace base
diff --git a/base/debug/trace_event_impl.cc b/base/debug/trace_event_impl.cc
index ce62766..1a64eb0 100644
--- a/base/debug/trace_event_impl.cc
+++ b/base/debug/trace_event_impl.cc
@@ -1185,6 +1185,12 @@
   // find the generation mismatch and delete this buffer soon.
 }
 
+TraceLogStatus::TraceLogStatus() : event_capacity(0), event_count(0) {
+}
+
+TraceLogStatus::~TraceLogStatus() {
+}
+
 // static
 TraceLog* TraceLog::GetInstance() {
   return Singleton<TraceLog, LeakySingletonTraits<TraceLog> >::get();
@@ -1586,10 +1592,12 @@
   return it != enabled_state_observer_list_.end();
 }
 
-float TraceLog::GetBufferPercentFull() const {
+TraceLogStatus TraceLog::GetStatus() const {
   AutoLock lock(lock_);
-  return static_cast<float>(static_cast<double>(logged_events_->Size()) /
-                            logged_events_->Capacity());
+  TraceLogStatus result;
+  result.event_capacity = logged_events_->Capacity();
+  result.event_count = logged_events_->Size();
+  return result;
 }
 
 bool TraceLog::BufferIsFull() const {
diff --git a/base/debug/trace_event_impl.h b/base/debug/trace_event_impl.h
index 6075e2d..ce2e017 100644
--- a/base/debug/trace_event_impl.h
+++ b/base/debug/trace_event_impl.h
@@ -420,6 +420,13 @@
   bool enable_systrace;
 };
 
+struct BASE_EXPORT TraceLogStatus {
+  TraceLogStatus();
+  ~TraceLogStatus();
+  size_t event_capacity;
+  size_t event_count;
+};
+
 class BASE_EXPORT TraceLog {
  public:
   enum Mode {
@@ -495,7 +502,7 @@
   void RemoveEnabledStateObserver(EnabledStateObserver* listener);
   bool HasEnabledStateObserver(EnabledStateObserver* listener) const;
 
-  float GetBufferPercentFull() const;
+  TraceLogStatus GetStatus() const;
   bool BufferIsFull() const;
 
   // Not using base::Callback because of its limited by 7 parameters.
@@ -603,7 +610,6 @@
   static void DeleteForTesting();
 
   // Allow tests to inspect TraceEvents.
-  size_t GetEventsSize() const { return logged_events_->Size(); }
   TraceEvent* GetEventByHandle(TraceEventHandle handle);
 
   void SetProcessID(int process_id);
diff --git a/base/debug/trace_event_unittest.cc b/base/debug/trace_event_unittest.cc
index 69b5743..0904954 100644
--- a/base/debug/trace_event_unittest.cc
+++ b/base/debug/trace_event_unittest.cc
@@ -1366,8 +1366,7 @@
 TEST_F(TraceEventTestFixture, StaticStringVsString) {
   TraceLog* tracer = TraceLog::GetInstance();
   // Make sure old events are flushed:
-  EndTraceAndFlush();
-  EXPECT_EQ(0u, tracer->GetEventsSize());
+  EXPECT_EQ(0u, tracer->GetStatus().event_count);
   const unsigned char* category_group_enabled =
       TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED("cat");
 
@@ -1384,8 +1383,7 @@
             TRACE_EVENT_PHASE_INSTANT, category_group_enabled, "name2", 0, 0,
             "arg1", TRACE_STR_COPY("argval"),
             "arg2", TRACE_STR_COPY("argval"));
-    size_t num_events = tracer->GetEventsSize();
-    EXPECT_GT(num_events, 1u);
+    EXPECT_GT(tracer->GetStatus().event_count, 1u);
     const TraceEvent* event1 = tracer->GetEventByHandle(handle1);
     const TraceEvent* event2 = tracer->GetEventByHandle(handle2);
     ASSERT_TRUE(event1);
@@ -1414,8 +1412,7 @@
             TRACE_EVENT_PHASE_INSTANT, category_group_enabled, "name2", 0, 0,
             "arg1", TRACE_STR_COPY(str1),
             "arg2", TRACE_STR_COPY(str2));
-    size_t num_events = tracer->GetEventsSize();
-    EXPECT_GT(num_events, 1u);
+    EXPECT_GT(tracer->GetStatus().event_count, 1u);
     const TraceEvent* event1 = tracer->GetEventByHandle(handle1);
     const TraceEvent* event2 = tracer->GetEventByHandle(handle2);
     ASSERT_TRUE(event1);
diff --git a/base/metrics/histogram.h b/base/metrics/histogram.h
index 43e7462..9ee172e 100644
--- a/base/metrics/histogram.h
+++ b/base/metrics/histogram.h
@@ -50,9 +50,12 @@
 // at the low end of the histogram scale, but allows the histogram to cover a
 // gigantic range with the addition of very few buckets.
 
-// Usually we use macros to define and use a histogram. These macros use a
-// pattern involving a function static variable, that is a pointer to a
-// histogram.  This static is explicitly initialized on any thread
+// Usually we use macros to define and use a histogram, which are defined in
+// base/metrics/histogram_macros.h. Note: Callers should include that header
+// directly if they only access the histogram APIs through macros.
+//
+// Macros use a pattern involving a function static variable, that is a pointer
+// to a histogram.  This static is explicitly initialized on any thread
 // that detects a uninitialized (NULL) pointer.  The potentially racy
 // initialization is not a problem as it is always set to point to the same
 // value (i.e., the FactoryGet always returns the same value).  FactoryGet
@@ -67,7 +70,6 @@
 #include <string>
 #include <vector>
 
-#include "base/atomicops.h"
 #include "base/base_export.h"
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
@@ -76,6 +78,8 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/metrics/bucket_ranges.h"
 #include "base/metrics/histogram_base.h"
+// TODO(asvitkine): Migrate callers to to include this directly and remove this.
+#include "base/metrics/histogram_macros.h"
 #include "base/metrics/histogram_samples.h"
 #include "base/time/time.h"
 
@@ -84,234 +88,11 @@
 
 namespace base {
 
-class Lock;
-//------------------------------------------------------------------------------
-// Histograms are often put in areas where they are called many many times, and
-// performance is critical.  As a result, they are designed to have a very low
-// recurring cost of executing (adding additional samples).  Toward that end,
-// the macros declare a static pointer to the histogram in question, and only
-// take a "slow path" to construct (or find) the histogram on the first run
-// through the macro.  We leak the histograms at shutdown time so that we don't
-// have to validate using the pointers at any time during the running of the
-// process.
-
-// The following code is generally what a thread-safe static pointer
-// initialization looks like for a histogram (after a macro is expanded).  This
-// sample is an expansion (with comments) of the code for
-// LOCAL_HISTOGRAM_CUSTOM_COUNTS().
-
-/*
-  do {
-    // The pointer's presence indicates the initialization is complete.
-    // Initialization is idempotent, so it can safely be atomically repeated.
-    static base::subtle::AtomicWord atomic_histogram_pointer = 0;
-
-    // Acquire_Load() ensures that we acquire visibility to the pointed-to data
-    // in the histogram.
-    base::Histogram* histogram_pointer(reinterpret_cast<base::Histogram*>(
-        base::subtle::Acquire_Load(&atomic_histogram_pointer)));
-
-    if (!histogram_pointer) {
-      // This is the slow path, which will construct OR find the matching
-      // histogram.  FactoryGet includes locks on a global histogram name map
-      // and is completely thread safe.
-      histogram_pointer = base::Histogram::FactoryGet(
-          name, min, max, bucket_count, base::HistogramBase::kNoFlags);
-
-      // Use Release_Store to ensure that the histogram data is made available
-      // globally before we make the pointer visible.
-      // Several threads may perform this store, but the same value will be
-      // stored in all cases (for a given named/spec'ed histogram).
-      // We could do this without any barrier, since FactoryGet entered and
-      // exited a lock after construction, but this barrier makes things clear.
-      base::subtle::Release_Store(&atomic_histogram_pointer,
-          reinterpret_cast<base::subtle::AtomicWord>(histogram_pointer));
-    }
-
-    // Ensure calling contract is upheld, and the name does NOT vary.
-    DCHECK(histogram_pointer->histogram_name() == constant_histogram_name);
-
-    histogram_pointer->Add(sample);
-  } while (0);
-*/
-
-// The above pattern is repeated in several macros.  The only elements that
-// vary are the invocation of the Add(sample) vs AddTime(sample), and the choice
-// of which FactoryGet method to use.  The different FactoryGet methods have
-// various argument lists, so the function with its argument list is provided as
-// a macro argument here.  The name is only used in a DCHECK, to assure that
-// callers don't try to vary the name of the histogram (which would tend to be
-// ignored by the one-time initialization of the histogtram_pointer).
-#define STATIC_HISTOGRAM_POINTER_BLOCK(constant_histogram_name, \
-                                       histogram_add_method_invocation, \
-                                       histogram_factory_get_invocation) \
-  do { \
-    static base::subtle::AtomicWord atomic_histogram_pointer = 0; \
-    base::HistogramBase* histogram_pointer( \
-        reinterpret_cast<base::HistogramBase*>( \
-            base::subtle::Acquire_Load(&atomic_histogram_pointer))); \
-    if (!histogram_pointer) { \
-      histogram_pointer = histogram_factory_get_invocation; \
-      base::subtle::Release_Store(&atomic_histogram_pointer, \
-          reinterpret_cast<base::subtle::AtomicWord>(histogram_pointer)); \
-    } \
-    if (DCHECK_IS_ON) \
-      histogram_pointer->CheckName(constant_histogram_name); \
-    histogram_pointer->histogram_add_method_invocation; \
-  } while (0)
-
-
-//------------------------------------------------------------------------------
-// Provide easy general purpose histogram in a macro, just like stats counters.
-// The first four macros use 50 buckets.
-
-#define LOCAL_HISTOGRAM_TIMES(name, sample) LOCAL_HISTOGRAM_CUSTOM_TIMES( \
-    name, sample, base::TimeDelta::FromMilliseconds(1), \
-    base::TimeDelta::FromSeconds(10), 50)
-
-// For folks that need real specific times, use this to select a precise range
-// of times you want plotted, and the number of buckets you want used.
-#define LOCAL_HISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) \
-    STATIC_HISTOGRAM_POINTER_BLOCK(name, AddTime(sample), \
-        base::Histogram::FactoryTimeGet(name, min, max, bucket_count, \
-                                        base::HistogramBase::kNoFlags))
-
-#define LOCAL_HISTOGRAM_COUNTS(name, sample) LOCAL_HISTOGRAM_CUSTOM_COUNTS( \
-    name, sample, 1, 1000000, 50)
-
-#define LOCAL_HISTOGRAM_COUNTS_100(name, sample) \
-    LOCAL_HISTOGRAM_CUSTOM_COUNTS(name, sample, 1, 100, 50)
-
-#define LOCAL_HISTOGRAM_COUNTS_10000(name, sample) \
-    LOCAL_HISTOGRAM_CUSTOM_COUNTS(name, sample, 1, 10000, 50)
-
-#define LOCAL_HISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) \
-    STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \
-        base::Histogram::FactoryGet(name, min, max, bucket_count, \
-                                    base::HistogramBase::kNoFlags))
-
-// This is a helper macro used by other macros and shouldn't be used directly.
-#define HISTOGRAM_ENUMERATION_WITH_FLAG(name, sample, boundary, flag) \
-    STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \
-        base::LinearHistogram::FactoryGet(name, 1, boundary, boundary + 1, \
-            flag))
-
-#define LOCAL_HISTOGRAM_PERCENTAGE(name, under_one_hundred) \
-    LOCAL_HISTOGRAM_ENUMERATION(name, under_one_hundred, 101)
-
-#define LOCAL_HISTOGRAM_BOOLEAN(name, sample) \
-    STATIC_HISTOGRAM_POINTER_BLOCK(name, AddBoolean(sample), \
-        base::BooleanHistogram::FactoryGet(name, base::Histogram::kNoFlags))
-
-// Support histograming of an enumerated value.  The samples should always be
-// strictly less than |boundary_value| -- this prevents you from running into
-// problems down the line if you add additional buckets to the histogram.  Note
-// also that, despite explicitly setting the minimum bucket value to |1| below,
-// it is fine for enumerated histograms to be 0-indexed -- this is because
-// enumerated histograms should never have underflow.
-#define LOCAL_HISTOGRAM_ENUMERATION(name, sample, boundary_value) \
-    STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \
-        base::LinearHistogram::FactoryGet(name, 1, boundary_value, \
-            boundary_value + 1, base::HistogramBase::kNoFlags))
-
-// Support histograming of an enumerated value. Samples should be one of the
-// std::vector<int> list provided via |custom_ranges|. See comments above
-// CustomRanges::FactoryGet about the requirement of |custom_ranges|.
-// You can use the helper function CustomHistogram::ArrayToCustomRanges to
-// transform a C-style array of valid sample values to a std::vector<int>.
-#define LOCAL_HISTOGRAM_CUSTOM_ENUMERATION(name, sample, custom_ranges) \
-    STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \
-        base::CustomHistogram::FactoryGet(name, custom_ranges, \
-                                          base::HistogramBase::kNoFlags))
-
-#define LOCAL_HISTOGRAM_MEMORY_KB(name, sample) LOCAL_HISTOGRAM_CUSTOM_COUNTS( \
-    name, sample, 1000, 500000, 50)
-
-//------------------------------------------------------------------------------
-// The following macros provide typical usage scenarios for callers that wish
-// to record histogram data, and have the data submitted/uploaded via UMA.
-// Not all systems support such UMA, but if they do, the following macros
-// should work with the service.
-
-#define UMA_HISTOGRAM_TIMES(name, sample) UMA_HISTOGRAM_CUSTOM_TIMES( \
-    name, sample, base::TimeDelta::FromMilliseconds(1), \
-    base::TimeDelta::FromSeconds(10), 50)
-
-#define UMA_HISTOGRAM_MEDIUM_TIMES(name, sample) UMA_HISTOGRAM_CUSTOM_TIMES( \
-    name, sample, base::TimeDelta::FromMilliseconds(10), \
-    base::TimeDelta::FromMinutes(3), 50)
-
-// Use this macro when times can routinely be much longer than 10 seconds.
-#define UMA_HISTOGRAM_LONG_TIMES(name, sample) UMA_HISTOGRAM_CUSTOM_TIMES( \
-    name, sample, base::TimeDelta::FromMilliseconds(1), \
-    base::TimeDelta::FromHours(1), 50)
-
-// Use this macro when times can routinely be much longer than 10 seconds and
-// you want 100 buckets.
-#define UMA_HISTOGRAM_LONG_TIMES_100(name, sample) UMA_HISTOGRAM_CUSTOM_TIMES( \
-    name, sample, base::TimeDelta::FromMilliseconds(1), \
-    base::TimeDelta::FromHours(1), 100)
-
-#define UMA_HISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) \
-    STATIC_HISTOGRAM_POINTER_BLOCK(name, AddTime(sample), \
-        base::Histogram::FactoryTimeGet(name, min, max, bucket_count, \
-            base::HistogramBase::kUmaTargetedHistogramFlag))
-
-#define UMA_HISTOGRAM_COUNTS(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
-    name, sample, 1, 1000000, 50)
-
-#define UMA_HISTOGRAM_COUNTS_100(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
-    name, sample, 1, 100, 50)
-
-#define UMA_HISTOGRAM_COUNTS_10000(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
-    name, sample, 1, 10000, 50)
-
-#define UMA_HISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) \
-    STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \
-        base::Histogram::FactoryGet(name, min, max, bucket_count, \
-            base::HistogramBase::kUmaTargetedHistogramFlag))
-
-#define UMA_HISTOGRAM_MEMORY_KB(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
-    name, sample, 1000, 500000, 50)
-
-#define UMA_HISTOGRAM_MEMORY_MB(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
-    name, sample, 1, 1000, 50)
-
-#define UMA_HISTOGRAM_PERCENTAGE(name, under_one_hundred) \
-    UMA_HISTOGRAM_ENUMERATION(name, under_one_hundred, 101)
-
-#define UMA_HISTOGRAM_BOOLEAN(name, sample) \
-    STATIC_HISTOGRAM_POINTER_BLOCK(name, AddBoolean(sample), \
-        base::BooleanHistogram::FactoryGet(name, \
-            base::HistogramBase::kUmaTargetedHistogramFlag))
-
-// The samples should always be strictly less than |boundary_value|.  For more
-// details, see the comment for the |LOCAL_HISTOGRAM_ENUMERATION| macro, above.
-#define UMA_HISTOGRAM_ENUMERATION(name, sample, boundary_value) \
-    HISTOGRAM_ENUMERATION_WITH_FLAG(name, sample, boundary_value, \
-        base::HistogramBase::kUmaTargetedHistogramFlag)
-
-// Similar to UMA_HISTOGRAM_ENUMERATION, but used for recording stability
-// histograms.  Use this if recording a histogram that should be part of the
-// initial stability log.
-#define UMA_STABILITY_HISTOGRAM_ENUMERATION(name, sample, boundary_value) \
-    HISTOGRAM_ENUMERATION_WITH_FLAG(name, sample, boundary_value, \
-        base::HistogramBase::kUmaStabilityHistogramFlag)
-
-#define UMA_HISTOGRAM_CUSTOM_ENUMERATION(name, sample, custom_ranges) \
-    STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \
-        base::CustomHistogram::FactoryGet(name, custom_ranges, \
-            base::HistogramBase::kUmaTargetedHistogramFlag))
-
-//------------------------------------------------------------------------------
-
-class BucketRanges;
-class SampleVector;
-
 class BooleanHistogram;
 class CustomHistogram;
 class Histogram;
 class LinearHistogram;
+class SampleVector;
 
 class BASE_EXPORT Histogram : public HistogramBase {
  public:
diff --git a/base/metrics/histogram_macros.h b/base/metrics/histogram_macros.h
new file mode 100644
index 0000000..a9996d1
--- /dev/null
+++ b/base/metrics/histogram_macros.h
@@ -0,0 +1,232 @@
+// 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 BASE_METRICS_HISTOGRAM_MACROS_H_
+#define BASE_METRICS_HISTOGRAM_MACROS_H_
+
+#include "base/atomicops.h"
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/metrics/histogram.h"
+#include "base/time/time.h"
+
+//------------------------------------------------------------------------------
+// Histograms are often put in areas where they are called many many times, and
+// performance is critical.  As a result, they are designed to have a very low
+// recurring cost of executing (adding additional samples).  Toward that end,
+// the macros declare a static pointer to the histogram in question, and only
+// take a "slow path" to construct (or find) the histogram on the first run
+// through the macro.  We leak the histograms at shutdown time so that we don't
+// have to validate using the pointers at any time during the running of the
+// process.
+
+// The following code is generally what a thread-safe static pointer
+// initialization looks like for a histogram (after a macro is expanded).  This
+// sample is an expansion (with comments) of the code for
+// LOCAL_HISTOGRAM_CUSTOM_COUNTS().
+
+/*
+  do {
+    // The pointer's presence indicates the initialization is complete.
+    // Initialization is idempotent, so it can safely be atomically repeated.
+    static base::subtle::AtomicWord atomic_histogram_pointer = 0;
+
+    // Acquire_Load() ensures that we acquire visibility to the pointed-to data
+    // in the histogram.
+    base::Histogram* histogram_pointer(reinterpret_cast<base::Histogram*>(
+        base::subtle::Acquire_Load(&atomic_histogram_pointer)));
+
+    if (!histogram_pointer) {
+      // This is the slow path, which will construct OR find the matching
+      // histogram.  FactoryGet includes locks on a global histogram name map
+      // and is completely thread safe.
+      histogram_pointer = base::Histogram::FactoryGet(
+          name, min, max, bucket_count, base::HistogramBase::kNoFlags);
+
+      // Use Release_Store to ensure that the histogram data is made available
+      // globally before we make the pointer visible.
+      // Several threads may perform this store, but the same value will be
+      // stored in all cases (for a given named/spec'ed histogram).
+      // We could do this without any barrier, since FactoryGet entered and
+      // exited a lock after construction, but this barrier makes things clear.
+      base::subtle::Release_Store(&atomic_histogram_pointer,
+          reinterpret_cast<base::subtle::AtomicWord>(histogram_pointer));
+    }
+
+    // Ensure calling contract is upheld, and the name does NOT vary.
+    DCHECK(histogram_pointer->histogram_name() == constant_histogram_name);
+
+    histogram_pointer->Add(sample);
+  } while (0);
+*/
+
+// The above pattern is repeated in several macros.  The only elements that
+// vary are the invocation of the Add(sample) vs AddTime(sample), and the choice
+// of which FactoryGet method to use.  The different FactoryGet methods have
+// various argument lists, so the function with its argument list is provided as
+// a macro argument here.  The name is only used in a DCHECK, to assure that
+// callers don't try to vary the name of the histogram (which would tend to be
+// ignored by the one-time initialization of the histogtram_pointer).
+#define STATIC_HISTOGRAM_POINTER_BLOCK(constant_histogram_name, \
+                                       histogram_add_method_invocation, \
+                                       histogram_factory_get_invocation) \
+  do { \
+    static base::subtle::AtomicWord atomic_histogram_pointer = 0; \
+    base::HistogramBase* histogram_pointer( \
+        reinterpret_cast<base::HistogramBase*>( \
+            base::subtle::Acquire_Load(&atomic_histogram_pointer))); \
+    if (!histogram_pointer) { \
+      histogram_pointer = histogram_factory_get_invocation; \
+      base::subtle::Release_Store(&atomic_histogram_pointer, \
+          reinterpret_cast<base::subtle::AtomicWord>(histogram_pointer)); \
+    } \
+    if (DCHECK_IS_ON) \
+      histogram_pointer->CheckName(constant_histogram_name); \
+    histogram_pointer->histogram_add_method_invocation; \
+  } while (0)
+
+
+//------------------------------------------------------------------------------
+// Provide easy general purpose histogram in a macro, just like stats counters.
+// The first four macros use 50 buckets.
+
+#define LOCAL_HISTOGRAM_TIMES(name, sample) LOCAL_HISTOGRAM_CUSTOM_TIMES( \
+    name, sample, base::TimeDelta::FromMilliseconds(1), \
+    base::TimeDelta::FromSeconds(10), 50)
+
+// For folks that need real specific times, use this to select a precise range
+// of times you want plotted, and the number of buckets you want used.
+#define LOCAL_HISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) \
+    STATIC_HISTOGRAM_POINTER_BLOCK(name, AddTime(sample), \
+        base::Histogram::FactoryTimeGet(name, min, max, bucket_count, \
+                                        base::HistogramBase::kNoFlags))
+
+#define LOCAL_HISTOGRAM_COUNTS(name, sample) LOCAL_HISTOGRAM_CUSTOM_COUNTS( \
+    name, sample, 1, 1000000, 50)
+
+#define LOCAL_HISTOGRAM_COUNTS_100(name, sample) \
+    LOCAL_HISTOGRAM_CUSTOM_COUNTS(name, sample, 1, 100, 50)
+
+#define LOCAL_HISTOGRAM_COUNTS_10000(name, sample) \
+    LOCAL_HISTOGRAM_CUSTOM_COUNTS(name, sample, 1, 10000, 50)
+
+#define LOCAL_HISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) \
+    STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \
+        base::Histogram::FactoryGet(name, min, max, bucket_count, \
+                                    base::HistogramBase::kNoFlags))
+
+// This is a helper macro used by other macros and shouldn't be used directly.
+#define HISTOGRAM_ENUMERATION_WITH_FLAG(name, sample, boundary, flag) \
+    STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \
+        base::LinearHistogram::FactoryGet(name, 1, boundary, boundary + 1, \
+            flag))
+
+#define LOCAL_HISTOGRAM_PERCENTAGE(name, under_one_hundred) \
+    LOCAL_HISTOGRAM_ENUMERATION(name, under_one_hundred, 101)
+
+#define LOCAL_HISTOGRAM_BOOLEAN(name, sample) \
+    STATIC_HISTOGRAM_POINTER_BLOCK(name, AddBoolean(sample), \
+        base::BooleanHistogram::FactoryGet(name, base::Histogram::kNoFlags))
+
+// Support histograming of an enumerated value.  The samples should always be
+// strictly less than |boundary_value| -- this prevents you from running into
+// problems down the line if you add additional buckets to the histogram.  Note
+// also that, despite explicitly setting the minimum bucket value to |1| below,
+// it is fine for enumerated histograms to be 0-indexed -- this is because
+// enumerated histograms should never have underflow.
+#define LOCAL_HISTOGRAM_ENUMERATION(name, sample, boundary_value) \
+    STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \
+        base::LinearHistogram::FactoryGet(name, 1, boundary_value, \
+            boundary_value + 1, base::HistogramBase::kNoFlags))
+
+// Support histograming of an enumerated value. Samples should be one of the
+// std::vector<int> list provided via |custom_ranges|. See comments above
+// CustomRanges::FactoryGet about the requirement of |custom_ranges|.
+// You can use the helper function CustomHistogram::ArrayToCustomRanges to
+// transform a C-style array of valid sample values to a std::vector<int>.
+#define LOCAL_HISTOGRAM_CUSTOM_ENUMERATION(name, sample, custom_ranges) \
+    STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \
+        base::CustomHistogram::FactoryGet(name, custom_ranges, \
+                                          base::HistogramBase::kNoFlags))
+
+#define LOCAL_HISTOGRAM_MEMORY_KB(name, sample) LOCAL_HISTOGRAM_CUSTOM_COUNTS( \
+    name, sample, 1000, 500000, 50)
+
+//------------------------------------------------------------------------------
+// The following macros provide typical usage scenarios for callers that wish
+// to record histogram data, and have the data submitted/uploaded via UMA.
+// Not all systems support such UMA, but if they do, the following macros
+// should work with the service.
+
+#define UMA_HISTOGRAM_TIMES(name, sample) UMA_HISTOGRAM_CUSTOM_TIMES( \
+    name, sample, base::TimeDelta::FromMilliseconds(1), \
+    base::TimeDelta::FromSeconds(10), 50)
+
+#define UMA_HISTOGRAM_MEDIUM_TIMES(name, sample) UMA_HISTOGRAM_CUSTOM_TIMES( \
+    name, sample, base::TimeDelta::FromMilliseconds(10), \
+    base::TimeDelta::FromMinutes(3), 50)
+
+// Use this macro when times can routinely be much longer than 10 seconds.
+#define UMA_HISTOGRAM_LONG_TIMES(name, sample) UMA_HISTOGRAM_CUSTOM_TIMES( \
+    name, sample, base::TimeDelta::FromMilliseconds(1), \
+    base::TimeDelta::FromHours(1), 50)
+
+// Use this macro when times can routinely be much longer than 10 seconds and
+// you want 100 buckets.
+#define UMA_HISTOGRAM_LONG_TIMES_100(name, sample) UMA_HISTOGRAM_CUSTOM_TIMES( \
+    name, sample, base::TimeDelta::FromMilliseconds(1), \
+    base::TimeDelta::FromHours(1), 100)
+
+#define UMA_HISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) \
+    STATIC_HISTOGRAM_POINTER_BLOCK(name, AddTime(sample), \
+        base::Histogram::FactoryTimeGet(name, min, max, bucket_count, \
+            base::HistogramBase::kUmaTargetedHistogramFlag))
+
+#define UMA_HISTOGRAM_COUNTS(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
+    name, sample, 1, 1000000, 50)
+
+#define UMA_HISTOGRAM_COUNTS_100(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
+    name, sample, 1, 100, 50)
+
+#define UMA_HISTOGRAM_COUNTS_10000(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
+    name, sample, 1, 10000, 50)
+
+#define UMA_HISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) \
+    STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \
+        base::Histogram::FactoryGet(name, min, max, bucket_count, \
+            base::HistogramBase::kUmaTargetedHistogramFlag))
+
+#define UMA_HISTOGRAM_MEMORY_KB(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
+    name, sample, 1000, 500000, 50)
+
+#define UMA_HISTOGRAM_MEMORY_MB(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
+    name, sample, 1, 1000, 50)
+
+#define UMA_HISTOGRAM_PERCENTAGE(name, under_one_hundred) \
+    UMA_HISTOGRAM_ENUMERATION(name, under_one_hundred, 101)
+
+#define UMA_HISTOGRAM_BOOLEAN(name, sample) \
+    STATIC_HISTOGRAM_POINTER_BLOCK(name, AddBoolean(sample), \
+        base::BooleanHistogram::FactoryGet(name, \
+            base::HistogramBase::kUmaTargetedHistogramFlag))
+
+// The samples should always be strictly less than |boundary_value|.  For more
+// details, see the comment for the |LOCAL_HISTOGRAM_ENUMERATION| macro, above.
+#define UMA_HISTOGRAM_ENUMERATION(name, sample, boundary_value) \
+    HISTOGRAM_ENUMERATION_WITH_FLAG(name, sample, boundary_value, \
+        base::HistogramBase::kUmaTargetedHistogramFlag)
+
+// Similar to UMA_HISTOGRAM_ENUMERATION, but used for recording stability
+// histograms.  Use this if recording a histogram that should be part of the
+// initial stability log.
+#define UMA_STABILITY_HISTOGRAM_ENUMERATION(name, sample, boundary_value) \
+    HISTOGRAM_ENUMERATION_WITH_FLAG(name, sample, boundary_value, \
+        base::HistogramBase::kUmaStabilityHistogramFlag)
+
+#define UMA_HISTOGRAM_CUSTOM_ENUMERATION(name, sample, custom_ranges) \
+    STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \
+        base::CustomHistogram::FactoryGet(name, custom_ranges, \
+            base::HistogramBase::kUmaTargetedHistogramFlag))
+
+#endif  // BASE_METRICS_HISTOGRAM_MACROS_H_
diff --git a/base/sys_info_android.cc b/base/sys_info_android.cc
index 0d885ee..829053f 100644
--- a/base/sys_info_android.cc
+++ b/base/sys_info_android.cc
@@ -59,8 +59,8 @@
 // cannot be acquired. Use the latest Android release with a higher bug fix
 // version to avoid unnecessarily comparison errors with the latest release.
 // This should be manually kept up-to-date on each Android release.
-const int kDefaultAndroidMajorVersion = 4;
-const int kDefaultAndroidMinorVersion = 4;
+const int kDefaultAndroidMajorVersion = 5;
+const int kDefaultAndroidMinorVersion = 0;
 const int kDefaultAndroidBugfixVersion = 99;
 
 // Parse out the OS version numbers from the system properties.
diff --git a/base/test/multiprocess_test_android.cc b/base/test/multiprocess_test_android.cc
index 4cfae5e..8f54b82 100644
--- a/base/test/multiprocess_test_android.cc
+++ b/base/test/multiprocess_test_android.cc
@@ -2,13 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/posix/global_descriptors.h"
 #include "base/test/multiprocess_test.h"
 
 #include <unistd.h>
 
+#include "base/base_switches.h"
+#include "base/command_line.h"
 #include "base/containers/hash_tables.h"
 #include "base/logging.h"
+#include "base/posix/global_descriptors.h"
 #include "testing/multiprocess_func_list.h"
 
 namespace base {
@@ -16,7 +18,6 @@
 // A very basic implementation for Android. On Android tests can run in an APK
 // and we don't have an executable to exec*. This implementation does the bare
 // minimum to execute the method specified by procname (in the child process).
-//  - |base_command_line| is ignored.
 //  - All options except |fds_to_remap| are ignored.
 ProcessHandle SpawnMultiProcessTestChild(const std::string& procname,
                                          const CommandLine& base_command_line,
@@ -60,6 +61,13 @@
     }
     close(old_fd);
   }
+  CommandLine::Reset();
+  CommandLine::Init(0, nullptr);
+  CommandLine* command_line = CommandLine::ForCurrentProcess();
+  command_line->InitFromArgv(base_command_line.argv());
+  if (!command_line->HasSwitch(switches::kTestChildProcess))
+    command_line->AppendSwitchASCII(switches::kTestChildProcess, procname);
+
   _exit(multi_process_function_list::InvokeChildProcessTest(procname));
   return 0;
 }
diff --git a/build/all.gyp b/build/all.gyp
index d47fc79..a11ee7a 100644
--- a/build/all.gyp
+++ b/build/all.gyp
@@ -42,13 +42,13 @@
             # NOTE: This list of targets is present because
             # mojo_base.gyp:mojo_base cannot be built on iOS, as
             # javascript-related targets cause v8 to be built.
-            '../mojo/edk/mojo_edk_tests.gyp:mojo_public_bindings_unittests',
-            '../mojo/edk/mojo_edk_tests.gyp:mojo_public_environment_unittests',
-            '../mojo/edk/mojo_edk_tests.gyp:mojo_public_system_perftests',
-            '../mojo/edk/mojo_edk_tests.gyp:mojo_public_system_unittests',
-            '../mojo/edk/mojo_edk_tests.gyp:mojo_public_utility_unittests',
+            '../mojo/edk/mojo_edk.gyp:mojo_public_bindings_unittests',
+            '../mojo/edk/mojo_edk.gyp:mojo_public_environment_unittests',
+            '../mojo/edk/mojo_edk.gyp:mojo_public_system_perftests',
+            '../mojo/edk/mojo_edk.gyp:mojo_public_system_unittests',
+            '../mojo/edk/mojo_edk.gyp:mojo_public_utility_unittests',
             '../mojo/edk/mojo_edk.gyp:mojo_system_impl',
-            '../mojo/edk/mojo_edk_tests.gyp:mojo_system_unittests',
+            '../mojo/edk/mojo_edk.gyp:mojo_system_unittests',
             '../mojo/mojo_base.gyp:mojo_common_lib',
             '../mojo/mojo_base.gyp:mojo_common_unittests',
             '../mojo/public/mojo_public.gyp:mojo_cpp_bindings',
@@ -689,6 +689,13 @@
             '../third_party/webrtc/tools/tools.gyp:frame_analyzer',
             '../third_party/webrtc/tools/tools.gyp:rgba_to_i420_converter',
           ],
+          'conditions': [
+            ['remoting==1', {
+              'dependencies': [
+                '../remoting/remoting.gyp:*',
+              ],
+            }],
+          ],
         },  # target_name: chromium_builder_webrtc
         {
           'target_name': 'chromium_builder_chromedriver',
@@ -868,6 +875,8 @@
             '../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',
+            '../components/devtools_bridge.gyp:devtools_bridge_tests2_apk',
             '../content/content_shell_and_tests.gyp:content_browsertests_apk',
           ],
         },  # target_name: android_builder_chromium_webrtc
diff --git a/build/android/buildbot/bb_device_steps.py b/build/android/buildbot/bb_device_steps.py
index d113842..530512a 100755
--- a/build/android/buildbot/bb_device_steps.py
+++ b/build/android/buildbot/bb_device_steps.py
@@ -124,6 +124,9 @@
     args += ['--target', 'Release']
   else:
     args += ['--target', 'Debug']
+  if options.flakiness_server:
+    args += ['--flakiness-dashboard-server=%s' %
+                options.flakiness_server]
   args += cmd
   RunCmd(args, cwd=DIR_BUILD_ROOT)
 
@@ -150,9 +153,6 @@
     args.append('--tool=asan')
   if options.gtest_filter:
     args.append('--gtest-filter=%s' % options.gtest_filter)
-  if options.flakiness_server:
-    args.append('--flakiness-dashboard-server=%s' %
-                options.flakiness_server)
 
   for suite in suites:
     bb_annotations.PrintNamedStep(suite)
diff --git a/build/android/pylib/device/device_utils.py b/build/android/pylib/device/device_utils.py
index f6bebce..334b74c 100644
--- a/build/android/pylib/device/device_utils.py
+++ b/build/android/pylib/device/device_utils.py
@@ -315,7 +315,7 @@
 
     self.adb.Reboot()
     self._cache = {}
-    timeout_retry.WaitFor(device_offline, wait_period=1, max_tries=5)
+    timeout_retry.WaitFor(device_offline, wait_period=1)
     if block:
       self.WaitUntilFullyBooted()
 
diff --git a/build/android/pylib/gtest/filter/content_browsertests_disabled b/build/android/pylib/gtest/filter/content_browsertests_disabled
index 748f680..0314f5f 100644
--- a/build/android/pylib/gtest/filter/content_browsertests_disabled
+++ b/build/android/pylib/gtest/filter/content_browsertests_disabled
@@ -23,11 +23,6 @@
 FileSystemBrowserTestWithLowQuota.QuotaTest
 ChildProcessSecurityPolicyInProcessBrowserTest.NoLeak
 
-# Needs to start the test server before
-# BrowserTestBase::SetUpCommandLine is called, but on Android
-# the test server needs to be started in SetUpOnMainThread().
-SecurityExploitBrowserTest.SetWebUIProperty
-
 # Plugins are not supported.
 BrowserPluginThreadedCompositorPixelTest.*
 BrowserPluginHostTest.*
@@ -108,10 +103,6 @@
 # http://crbug.com/338408
 TracingControllerTest.EnableCaptureAndDisableMonitoring
 
-# http://crbug.com/338023
-SecurityExploitBrowserTest.AttemptDuplicateRenderViewHost
-SecurityExploitBrowserTest.AttemptDuplicateRenderWidgetHost
-
 # http://crbug.com/338411
 FrameTreeBrowserTest.NavigateWithLeftoverFrames
 
diff --git a/build/android/pylib/gtest/test_runner.py b/build/android/pylib/gtest/test_runner.py
index 56e7449..66feea6 100644
--- a/build/android/pylib/gtest/test_runner.py
+++ b/build/android/pylib/gtest/test_runner.py
@@ -79,8 +79,8 @@
 
     # Test case statuses.
     re_run = re.compile('\[ RUN      \] ?(.*)\r\n')
-    re_fail = re.compile('\[  FAILED  \] ?(.*)\r\n')
-    re_ok = re.compile('\[       OK \] ?(.*?) .*\r\n')
+    re_fail = re.compile('\[  FAILED  \] ?(.*?)( \((\d+) ms\))?\r\r\n')
+    re_ok = re.compile('\[       OK \] ?(.*?)( \((\d+) ms\))?\r\r\n')
 
     # Test run statuses.
     re_passed = re.compile('\[  PASSED  \] ?(.*)\r\n')
@@ -93,6 +93,7 @@
     try:
       while True:
         full_test_name = None
+
         found = p.expect([re_run, re_passed, re_runner_fail],
                          timeout=self._timeout)
         if found == 1:  # re_passed
@@ -105,17 +106,20 @@
           log = p.before.replace('\r', '')
           if found == 0:  # re_ok
             if full_test_name == p.match.group(1).replace('\r', ''):
+              duration_ms = int(p.match.group(3)) if p.match.group(3) else 0
               results.AddResult(base_test_result.BaseTestResult(
                   full_test_name, base_test_result.ResultType.PASS,
-                  log=log))
+                  duration=duration_ms, log=log))
           elif found == 2:  # re_crash
             results.AddResult(base_test_result.BaseTestResult(
                 full_test_name, base_test_result.ResultType.CRASH,
                 log=log))
             break
           else:  # re_fail
+            duration_ms = int(p.match.group(3)) if p.match.group(3) else 0
             results.AddResult(base_test_result.BaseTestResult(
-                full_test_name, base_test_result.ResultType.FAIL, log=log))
+                full_test_name, base_test_result.ResultType.FAIL,
+                duration=duration_ms, log=log))
     except pexpect.EOF:
       logging.error('Test terminated - EOF')
       # We're here because either the device went offline, or the test harness
diff --git a/build/common.gypi b/build/common.gypi
index 3ddb01a..30ba070 100644
--- a/build/common.gypi
+++ b/build/common.gypi
@@ -1292,6 +1292,11 @@
     # Experimental setting to optimize Chrome's DLLs with PGO.
     'chrome_pgo_phase%': '0',
 
+    # Whether the VS xtree header has been patched to disable warning 4702. If
+    # it has, then we don't need to disable 4702 (unreachable code warning).
+    # The patch is preapplied to the internal toolchain and hence all bots.
+    'msvs_xtree_patched%': '<!pymod_do_main(win_is_xtree_patched)',
+
     # Clang stuff.
     'clang%': '<(clang)',
     'host_clang%': '<(host_clang)',
@@ -1565,7 +1570,7 @@
       ['OS=="win" and "<!pymod_do_main(dir_exists <(windows_sdk_default_path))"=="True"', {
         'windows_sdk_path%': '<(windows_sdk_default_path)',
       }, {
-        'windows_sdk_path%': 'C:/Program Files (x86)/Windows Kits/8.0',
+        'windows_sdk_path%': 'C:/Program Files (x86)/Windows Kits/8.1',
       }],
       ['OS=="win" and "<!pymod_do_main(dir_exists <(directx_sdk_default_path))"=="True"', {
         'directx_sdk_path%': '<(directx_sdk_default_path)',
@@ -2785,7 +2790,7 @@
           '_SCL_SECURE_NO_DEPRECATE',
           # This define is required to pull in the new Win8 interfaces from
           # system headers like ShObjIdl.h.
-          'NTDDI_VERSION=0x06020000',
+          'NTDDI_VERSION=0x06030000',
           # This is required for ATL to use XP-safe versions of its functions.
           '_USING_V110_SDK71_',
         ],
@@ -5259,8 +5264,8 @@
     ['OS=="win"', {
       'target_defaults': {
         'defines': [
-          '_WIN32_WINNT=0x0602',
-          'WINVER=0x0602',
+          '_WIN32_WINNT=0x0603',
+          'WINVER=0x0603',
           'WIN32',
           '_WINDOWS',
           'NOMINMAX',
@@ -5271,6 +5276,9 @@
           '_ATL_NO_OPENGL',
           # _HAS_EXCEPTIONS must match ExceptionHandling in msvs_settings.
           '_HAS_EXCEPTIONS=0',
+          # Silence some warnings; we can't switch the the 'recommended'
+          # versions as they're not available on old OSs.
+          '_WINSOCK_DEPRECATED_NO_WARNINGS',
         ],
         'conditions': [
           ['buildtype=="Official"', {
@@ -5338,6 +5346,14 @@
               ],
             },
           ],
+          ['msvs_xtree_patched!=1', {
+            # If xtree hasn't been patched, then we disable C4702. Otherwise,
+            # it's enabled. This will generally only be true for system-level
+            # installed Express users.
+            'msvs_disabled_warnings': [
+              4702,
+            ],
+          }],
           ['secure_atl', {
             'defines': [
               '_SECURE_ATL',
@@ -5370,12 +5386,6 @@
                 },
               },
             },
-            # https://code.google.com/p/chromium/issues/detail?id=372451#c20
-            # Warning 4702 ("Unreachable code") should be re-enabled once
-            # Express users are updated to VS2013 Update 2.
-            'msvs_disabled_warnings': [
-              4702
-            ],
             'msvs_settings': {
               'VCCLCompilerTool': {
                 'AdditionalOptions!': [
@@ -5463,6 +5473,7 @@
           4510, # Default constructor could not be generated
           4512, # Assignment operator could not be generated
           4610, # Object can never be instantiated
+          4996, # 'X': was declared deprecated (for GetVersionEx).
         ],
         'msvs_settings': {
           'VCCLCompilerTool': {
diff --git a/build/config/BUILDCONFIG.gn b/build/config/BUILDCONFIG.gn
index c9ec4a2..0d65c44 100644
--- a/build/config/BUILDCONFIG.gn
+++ b/build/config/BUILDCONFIG.gn
@@ -34,15 +34,6 @@
   # to configure warnings.
   is_clang = (os == "mac" || os == "ios" || os == "linux" || os == "chromeos")
 
-  # Forces a 64-bit build on Windows. Does nothing on other platforms. Normally
-  # we build 32-bit on Windows regardless of the current host OS bit depth.
-  # Setting this flag will override this logic and generate 64-bit toolchains.
-  #
-  # Normally this would get set automatically when you specify a target using
-  # the 64-bit toolchain. You can also set this on the command line to convert
-  # the default toolchain to 64-bit.
-  force_win64 = false
-
   # Selects the desired build flavor. Official builds get additional
   # processing to prepare for release. Normally you will want to develop and
   # test with this flag off.
@@ -174,16 +165,6 @@
 # CPU ARCHITECTURE
 # =============================================================================
 
-if (is_win) {
-  # Always use 32-bit on Windows, even when compiling on a 64-bit host OS,
-  # unless the override flag is specified.
-  if (force_win64) {
-    cpu_arch = "x64"
-  } else {
-    cpu_arch = "x86"
-  }
-}
-
 if (is_android) {
   # TODO(cjhopman): enable this assert once bots are updated to not set
   # cpu_arch.
@@ -495,19 +476,14 @@
 # default toolchain.
 
 if (is_win) {
-  # TODO(brettw) name the toolchains the same as cpu_arch as with Linux below
-  # to eliminate these conditionals.
-  if (build_cpu_arch == "x64") {
+  # On windows we use the same toolchain for host and target by default.
+  # TODO(dpranke): rename the toolchains to x64 and x86 to match cpu_arch.
+  if (cpu_arch == "x64") {
     host_toolchain = "//build/toolchain/win:64"
-  } else if (build_cpu_arch == "x86") {
+  } else if (cpu_arch == "x86") {
     host_toolchain = "//build/toolchain/win:32"
   }
-
-  if (cpu_arch == "x64") {
-    set_default_toolchain("//build/toolchain/win:64")
-  } else if (cpu_arch == "x86") {
-    set_default_toolchain("//build/toolchain/win:32")
-  }
+  set_default_toolchain("$host_toolchain")
 } else if (is_android) {
   # Use clang for the x86/64 Linux host builds.
   if (build_cpu_arch == "x86" || build_cpu_arch == "x64") {
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni
index d28c481..c130dd4 100644
--- a/build/config/android/rules.gni
+++ b/build/config/android/rules.gni
@@ -993,7 +993,10 @@
           " Chromium linker.")
     }
 
-    _native_libs = invoker.native_libs
+    _native_libs = process_file_template(
+        invoker.native_libs,
+        "$root_build_dir/lib.stripped/{{source_file_part}}")
+
     _native_libs_dir = base_path + "/libs"
 
     if (_use_chromium_linker) {
@@ -1220,10 +1223,9 @@
 #     resource dependencies of the apk.
 #   unittests_dep: This should be the label of the gtest native target. This
 #     target must be defined previously in the same file.
-#   unittests_binary: The name of the binary produced by the unittests_dep
-#     target, relative to the root build directory. If unspecified, it assumes
-#     the name of the unittests_dep target (which will be correct unless that
-#     target specifies an "output_name".
+#   unittests_binary: The basename of the library produced by the unittests_dep
+#     target. If unspecified, it assumes the name of the unittests_dep target
+#     (which will be correct unless that target specifies an "output_name".
 #     TODO(brettw) make this automatic by allowing get_target_outputs to
 #     support executables.
 #
@@ -1240,9 +1242,9 @@
   test_suite_name = get_label_info(invoker.unittests_dep, "name")
 
   if (defined(invoker.unittests_binary)) {
-    unittests_binary = root_out_dir + "/" + invoker.unittests_binary
+    unittests_binary = invoker.unittests_binary
   } else {
-    unittests_binary = root_out_dir + "/lib.stripped/lib" + test_suite_name + ".so"
+    unittests_binary = "lib" + test_suite_name + ".so"
   }
 
   android_apk(target_name) {
@@ -1252,8 +1254,7 @@
       "//testing/android/java/src/org/chromium/native_test/ChromeNativeTestActivity.java"
     ]
     android_manifest = "//testing/android/java/AndroidManifest.xml"
-    unittests_outputs = [ unittests_binary ]
-    native_libs = [unittests_outputs[0]]
+    native_libs = [ unittests_binary ]
     deps = [ "//base:base_java" ]
     if (defined(invoker.deps)) {
       deps += invoker.deps
diff --git a/build/config/win/BUILD.gn b/build/config/win/BUILD.gn
index 0f00a1e..51ba62a 100644
--- a/build/config/win/BUILD.gn
+++ b/build/config/win/BUILD.gn
@@ -13,7 +13,7 @@
     "_ATL_NO_OPENGL",
     "_WINDOWS",
     "CERT_CHAIN_PARA_HAS_EXTRA_FIELDS",
-    "NTDDI_VERSION=0x06020000",
+    "NTDDI_VERSION=0x06030000",
     "PSAPI_VERSION=1",
     "WIN32",
   ]
@@ -35,8 +35,8 @@
 # targets need to manually override it for their compiles.
 config("winver") {
   defines = [
-    "_WIN32_WINNT=0x0602",
-    "WINVER=0x0602",
+    "_WIN32_WINNT=0x0603",
+    "WINVER=0x0603",
   ]
 }
 
diff --git a/build/get_landmines.py b/build/get_landmines.py
index 1eec5ee..2c3b3d7 100755
--- a/build/get_landmines.py
+++ b/build/get_landmines.py
@@ -48,6 +48,7 @@
       gyp_msvs_version().startswith('2013')):
     print "Switched win from VS2010 to VS2013."
     print "Update to VS2013 Update 2."
+    print "Update to VS2013 Update 4."
   print 'Need to clobber everything due to an IDL change in r154579 (blink)'
   print 'Need to clobber everything due to gen file moves in r175513 (Blink)'
   if (platform() != 'ios'):
diff --git a/build/toolchain/win/BUILD.gn b/build/toolchain/win/BUILD.gn
index a9fab7c..988683d 100644
--- a/build/toolchain/win/BUILD.gn
+++ b/build/toolchain/win/BUILD.gn
@@ -24,7 +24,6 @@
 # Parameters:
 #  cpu_arch: cpu_arch to pass as a build arg
 #  environment: File name of environment file.
-#  force_win64 (optional): value for this build arg.
 template("msvc_toolchain") {
   if (defined(invoker.concurrent_links)) {
     concurrent_links = invoker.concurrent_links
@@ -32,6 +31,16 @@
 
   env = invoker.environment
 
+  if (is_debug) {
+    configuration = "Debug"
+  } else {
+    configuration = "Release"
+  }
+  exec_script("../../vs_toolchain.py", ["copy_dlls",
+                                        rebase_path(root_build_dir),
+                                        configuration,
+                                        invoker.cpu_arch])
+
   toolchain(target_name) {
     # Make these apply to all tools below.
     lib_switch = ""
@@ -154,23 +163,24 @@
     # passed to the build. They are ignored when this is the default toolchain.
     toolchain_args() {
       cpu_arch = invoker.cpu_arch
-
-      # Normally the build config resets the CPU architecture to 32-bits. Setting
-      # this flag overrides that behavior.
-      if (defined(invoker.force_win64)) {
-        force_win64 = invoker.force_win64
-      }
     }
   }
 }
 
-msvc_toolchain("32") {
-  environment = "environment.x86"
-  cpu_arch = "x64"
+# TODO(dpranke): Declare both toolchains all of the time when we
+# get it sorted out how we want to support them both in a single build.
+# Right now only one of these can be enabled at a time because the
+# runtime libraries get copied to root_build_dir and would collide.
+if (cpu_arch == "x86") {
+  msvc_toolchain("32") {
+    environment = "environment.x86"
+    cpu_arch = "x86"
+  }
 }
 
-msvc_toolchain("64") {
-  environment = "environment.x64"
-  cpu_arch = "x64"
-  force_win64 = true
+if (cpu_arch == "x64") {
+  msvc_toolchain("64") {
+    environment = "environment.x64"
+    cpu_arch = "x64"
+  }
 }
diff --git a/build/toolchain_vs2013.hash b/build/toolchain_vs2013.hash
new file mode 100644
index 0000000..4ed8816
--- /dev/null
+++ b/build/toolchain_vs2013.hash
@@ -0,0 +1 @@
+ee7d718ec60c2dc5d255bbe325909c2021a7efef
diff --git a/build/vs_toolchain.py b/build/vs_toolchain.py
index bdedd6f..a490a2c 100644
--- a/build/vs_toolchain.py
+++ b/build/vs_toolchain.py
@@ -63,6 +63,29 @@
   return vs2013_runtime_dll_dirs
 
 
+def _CopyRuntimeImpl(target, source):
+  """Copy |source| to |target| if it doesn't already exist or if it
+  needs to be updated.
+  """
+  if (os.path.isdir(os.path.dirname(target)) and
+      (not os.path.isfile(target) or
+      os.stat(target).st_mtime != os.stat(source).st_mtime)):
+    print 'Copying %s to %s...' % (source, target)
+    if os.path.exists(target):
+      os.unlink(target)
+    shutil.copy2(source, target)
+
+
+def _CopyRuntime(target_dir, source_dir, dll_pattern):
+    """Copy both the msvcr and msvcp runtime DLLs, only if the target doesn't
+    exist, but the target directory does exist."""
+    for which in ('p', 'r'):
+      dll = dll_pattern % which
+      target = os.path.join(target_dir, dll)
+      source = os.path.join(source_dir, dll)
+      _CopyRuntimeImpl(target, source)
+
+
 def CopyVsRuntimeDlls(output_dir, runtime_dirs):
   """Copies the VS runtime DLLs from the given |runtime_dirs| to the output
   directory so that even if not system-installed, built binaries are likely to
@@ -73,27 +96,6 @@
   """
   assert sys.platform.startswith(('win32', 'cygwin'))
 
-  def copy_runtime_impl(target, source):
-    """Copy |source| to |target| if it doesn't already exist or if it need to be
-    updated.
-    """
-    if (os.path.isdir(os.path.dirname(target)) and
-        (not os.path.isfile(target) or
-          os.stat(target).st_mtime != os.stat(source).st_mtime)):
-      print 'Copying %s to %s...' % (source, target)
-      if os.path.exists(target):
-        os.unlink(target)
-      shutil.copy2(source, target)
-
-  def copy_runtime(target_dir, source_dir, dll_pattern):
-    """Copy both the msvcr and msvcp runtime DLLs, only if the target doesn't
-    exist, but the target directory does exist."""
-    for which in ('p', 'r'):
-      dll = dll_pattern % which
-      target = os.path.join(target_dir, dll)
-      source = os.path.join(source_dir, dll)
-      copy_runtime_impl(target, source)
-
   x86, x64 = runtime_dirs
   out_debug = os.path.join(output_dir, 'Debug')
   out_debug_nacl64 = os.path.join(output_dir, 'Debug', 'x64')
@@ -106,12 +108,12 @@
     os.makedirs(out_debug_nacl64)
   if os.path.exists(out_release) and not os.path.exists(out_release_nacl64):
     os.makedirs(out_release_nacl64)
-  copy_runtime(out_debug,          x86, 'msvc%s120d.dll')
-  copy_runtime(out_release,        x86, 'msvc%s120.dll')
-  copy_runtime(out_debug_x64,      x64, 'msvc%s120d.dll')
-  copy_runtime(out_release_x64,    x64, 'msvc%s120.dll')
-  copy_runtime(out_debug_nacl64,   x64, 'msvc%s120d.dll')
-  copy_runtime(out_release_nacl64, x64, 'msvc%s120.dll')
+  _CopyRuntime(out_debug,          x86, 'msvc%s120d.dll')
+  _CopyRuntime(out_release,        x86, 'msvc%s120.dll')
+  _CopyRuntime(out_debug_x64,      x64, 'msvc%s120d.dll')
+  _CopyRuntime(out_release_x64,    x64, 'msvc%s120.dll')
+  _CopyRuntime(out_debug_nacl64,   x64, 'msvc%s120d.dll')
+  _CopyRuntime(out_release_nacl64, x64, 'msvc%s120.dll')
 
   # Copy the PGO runtime library to the release directories.
   if os.environ.get('GYP_MSVS_OVERRIDE_PATH'):
@@ -121,18 +123,37 @@
     pgo_runtime_dll = 'pgort120.dll'
     source_x86 = os.path.join(pgo_x86_runtime_dir, pgo_runtime_dll)
     if os.path.exists(source_x86):
-      copy_runtime_impl(os.path.join(out_release, pgo_runtime_dll), source_x86)
+      _CopyRuntimeImpl(os.path.join(out_release, pgo_runtime_dll), source_x86)
     source_x64 = os.path.join(pgo_x64_runtime_dir, pgo_runtime_dll)
     if os.path.exists(source_x64):
-      copy_runtime_impl(os.path.join(out_release_x64, pgo_runtime_dll),
-                        source_x64)
+      _CopyRuntimeImpl(os.path.join(out_release_x64, pgo_runtime_dll),
+                       source_x64)
+
+
+def CopyDlls(target_dir, configuration, cpu_arch):
+  """Copy the VS runtime DLLs into the requested directory as needed.
+
+  configuration is one of 'Debug' or 'Release'.
+  cpu_arch is one of 'x86' or 'x64'.
+
+  The debug configuration gets both the debug and release DLLs; the
+  release config only the latter.
+  """
+  vs2013_runtime_dll_dirs = SetEnvironmentAndGetRuntimeDllDirs()
+  if not vs2013_runtime_dll_dirs:
+    return
+
+  x64_runtime, x86_runtime = vs2013_runtime_dll_dirs
+  runtime_dir = x64_runtime if cpu_arch == 'x64' else x86_runtime
+  _CopyRuntime(target_dir, runtime_dir, 'msvc%s120.dll')
+  if configuration == 'Debug':
+    _CopyRuntime(target_dir, runtime_dir, 'msvc%s120d.dll')
 
 
 def _GetDesiredVsToolchainHashes():
   """Load a list of SHA1s corresponding to the toolchains that we want installed
   to build with."""
-  sha1path = os.path.join(script_dir,
-                          '..', 'buildtools', 'toolchain_vs2013.hash')
+  sha1path = os.path.join(script_dir, 'toolchain_vs2013.hash')
   with open(sha1path, 'rb') as f:
     return f.read().strip().splitlines()
 
@@ -188,13 +209,12 @@
   commands = {
       'update': Update,
       'get_toolchain_dir': GetToolchainDir,
-      # TODO(scottmg): Add copy_dlls for GN builds (gyp_chromium calls
-      # CopyVsRuntimeDlls via import, currently).
+      'copy_dlls': CopyDlls,
   }
   if len(sys.argv) < 2 or sys.argv[1] not in commands:
     print >>sys.stderr, 'Expected one of: %s' % ', '.join(commands)
     return 1
-  return commands[sys.argv[1]]()
+  return commands[sys.argv[1]](*sys.argv[2:])
 
 
 if __name__ == '__main__':
diff --git a/build/win_is_xtree_patched.py b/build/win_is_xtree_patched.py
new file mode 100755
index 0000000..5717322
--- /dev/null
+++ b/build/win_is_xtree_patched.py
@@ -0,0 +1,26 @@
+#!/usr/bin/env python
+# 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.
+
+"""Determines if the VS xtree header has been patched to disable C4702."""
+
+import os
+
+
+def IsPatched():
+  # TODO(scottmg): For now, just return if we're using the packaged toolchain
+  # script (because we know it's patched). Another case could be added here to
+  # query the active VS installation and actually check the contents of xtree.
+  # http://crbug.com/346399.
+  return os.environ.get('DEPOT_TOOLS_WIN_TOOLCHAIN', 1) == 0
+
+
+def DoMain(_):
+  """Hook to be called from gyp without starting a separate python
+  interpreter."""
+  return IsPatched()
+
+
+if __name__ == '__main__':
+  print DoMain([])
diff --git a/cc/BUILD.gn b/cc/BUILD.gn
index 3b3ed6d..ab3aab4 100644
--- a/cc/BUILD.gn
+++ b/cc/BUILD.gn
@@ -534,6 +534,7 @@
     "test/fake_picture_layer_impl.h",
     "test/fake_picture_layer_tiling_client.cc",
     "test/fake_picture_layer_tiling_client.h",
+    "test/fake_picture_pile.cc",
     "test/fake_picture_pile.h",
     "test/fake_picture_pile_impl.cc",
     "test/fake_picture_pile_impl.h",
diff --git a/cc/PRESUBMIT.py b/cc/PRESUBMIT.py
index 46c3a54..71c4ea1 100644
--- a/cc/PRESUBMIT.py
+++ b/cc/PRESUBMIT.py
@@ -11,7 +11,7 @@
 import re
 import string
 
-CC_SOURCE_FILES=(r'^cc/.*\.(cc|h)$',)
+CC_SOURCE_FILES=(r'^cc/.*\.(cc|h)$', r'^cc\\.*\.(cc|h)$')
 
 def CheckChangeLintsClean(input_api, output_api):
   input_api.cpplint._cpplint_state.ResetErrorCounts()  # reset global state
@@ -21,10 +21,6 @@
            input_api.AffectedSourceFiles(source_filter)]
   level = 1  # strict, but just warn
 
-  # TODO(danakj): Temporary, while the OVERRIDE and FINAL fixup is in progress.
-  # crbug.com/422353
-  input_api.cpplint._SetFilters('-readability/inheritance')
-
   for file_name in files:
     input_api.cpplint.ProcessFile(file_name, level)
 
diff --git a/cc/base/delayed_unique_notifier_unittest.cc b/cc/base/delayed_unique_notifier_unittest.cc
index 3e41d32..f30834e 100644
--- a/cc/base/delayed_unique_notifier_unittest.cc
+++ b/cc/base/delayed_unique_notifier_unittest.cc
@@ -35,7 +35,7 @@
  public:
   DelayedUniqueNotifierTest() : notification_count_(0) {}
 
-  virtual void SetUp() override {
+  void SetUp() override {
     notification_count_ = 0;
     task_runner_ = make_scoped_refptr(new base::TestSimpleTaskRunner);
   }
diff --git a/cc/base/unique_notifier_unittest.cc b/cc/base/unique_notifier_unittest.cc
index 0ba9892..dfab85e 100644
--- a/cc/base/unique_notifier_unittest.cc
+++ b/cc/base/unique_notifier_unittest.cc
@@ -17,7 +17,7 @@
  public:
   UniqueNotifierTest() : notification_count_(0) {}
 
-  virtual void SetUp() override { ResetNotificationCount(); }
+  void SetUp() override { ResetNotificationCount(); }
 
   void Notify() { ++notification_count_; }
 
diff --git a/cc/blink/web_external_bitmap_impl.h b/cc/blink/web_external_bitmap_impl.h
index 7dbfab3..2d2d8ce 100644
--- a/cc/blink/web_external_bitmap_impl.h
+++ b/cc/blink/web_external_bitmap_impl.h
@@ -28,9 +28,9 @@
   virtual ~WebExternalBitmapImpl();
 
   // blink::WebExternalBitmap implementation.
-  virtual blink::WebSize size() override;
-  virtual void setSize(blink::WebSize size) override;
-  virtual uint8* pixels() override;
+  blink::WebSize size() override;
+  void setSize(blink::WebSize size) override;
+  uint8* pixels() override;
 
   base::SharedMemory* shared_memory() { return shared_memory_.get(); }
 
diff --git a/cc/blink/web_layer_impl_fixed_bounds.h b/cc/blink/web_layer_impl_fixed_bounds.h
index 099feaf..edfd4bb 100644
--- a/cc/blink/web_layer_impl_fixed_bounds.h
+++ b/cc/blink/web_layer_impl_fixed_bounds.h
@@ -24,13 +24,13 @@
   virtual ~WebLayerImplFixedBounds();
 
   // WebLayerImpl overrides.
-  virtual void invalidateRect(const blink::WebRect& rect) override;
-  virtual void setTransformOrigin(
+  void invalidateRect(const blink::WebRect& rect) override;
+  void setTransformOrigin(
       const blink::WebFloatPoint3D& transform_origin) override;
-  virtual void setBounds(const blink::WebSize& bounds) override;
-  virtual blink::WebSize bounds() const override;
-  virtual void setTransform(const SkMatrix44& transform) override;
-  virtual SkMatrix44 transform() const override;
+  void setBounds(const blink::WebSize& bounds) override;
+  blink::WebSize bounds() const override;
+  void setTransform(const SkMatrix44& transform) override;
+  SkMatrix44 transform() const override;
 
   CC_BLINK_EXPORT void SetFixedBounds(gfx::Size bounds);
 
diff --git a/cc/cc_tests.gyp b/cc/cc_tests.gyp
index db58318..d4a031f 100644
--- a/cc/cc_tests.gyp
+++ b/cc/cc_tests.gyp
@@ -170,6 +170,7 @@
       'test/fake_picture_layer_impl.h',
       'test/fake_picture_layer_tiling_client.cc',
       'test/fake_picture_layer_tiling_client.h',
+      'test/fake_picture_pile.cc',
       'test/fake_picture_pile.h',
       'test/fake_picture_pile_impl.cc',
       'test/fake_picture_pile_impl.h',
diff --git a/cc/debug/micro_benchmark_controller_unittest.cc b/cc/debug/micro_benchmark_controller_unittest.cc
index a5683c4..31494ac 100644
--- a/cc/debug/micro_benchmark_controller_unittest.cc
+++ b/cc/debug/micro_benchmark_controller_unittest.cc
@@ -21,7 +21,7 @@
   MicroBenchmarkControllerTest()
       : layer_tree_host_client_(FakeLayerTreeHostClient::DIRECT_3D) {}
 
-  virtual void SetUp() override {
+  void SetUp() override {
     impl_proxy_ = make_scoped_ptr(new FakeImplProxy);
     shared_bitmap_manager_.reset(new TestSharedBitmapManager());
     layer_tree_host_impl_ = make_scoped_ptr(new FakeLayerTreeHostImpl(
@@ -32,7 +32,7 @@
     layer_tree_host_->InitializeForTesting(scoped_ptr<Proxy>(new FakeProxy));
   }
 
-  virtual void TearDown() override {
+  void TearDown() override {
     layer_tree_host_impl_ = nullptr;
     layer_tree_host_ = nullptr;
     impl_proxy_ = nullptr;
diff --git a/cc/debug/rendering_stats.h b/cc/debug/rendering_stats.h
index 193454c..17ec668 100644
--- a/cc/debug/rendering_stats.h
+++ b/cc/debug/rendering_stats.h
@@ -6,6 +6,7 @@
 #define CC_DEBUG_RENDERING_STATS_H_
 
 #include <list>
+#include <vector>
 
 #include "base/basictypes.h"
 #include "base/debug/trace_event_argument.h"
diff --git a/cc/debug/ring_buffer.h b/cc/debug/ring_buffer.h
index 94d8459..f9a6749 100644
--- a/cc/debug/ring_buffer.h
+++ b/cc/debug/ring_buffer.h
@@ -12,9 +12,7 @@
 template<typename T, size_t kSize>
 class RingBuffer {
  public:
-  explicit RingBuffer()
-    : current_index_(0) {
-  }
+  RingBuffer() : current_index_(0) {}
 
   size_t BufferSize() const {
     return kSize;
diff --git a/cc/layers/delegated_frame_provider_unittest.cc b/cc/layers/delegated_frame_provider_unittest.cc
index 5ba92bf..454bf7d 100644
--- a/cc/layers/delegated_frame_provider_unittest.cc
+++ b/cc/layers/delegated_frame_provider_unittest.cc
@@ -62,12 +62,12 @@
                  false);
   }
 
-  virtual void SetUp() override {
+  void SetUp() override {
     resource_collection_ = new DelegatedFrameResourceCollection;
     resource_collection_->SetClient(this);
   }
 
-  virtual void TearDown() override { resource_collection_->SetClient(nullptr); }
+  void TearDown() override { resource_collection_->SetClient(nullptr); }
 
   void UnusedResourcesAreAvailable() override {
     resources_available_ = true;
diff --git a/cc/layers/delegated_frame_resource_collection_unittest.cc b/cc/layers/delegated_frame_resource_collection_unittest.cc
index 3e95823..f91fe63 100644
--- a/cc/layers/delegated_frame_resource_collection_unittest.cc
+++ b/cc/layers/delegated_frame_resource_collection_unittest.cc
@@ -21,9 +21,9 @@
  protected:
   DelegatedFrameResourceCollectionTest() : resources_available_(false) {}
 
-  virtual void SetUp() override { CreateResourceCollection(); }
+  void SetUp() override { CreateResourceCollection(); }
 
-  virtual void TearDown() override { DestroyResourceCollection(); }
+  void TearDown() override { DestroyResourceCollection(); }
 
   void CreateResourceCollection() {
     DCHECK(!resource_collection_.get());
diff --git a/cc/layers/layer_perftest.cc b/cc/layers/layer_perftest.cc
index f42e228..0b4c852 100644
--- a/cc/layers/layer_perftest.cc
+++ b/cc/layers/layer_perftest.cc
@@ -37,13 +37,13 @@
                kTimeCheckInterval) {}
 
  protected:
-  virtual void SetUp() override {
+  void SetUp() override {
     layer_tree_host_ = FakeLayerTreeHost::Create(&fake_client_);
     layer_tree_host_->InitializeSingleThreaded(
         &fake_client_, base::MessageLoopProxy::current(), nullptr);
   }
 
-  virtual void TearDown() override {
+  void TearDown() override {
     layer_tree_host_->SetRootLayer(nullptr);
     layer_tree_host_ = nullptr;
   }
diff --git a/cc/layers/layer_unittest.cc b/cc/layers/layer_unittest.cc
index 246a658..4dfe86a 100644
--- a/cc/layers/layer_unittest.cc
+++ b/cc/layers/layer_unittest.cc
@@ -64,11 +64,11 @@
         fake_client_(FakeLayerTreeHostClient::DIRECT_3D) {}
 
  protected:
-  virtual void SetUp() override {
+  void SetUp() override {
     layer_tree_host_.reset(new StrictMock<MockLayerTreeHost>(&fake_client_));
   }
 
-  virtual void TearDown() override {
+  void TearDown() override {
     Mock::VerifyAndClearExpectations(layer_tree_host_.get());
     EXPECT_CALL(*layer_tree_host_, SetNeedsFullTreeSync()).Times(AnyNumber());
     parent_ = nullptr;
diff --git a/cc/layers/layer_utils.h b/cc/layers/layer_utils.h
index 396f070..bef37f4 100644
--- a/cc/layers/layer_utils.h
+++ b/cc/layers/layer_utils.h
@@ -8,21 +8,21 @@
 #include "cc/base/cc_export.h"
 
 namespace gfx {
-  class BoxF;
+class BoxF;
 }  // namespace gfx
 
 namespace cc {
-  class LayerImpl;
+class LayerImpl;
 
-  class CC_EXPORT LayerUtils {
-   public:
-    // Computes a box in screen space that should entirely contain the layer's
-    // bounds through the entirety of the layer's current animation. Returns
-    // true and sets |out| to the inflation if there are animations that can
-    // inflate bounds in the path to the root layer and that it was able to
-    // inflate correctly. Returns false otherwise.
-    static bool GetAnimationBounds(const LayerImpl& layer, gfx::BoxF* out);
-  };
+class CC_EXPORT LayerUtils {
+ public:
+  // Computes a box in screen space that should entirely contain the layer's
+  // bounds through the entirety of the layer's current animation. Returns
+  // true and sets |out| to the inflation if there are animations that can
+  // inflate bounds in the path to the root layer and that it was able to
+  // inflate correctly. Returns false otherwise.
+  static bool GetAnimationBounds(const LayerImpl& layer, gfx::BoxF* out);
+};
 
 }  // namespace cc
 
diff --git a/cc/layers/layer_utils_unittest.cc b/cc/layers/layer_utils_unittest.cc
index 1eb1986..5764bc6 100644
--- a/cc/layers/layer_utils_unittest.cc
+++ b/cc/layers/layer_utils_unittest.cc
@@ -25,7 +25,7 @@
  public:
   LayerUtilsGetAnimationBoundsTest()
       : host_impl_(&proxy_, &shared_bitmap_manager_),
-        root_(CreateThreeNodeTree(host_impl_)),
+        root_(CreateThreeNodeTree(&host_impl_)),
         parent_(root_->children()[0]),
         child_(parent_->children()[0]) {}
 
@@ -35,11 +35,11 @@
 
  private:
   static scoped_ptr<LayerImpl> CreateThreeNodeTree(
-      LayerTreeHostImpl& host_impl) {
-    scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl.active_tree(), 1);
-    root->AddChild(LayerImpl::Create(host_impl.active_tree(), 2));
-    root->children()[0]
-        ->AddChild(LayerImpl::Create(host_impl.active_tree(), 3));
+      LayerTreeHostImpl* host_impl) {
+    scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl->active_tree(), 1);
+    root->AddChild(LayerImpl::Create(host_impl->active_tree(), 2));
+    root->children()[0]->AddChild(
+        LayerImpl::Create(host_impl->active_tree(), 3));
     return root.Pass();
   }
 
diff --git a/cc/layers/nine_patch_layer_impl.cc b/cc/layers/nine_patch_layer_impl.cc
index 1c76d11..0dd2b6f 100644
--- a/cc/layers/nine_patch_layer_impl.cc
+++ b/cc/layers/nine_patch_layer_impl.cc
@@ -207,14 +207,14 @@
                        uv_top.width(),
                        uv_left.height());
 
-  // Nothing is opaque here.
-  // TODO(danakj): Should we look at the SkBitmaps to determine opaqueness?
   gfx::Rect opaque_rect;
   gfx::Rect visible_rect;
   const float vertex_opacity[] = {1.0f, 1.0f, 1.0f, 1.0f};
+  const bool opaque = layer_tree_impl()->IsUIResourceOpaque(ui_resource_id_);
 
   visible_rect =
       occlusion_in_content_space.GetUnoccludedContentRect(layer_top_left);
+  opaque_rect = opaque ? visible_rect : gfx::Rect();
   if (!visible_rect.IsEmpty()) {
     TextureDrawQuad* quad =
         render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
@@ -233,6 +233,7 @@
 
   visible_rect =
       occlusion_in_content_space.GetUnoccludedContentRect(layer_top_right);
+  opaque_rect = opaque ? visible_rect : gfx::Rect();
   if (!visible_rect.IsEmpty()) {
     TextureDrawQuad* quad =
         render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
@@ -251,6 +252,7 @@
 
   visible_rect =
       occlusion_in_content_space.GetUnoccludedContentRect(layer_bottom_left);
+  opaque_rect = opaque ? visible_rect : gfx::Rect();
   if (!visible_rect.IsEmpty()) {
     TextureDrawQuad* quad =
         render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
@@ -269,6 +271,7 @@
 
   visible_rect =
       occlusion_in_content_space.GetUnoccludedContentRect(layer_bottom_right);
+  opaque_rect = opaque ? visible_rect : gfx::Rect();
   if (!visible_rect.IsEmpty()) {
     TextureDrawQuad* quad =
         render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
@@ -286,6 +289,7 @@
   }
 
   visible_rect = occlusion_in_content_space.GetUnoccludedContentRect(layer_top);
+  opaque_rect = opaque ? visible_rect : gfx::Rect();
   if (!visible_rect.IsEmpty()) {
     TextureDrawQuad* quad =
         render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
@@ -304,6 +308,7 @@
 
   visible_rect =
       occlusion_in_content_space.GetUnoccludedContentRect(layer_left);
+  opaque_rect = opaque ? visible_rect : gfx::Rect();
   if (!visible_rect.IsEmpty()) {
     TextureDrawQuad* quad =
         render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
@@ -322,6 +327,7 @@
 
   visible_rect =
       occlusion_in_content_space.GetUnoccludedContentRect(layer_right);
+  opaque_rect = opaque ? visible_rect : gfx::Rect();
   if (!visible_rect.IsEmpty()) {
     TextureDrawQuad* quad =
         render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
@@ -340,6 +346,7 @@
 
   visible_rect =
       occlusion_in_content_space.GetUnoccludedContentRect(layer_bottom);
+  opaque_rect = opaque ? visible_rect : gfx::Rect();
   if (!visible_rect.IsEmpty()) {
     TextureDrawQuad* quad =
         render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
@@ -359,6 +366,7 @@
   if (fill_center_) {
     visible_rect =
         occlusion_in_content_space.GetUnoccludedContentRect(layer_center);
+    opaque_rect = opaque ? visible_rect : gfx::Rect();
     if (!visible_rect.IsEmpty()) {
       TextureDrawQuad* quad =
           render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
diff --git a/cc/layers/nine_patch_layer_impl_unittest.cc b/cc/layers/nine_patch_layer_impl_unittest.cc
index 695d827..f6262d3 100644
--- a/cc/layers/nine_patch_layer_impl_unittest.cc
+++ b/cc/layers/nine_patch_layer_impl_unittest.cc
@@ -271,5 +271,70 @@
   }
 }
 
+TEST(NinePatchLayerImplTest, OpaqueRect) {
+  gfx::Size layer_size(1000, 1000);
+  gfx::Size viewport_size(1000, 1000);
+
+  LayerTestCommon::LayerImplTest impl;
+
+  SkBitmap sk_bitmap_opaque;
+  sk_bitmap_opaque.allocN32Pixels(10, 10);
+  sk_bitmap_opaque.setImmutable();
+  sk_bitmap_opaque.setAlphaType(kOpaque_SkAlphaType);
+
+  UIResourceId uid_opaque = 6;
+  UIResourceBitmap bitmap_opaque(sk_bitmap_opaque);
+  impl.host_impl()->CreateUIResource(uid_opaque, bitmap_opaque);
+
+  SkBitmap sk_bitmap_alpha;
+  sk_bitmap_alpha.allocN32Pixels(10, 10);
+  sk_bitmap_alpha.setImmutable();
+  sk_bitmap_alpha.setAlphaType(kUnpremul_SkAlphaType);
+
+  UIResourceId uid_alpha = 7;
+  UIResourceBitmap bitmap_alpha(sk_bitmap_alpha);
+
+  impl.host_impl()->CreateUIResource(uid_alpha, bitmap_alpha);
+
+  NinePatchLayerImpl *nine_patch_layer_impl =
+      impl.AddChildToRoot<NinePatchLayerImpl>();
+  nine_patch_layer_impl->SetBounds(layer_size);
+  nine_patch_layer_impl->SetContentBounds(layer_size);
+  nine_patch_layer_impl->SetDrawsContent(true);
+
+  impl.CalcDrawProps(viewport_size);
+
+  {
+    SCOPED_TRACE("Use opaque image");
+
+    nine_patch_layer_impl->SetUIResourceId(uid_opaque);
+    nine_patch_layer_impl->SetImageBounds(gfx::Size(10, 10));
+
+    gfx::Rect aperture = gfx::Rect(3, 3, 4, 4);
+    gfx::Rect border = gfx::Rect(300, 300, 400, 400);
+    nine_patch_layer_impl->SetLayout(aperture, border, true);
+
+    impl.AppendQuadsWithOcclusion(nine_patch_layer_impl, gfx::Rect());
+
+    const QuadList &quad_list = impl.quad_list();
+    for (QuadList::ConstBackToFrontIterator it = quad_list.BackToFrontBegin();
+         it != quad_list.BackToFrontEnd(); ++it)
+      EXPECT_FALSE(it->ShouldDrawWithBlending());
+  }
+
+  {
+    SCOPED_TRACE("Use tranparent image");
+
+    nine_patch_layer_impl->SetUIResourceId(uid_alpha);
+
+    impl.AppendQuadsWithOcclusion(nine_patch_layer_impl, gfx::Rect());
+
+    const QuadList &quad_list = impl.quad_list();
+    for (QuadList::ConstBackToFrontIterator it = quad_list.BackToFrontBegin();
+         it != quad_list.BackToFrontEnd(); ++it)
+      EXPECT_TRUE(it->ShouldDrawWithBlending());
+  }
+}
+
 }  // namespace
 }  // namespace cc
diff --git a/cc/layers/picture_layer.cc b/cc/layers/picture_layer.cc
index 5d45cae..dbfa63c 100644
--- a/cc/layers/picture_layer.cc
+++ b/cc/layers/picture_layer.cc
@@ -26,6 +26,12 @@
       can_use_lcd_text_last_frame_(can_use_lcd_text()) {
 }
 
+PictureLayer::PictureLayer(ContentLayerClient* client,
+                           scoped_ptr<RecordingSource> source)
+    : PictureLayer(client) {
+  recording_source_ = source.Pass();
+}
+
 PictureLayer::~PictureLayer() {
 }
 
diff --git a/cc/layers/picture_layer.h b/cc/layers/picture_layer.h
index 2969ee1..ebd6427 100644
--- a/cc/layers/picture_layer.h
+++ b/cc/layers/picture_layer.h
@@ -45,6 +45,8 @@
 
  protected:
   explicit PictureLayer(ContentLayerClient* client);
+  // Allow tests to inject a recording source.
+  PictureLayer(ContentLayerClient* client, scoped_ptr<RecordingSource> source);
   ~PictureLayer() override;
 
   bool HasDrawableContent() const override;
diff --git a/cc/layers/picture_layer_impl_perftest.cc b/cc/layers/picture_layer_impl_perftest.cc
index 7f1ce85..1f98a68 100644
--- a/cc/layers/picture_layer_impl_perftest.cc
+++ b/cc/layers/picture_layer_impl_perftest.cc
@@ -45,7 +45,7 @@
                base::TimeDelta::FromMilliseconds(kTimeLimitMillis),
                kTimeCheckInterval) {}
 
-  virtual void SetUp() override {
+  void SetUp() override {
     host_impl_.InitializeRenderer(FakeOutputSurface::Create3d());
   }
 
diff --git a/cc/layers/picture_layer_impl_unittest.cc b/cc/layers/picture_layer_impl_unittest.cc
index a75feb0..bd0585e 100644
--- a/cc/layers/picture_layer_impl_unittest.cc
+++ b/cc/layers/picture_layer_impl_unittest.cc
@@ -71,9 +71,7 @@
   virtual ~PictureLayerImplTest() {
   }
 
-  virtual void SetUp() override {
-    InitializeRenderer();
-  }
+  void SetUp() override { InitializeRenderer(); }
 
   virtual void InitializeRenderer() {
     host_impl_.InitializeRenderer(FakeOutputSurface::Create3d());
@@ -2474,7 +2472,7 @@
         delegated_rendering));
   }
 
-  virtual void SetUp() override {
+  void SetUp() override {
     PictureLayerImplTest::SetUp();
 
     // Create some default active and pending trees.
diff --git a/cc/layers/surface_layer_unittest.cc b/cc/layers/surface_layer_unittest.cc
index 73415c0..436eadc 100644
--- a/cc/layers/surface_layer_unittest.cc
+++ b/cc/layers/surface_layer_unittest.cc
@@ -2,6 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <set>
+#include <vector>
+
 #include "base/message_loop/message_loop_proxy.h"
 #include "cc/layers/solid_color_layer.h"
 #include "cc/layers/surface_layer.h"
diff --git a/cc/layers/tiled_layer_unittest.cc b/cc/layers/tiled_layer_unittest.cc
index 7433a14..908d428 100644
--- a/cc/layers/tiled_layer_unittest.cc
+++ b/cc/layers/tiled_layer_unittest.cc
@@ -103,7 +103,7 @@
     settings_.layer_transforms_should_scale_layer_contents = true;
   }
 
-  virtual void SetUp() {
+  void SetUp() override {
     impl_thread_.Start();
     shared_bitmap_manager_.reset(new TestSharedBitmapManager());
     layer_tree_host_ = SynchronousOutputSurfaceLayerTreeHost::Create(
diff --git a/cc/output/geometry_binding.cc b/cc/output/geometry_binding.cc
index b8c9759..054a962 100644
--- a/cc/output/geometry_binding.cc
+++ b/cc/output/geometry_binding.cc
@@ -26,11 +26,9 @@
     uint16 data[6];
   };
 
-  COMPILE_ASSERT(sizeof(Quad) == 24 * sizeof(float),  // NOLINT(runtime/sizeof)
+  COMPILE_ASSERT(sizeof(Quad) == 24 * sizeof(float), struct_is_densely_packed);
+  COMPILE_ASSERT(sizeof(QuadIndex) == 6 * sizeof(uint16_t),
                  struct_is_densely_packed);
-  COMPILE_ASSERT(
-      sizeof(QuadIndex) == 6 * sizeof(uint16_t),  // NOLINT(runtime/sizeof)
-      struct_is_densely_packed);
 
   Quad quad_list[8];
   QuadIndex quad_index_list[8];
@@ -79,33 +77,17 @@
   // "const GLvoid*" even though it is actually an offset into the buffer
   // object's data store and not a pointer to the client's address space.
   const void* offsets[3] = {
-      0, reinterpret_cast<const void*>(
-             3 * sizeof(float)),  // NOLINT(runtime/sizeof)
-      reinterpret_cast<const void*>(5 *
-                                    sizeof(float)),  // NOLINT(runtime/sizeof)
+      0,
+      reinterpret_cast<const void*>(3 * sizeof(float)),
+      reinterpret_cast<const void*>(5 * sizeof(float)),
   };
 
-  GLC(gl_,
-      gl_->VertexAttribPointer(PositionAttribLocation(),
-                               3,
-                               GL_FLOAT,
-                               false,
-                               6 * sizeof(float),  // NOLINT(runtime/sizeof)
-                               offsets[0]));
-  GLC(gl_,
-      gl_->VertexAttribPointer(TexCoordAttribLocation(),
-                               2,
-                               GL_FLOAT,
-                               false,
-                               6 * sizeof(float),  // NOLINT(runtime/sizeof)
-                               offsets[1]));
-  GLC(gl_,
-      gl_->VertexAttribPointer(TriangleIndexAttribLocation(),
-                               1,
-                               GL_FLOAT,
-                               false,
-                               6 * sizeof(float),  // NOLINT(runtime/sizeof)
-                               offsets[2]));
+  GLC(gl_, gl_->VertexAttribPointer(PositionAttribLocation(), 3, GL_FLOAT,
+                                    false, 6 * sizeof(float), offsets[0]));
+  GLC(gl_, gl_->VertexAttribPointer(TexCoordAttribLocation(), 2, GL_FLOAT,
+                                    false, 6 * sizeof(float), offsets[1]));
+  GLC(gl_, gl_->VertexAttribPointer(TriangleIndexAttribLocation(), 1, GL_FLOAT,
+                                    false, 6 * sizeof(float), offsets[2]));
   GLC(gl_, gl_->EnableVertexAttribArray(PositionAttribLocation()));
   GLC(gl_, gl_->EnableVertexAttribArray(TexCoordAttribLocation()));
   GLC(gl_, gl_->EnableVertexAttribArray(TriangleIndexAttribLocation()));
diff --git a/cc/output/overlay_unittest.cc b/cc/output/overlay_unittest.cc
index 99192c8..a3a297b 100644
--- a/cc/output/overlay_unittest.cc
+++ b/cc/output/overlay_unittest.cc
@@ -539,7 +539,7 @@
 
   using GLRenderer::BeginDrawingFrame;
 
-  virtual void FinishDrawingFrame(DrawingFrame* frame) override {
+  void FinishDrawingFrame(DrawingFrame* frame) override {
     GLRenderer::FinishDrawingFrame(frame);
 
     if (!expect_overlays_) {
diff --git a/cc/quads/list_container_unittest.cc b/cc/quads/list_container_unittest.cc
index 3ef677c..d41d8bd 100644
--- a/cc/quads/list_container_unittest.cc
+++ b/cc/quads/list_container_unittest.cc
@@ -56,10 +56,9 @@
 
 class MockDrawQuad : public DrawQuad {
  public:
-  virtual ~MockDrawQuad() { Destruct(); }
-  virtual void IterateResources(
-      const ResourceIteratorCallback& callback) override {}
-  virtual void ExtendValue(base::debug::TracedValue* value) const override {}
+  ~MockDrawQuad() override { Destruct(); }
+  void IterateResources(const ResourceIteratorCallback& callback) override {}
+  void ExtendValue(base::debug::TracedValue* value) const override {}
   MOCK_METHOD0(Destruct, void());
 };
 
diff --git a/cc/resources/picture_layer_tiling_perftest.cc b/cc/resources/picture_layer_tiling_perftest.cc
index 0d1443e..43ec6fe 100644
--- a/cc/resources/picture_layer_tiling_perftest.cc
+++ b/cc/resources/picture_layer_tiling_perftest.cc
@@ -43,7 +43,7 @@
                                                   1).Pass();
   }
 
-  virtual void SetUp() override {
+  void SetUp() override {
     picture_layer_tiling_client_.SetTileSize(gfx::Size(256, 256));
     picture_layer_tiling_client_.set_max_tiles_for_interest_area(250);
     picture_layer_tiling_client_.set_tree(PENDING_TREE);
@@ -52,9 +52,7 @@
     picture_layer_tiling_->CreateAllTilesForTesting();
   }
 
-  virtual void TearDown() override {
-    picture_layer_tiling_.reset(NULL);
-  }
+  void TearDown() override { picture_layer_tiling_.reset(NULL); }
 
   void RunInvalidateTest(const std::string& test_name, const Region& region) {
     timer_.Reset();
diff --git a/cc/resources/picture_pile.h b/cc/resources/picture_pile.h
index ffd9b52..1f41d01 100644
--- a/cc/resources/picture_pile.h
+++ b/cc/resources/picture_pile.h
@@ -6,7 +6,9 @@
 #define CC_RESOURCES_PICTURE_PILE_H_
 
 #include <bitset>
+#include <utility>
 
+#include "base/containers/hash_tables.h"
 #include "base/memory/ref_counted.h"
 #include "cc/base/tiling_data.h"
 #include "cc/resources/recording_source.h"
diff --git a/cc/resources/picture_pile_impl.h b/cc/resources/picture_pile_impl.h
index 6986db4..9f5b5f6 100644
--- a/cc/resources/picture_pile_impl.h
+++ b/cc/resources/picture_pile_impl.h
@@ -17,7 +17,14 @@
 #include "cc/resources/raster_source.h"
 #include "skia/ext/analysis_canvas.h"
 #include "skia/ext/refptr.h"
-#include "third_party/skia/include/core/SkPicture.h"
+
+class SkCanvas;
+class SkPicture;
+class SkPixelRef;
+
+namespace gfx {
+class Rect;
+}
 
 namespace cc {
 
diff --git a/cc/resources/picture_pile_unittest.cc b/cc/resources/picture_pile_unittest.cc
index 25e0d12..bfb4692 100644
--- a/cc/resources/picture_pile_unittest.cc
+++ b/cc/resources/picture_pile_unittest.cc
@@ -67,7 +67,7 @@
 
 class PicturePileTest : public PicturePileTestBase, public testing::Test {
  public:
-  virtual void SetUp() override { InitializeData(); }
+  void SetUp() override { InitializeData(); }
 };
 
 TEST_F(PicturePileTest, InvalidationOnTileBorderOutsideInterestRect) {
@@ -531,7 +531,7 @@
 class PicturePileResizeCornerTest : public PicturePileTestBase,
                                     public testing::TestWithParam<Corner> {
  protected:
-  virtual void SetUp() override { InitializeData(); }
+  void SetUp() override { InitializeData(); }
 
   static gfx::Rect CornerSinglePixelRect(Corner corner, const gfx::Size& s) {
     switch (corner) {
diff --git a/cc/resources/raster_worker_pool_perftest.cc b/cc/resources/raster_worker_pool_perftest.cc
index fdec054..d86155a 100644
--- a/cc/resources/raster_worker_pool_perftest.cc
+++ b/cc/resources/raster_worker_pool_perftest.cc
@@ -228,7 +228,7 @@
       public RasterizerClient {
  public:
   // Overridden from testing::Test:
-  virtual void SetUp() override {
+  void SetUp() override {
     switch (GetParam()) {
       case RASTER_WORKER_POOL_TYPE_PIXEL_BUFFER:
         Create3dOutputSurfaceAndResourceProvider();
@@ -277,7 +277,7 @@
     DCHECK(raster_worker_pool_);
     raster_worker_pool_->AsRasterizer()->SetClient(this);
   }
-  virtual void TearDown() override {
+  void TearDown() override {
     raster_worker_pool_->AsRasterizer()->Shutdown();
     raster_worker_pool_->AsRasterizer()->CheckForCompletedTasks();
   }
@@ -485,7 +485,7 @@
                                        public testing::Test {
  public:
   // Overridden from testing::Test:
-  virtual void SetUp() override {
+  void SetUp() override {
     output_surface_ = FakeOutputSurface::Create3d(context_provider_).Pass();
     CHECK(output_surface_->BindToClient(&output_surface_client_));
     resource_provider_ =
diff --git a/cc/resources/raster_worker_pool_unittest.cc b/cc/resources/raster_worker_pool_unittest.cc
index 775acda..0518f64 100644
--- a/cc/resources/raster_worker_pool_unittest.cc
+++ b/cc/resources/raster_worker_pool_unittest.cc
@@ -129,7 +129,7 @@
         timed_out_(false) {}
 
   // Overridden from testing::Test:
-  virtual void SetUp() override {
+  void SetUp() override {
     switch (GetParam()) {
       case RASTER_WORKER_POOL_TYPE_PIXEL_BUFFER:
         Create3dOutputSurfaceAndResourceProvider();
@@ -179,7 +179,7 @@
     raster_worker_pool_->AsRasterizer()->SetClient(this);
   }
 
-  virtual void TearDown() override {
+  void TearDown() override {
     raster_worker_pool_->AsRasterizer()->Shutdown();
     raster_worker_pool_->AsRasterizer()->CheckForCompletedTasks();
   }
diff --git a/cc/resources/recording_source.h b/cc/resources/recording_source.h
index cbbeb70..d2b0893 100644
--- a/cc/resources/recording_source.h
+++ b/cc/resources/recording_source.h
@@ -50,6 +50,7 @@
   virtual void SetUnsuitableForGpuRasterizationForTesting() = 0;
   virtual SkTileGridFactory::TileGridInfo GetTileGridInfoForTesting() const = 0;
 };
-}
+
+}  // namespace cc
 
 #endif  // CC_RESOURCES_RECORDING_SOURCE_H_
diff --git a/cc/resources/resource_provider_unittest.cc b/cc/resources/resource_provider_unittest.cc
index e507ad6..d8bfe4c 100644
--- a/cc/resources/resource_provider_unittest.cc
+++ b/cc/resources/resource_provider_unittest.cc
@@ -103,11 +103,11 @@
 
   // Force all textures to be consecutive numbers starting at "1",
   // so we easily can test for them.
-  virtual GLuint NextTextureId() override {
+  GLuint NextTextureId() override {
     base::AutoLock lock(namespace_->lock);
     return namespace_->next_texture_id++;
   }
-  virtual void RetireTextureId(GLuint) override {}
+  void RetireTextureId(GLuint) override {}
 };
 
 // Shared data between multiple ResourceProviderContext. This contains mailbox
diff --git a/cc/resources/scoped_gpu_raster.h b/cc/resources/scoped_gpu_raster.h
index a322ccb..e70ebd0 100644
--- a/cc/resources/scoped_gpu_raster.h
+++ b/cc/resources/scoped_gpu_raster.h
@@ -17,7 +17,7 @@
 // GL resources while an instance of this class is alive.
 class CC_EXPORT ScopedGpuRaster {
  public:
-  ScopedGpuRaster(ContextProvider* context_provider);
+  explicit ScopedGpuRaster(ContextProvider* context_provider);
   ~ScopedGpuRaster();
 
  private:
diff --git a/cc/resources/task_graph_runner_perftest.cc b/cc/resources/task_graph_runner_perftest.cc
index 7809e58..51dad74 100644
--- a/cc/resources/task_graph_runner_perftest.cc
+++ b/cc/resources/task_graph_runner_perftest.cc
@@ -45,11 +45,11 @@
                kTimeCheckInterval) {}
 
   // Overridden from testing::Test:
-  virtual void SetUp() override {
+  void SetUp() override {
     task_graph_runner_ = make_scoped_ptr(new TaskGraphRunner);
     namespace_token_ = task_graph_runner_->GetNamespaceToken();
   }
-  virtual void TearDown() override { task_graph_runner_ = nullptr; }
+  void TearDown() override { task_graph_runner_ = nullptr; }
 
   void AfterTest(const std::string& test_name) {
     // Format matches chrome/test/perf/perf_test.h:PrintResult
diff --git a/cc/resources/task_graph_runner_unittest.cc b/cc/resources/task_graph_runner_unittest.cc
index ad23b66..afc369d 100644
--- a/cc/resources/task_graph_runner_unittest.cc
+++ b/cc/resources/task_graph_runner_unittest.cc
@@ -167,7 +167,7 @@
                             public base::DelegateSimpleThread::Delegate {
  public:
   // Overridden from testing::Test:
-  virtual void SetUp() override {
+  void SetUp() override {
     const size_t num_threads = GetParam();
     while (workers_.size() < num_threads) {
       scoped_ptr<base::DelegateSimpleThread> worker =
@@ -179,7 +179,7 @@
     for (int i = 0; i < kNamespaceCount; ++i)
       namespace_token_[i] = task_graph_runner_->GetNamespaceToken();
   }
-  virtual void TearDown() override {
+  void TearDown() override {
     task_graph_runner_->Shutdown();
     while (workers_.size()) {
       scoped_ptr<base::DelegateSimpleThread> worker = workers_.take_front();
@@ -285,14 +285,14 @@
       public base::DelegateSimpleThread::Delegate {
  public:
   // Overridden from testing::Test:
-  virtual void SetUp() override {
+  void SetUp() override {
     worker_.reset(new base::DelegateSimpleThread(this, "TestWorker"));
     worker_->Start();
 
     for (int i = 0; i < kNamespaceCount; ++i)
       namespace_token_[i] = task_graph_runner_->GetNamespaceToken();
   }
-  virtual void TearDown() override {
+  void TearDown() override {
     task_graph_runner_->Shutdown();
     worker_->Join();
   }
diff --git a/cc/resources/tile_manager.cc b/cc/resources/tile_manager.cc
index 1c7d4ca..d83b824 100644
--- a/cc/resources/tile_manager.cc
+++ b/cc/resources/tile_manager.cc
@@ -233,7 +233,6 @@
       scheduled_raster_task_limit_(scheduled_raster_task_limit),
       all_tiles_that_need_to_be_rasterized_are_scheduled_(true),
       rendering_stats_instrumentation_(rendering_stats_instrumentation),
-      did_initialize_visible_tile_(false),
       did_check_for_completed_tasks_since_last_schedule_tasks_(true),
       did_oom_on_last_assign_(false),
       ready_to_activate_check_notifier_(
@@ -433,7 +432,7 @@
                         resource_pool_->acquired_memory_usage_bytes());
 }
 
-bool TileManager::UpdateVisibleTiles() {
+void TileManager::UpdateVisibleTiles() {
   TRACE_EVENT0("cc", "TileManager::UpdateVisibleTiles");
 
   rasterizer_->CheckForCompletedTasks();
@@ -446,10 +445,6 @@
       "stats",
       RasterTaskCompletionStatsAsValue(update_visible_tiles_stats_));
   update_visible_tiles_stats_ = RasterTaskCompletionStats();
-
-  bool did_initialize_visible_tile = did_initialize_visible_tile_;
-  did_initialize_visible_tile_ = false;
-  return did_initialize_visible_tile;
 }
 
 scoped_refptr<base::debug::ConvertableToTraceFormat>
@@ -828,9 +823,6 @@
     mts.draw_info.resource_ = resource.Pass();
   }
 
-  if (tile->priority(ACTIVE_TREE).distance_to_visible == 0.f)
-    did_initialize_visible_tile_ = true;
-
   client_->NotifyTileStateChanged(tile);
 }
 
diff --git a/cc/resources/tile_manager.h b/cc/resources/tile_manager.h
index 92821e0..e94fb7c 100644
--- a/cc/resources/tile_manager.h
+++ b/cc/resources/tile_manager.h
@@ -108,8 +108,7 @@
 
   void ManageTiles(const GlobalStateThatImpactsTilePriority& state);
 
-  // Returns true when visible tiles have been initialized.
-  bool UpdateVisibleTiles();
+  void UpdateVisibleTiles();
 
   scoped_refptr<Tile> CreateTile(RasterSource* raster_source,
                                  const gfx::Size& tile_size,
@@ -254,7 +253,6 @@
 
   RenderingStatsInstrumentation* rendering_stats_instrumentation_;
 
-  bool did_initialize_visible_tile_;
   bool did_check_for_completed_tasks_since_last_schedule_tasks_;
   bool did_oom_on_last_assign_;
 
diff --git a/cc/resources/tile_manager_perftest.cc b/cc/resources/tile_manager_perftest.cc
index 7262926..7b096bd 100644
--- a/cc/resources/tile_manager_perftest.cc
+++ b/cc/resources/tile_manager_perftest.cc
@@ -111,7 +111,7 @@
     host_impl_.tile_manager()->SetGlobalStateForTesting(state);
   }
 
-  virtual void SetUp() override {
+  void SetUp() override {
     InitializeRenderer();
     SetTreePriority(SAME_PRIORITY_FOR_BOTH_TREES);
   }
diff --git a/cc/resources/tile_manager_unittest.cc b/cc/resources/tile_manager_unittest.cc
index a253672..b8aceb6 100644
--- a/cc/resources/tile_manager_unittest.cc
+++ b/cc/resources/tile_manager_unittest.cc
@@ -55,7 +55,7 @@
     host_impl_.tile_manager()->SetGlobalStateForTesting(state);
   }
 
-  virtual void SetUp() override {
+  void SetUp() override {
     InitializeRenderer();
     SetTreePriority(SAME_PRIORITY_FOR_BOTH_TREES);
   }
diff --git a/cc/scheduler/begin_frame_source_unittest.cc b/cc/scheduler/begin_frame_source_unittest.cc
index b741e35..a4b3d6e 100644
--- a/cc/scheduler/begin_frame_source_unittest.cc
+++ b/cc/scheduler/begin_frame_source_unittest.cc
@@ -312,7 +312,7 @@
   scoped_ptr<TestBackToBackBeginFrameSource> source_;
   scoped_ptr<MockBeginFrameObserver> obs_;
 
-  virtual void SetUp() override {
+  void SetUp() override {
     now_src_ = TestNowSource::Create(1000);
     task_runner_ =
         make_scoped_refptr(new OrderedSimpleTaskRunner(now_src_, false));
@@ -323,7 +323,7 @@
     source_->AddObserver(obs_.get());
   }
 
-  virtual void TearDown() override { obs_.reset(); }
+  void TearDown() override { obs_.reset(); }
 };
 
 const int64_t BackToBackBeginFrameSourceTest::kDeadline =
@@ -478,7 +478,7 @@
   scoped_ptr<TestSyntheticBeginFrameSource> source_;
   scoped_ptr<MockBeginFrameObserver> obs_;
 
-  virtual void SetUp() override {
+  void SetUp() override {
     now_src_ = TestNowSource::Create(1000);
     task_runner_ =
         make_scoped_refptr(new OrderedSimpleTaskRunner(now_src_, false));
@@ -488,7 +488,7 @@
     source_->AddObserver(obs_.get());
   }
 
-  virtual void TearDown() override { obs_.reset(); }
+  void TearDown() override { obs_.reset(); }
 };
 
 TEST_F(SyntheticBeginFrameSourceTest,
@@ -547,7 +547,7 @@
 // BeginFrameSourceMultiplexer testing -----------------------------------
 class BeginFrameSourceMultiplexerTest : public ::testing::Test {
  protected:
-  virtual void SetUp() override {
+  void SetUp() override {
     mux_ = BeginFrameSourceMultiplexer::Create();
 
     source1_store_ = make_scoped_ptr(new FakeBeginFrameSource());
@@ -559,7 +559,7 @@
     source3_ = source3_store_.get();
   }
 
-  virtual void TearDown() override {
+  void TearDown() override {
     // Make sure the mux is torn down before the sources.
     mux_.reset();
   }
diff --git a/cc/scheduler/scheduler.cc b/cc/scheduler/scheduler.cc
index 5c515b2..b190988 100644
--- a/cc/scheduler/scheduler.cc
+++ b/cc/scheduler/scheduler.cc
@@ -244,11 +244,6 @@
   }
 }
 
-void Scheduler::SetSwapUsedIncompleteTile(bool used_incomplete_tile) {
-  state_machine_.SetSwapUsedIncompleteTile(used_incomplete_tile);
-  ProcessScheduledActions();
-}
-
 void Scheduler::DidSwapBuffersComplete() {
   state_machine_.DidSwapBuffersComplete();
   ProcessScheduledActions();
@@ -477,8 +472,9 @@
                          "Scheduler::BeginRetroFrames all expired",
                          TRACE_EVENT_SCOPE_THREAD);
   } else {
-    BeginImplFrame(begin_retro_frame_args_.front());
+    BeginFrameArgs front = begin_retro_frame_args_.front();
     begin_retro_frame_args_.pop_front();
+    BeginImplFrame(front);
   }
 }
 
@@ -669,9 +665,6 @@
       case SchedulerStateMachine::ACTION_COMMIT:
         client_->ScheduledActionCommit();
         break;
-      case SchedulerStateMachine::ACTION_UPDATE_VISIBLE_TILES:
-        client_->ScheduledActionUpdateVisibleTiles();
-        break;
       case SchedulerStateMachine::ACTION_ACTIVATE_SYNC_TREE:
         client_->ScheduledActionActivateSyncTree();
         break;
diff --git a/cc/scheduler/scheduler.h b/cc/scheduler/scheduler.h
index 523c246..2a924f1 100644
--- a/cc/scheduler/scheduler.h
+++ b/cc/scheduler/scheduler.h
@@ -40,7 +40,6 @@
   virtual DrawResult ScheduledActionDrawAndSwapForced() = 0;
   virtual void ScheduledActionAnimate() = 0;
   virtual void ScheduledActionCommit() = 0;
-  virtual void ScheduledActionUpdateVisibleTiles() = 0;
   virtual void ScheduledActionActivateSyncTree() = 0;
   virtual void ScheduledActionBeginOutputSurfaceCreation() = 0;
   virtual void ScheduledActionManageTiles() = 0;
@@ -120,7 +119,6 @@
 
   void SetMaxSwapsPending(int max);
   void DidSwapBuffers();
-  void SetSwapUsedIncompleteTile(bool used_incomplete_tile);
   void DidSwapBuffersComplete();
 
   void SetImplLatencyTakesPriority(bool impl_latency_takes_priority);
diff --git a/cc/scheduler/scheduler_state_machine.cc b/cc/scheduler/scheduler_state_machine.cc
index 94016f3..82b13d7 100644
--- a/cc/scheduler/scheduler_state_machine.cc
+++ b/cc/scheduler/scheduler_state_machine.cc
@@ -26,7 +26,6 @@
       last_frame_number_swap_performed_(-1),
       last_frame_number_swap_requested_(-1),
       last_frame_number_begin_main_frame_sent_(-1),
-      last_frame_number_update_visible_tiles_was_called_(-1),
       manage_tiles_funnel_(0),
       consecutive_checkerboard_animations_(0),
       max_pending_swaps_(1),
@@ -34,7 +33,6 @@
       needs_redraw_(false),
       needs_animate_(false),
       needs_manage_tiles_(false),
-      swap_used_incomplete_tile_(false),
       needs_commit_(false),
       inside_poll_for_anticipated_draw_triggers_(false),
       visible_(false),
@@ -129,8 +127,6 @@
       return "ACTION_SEND_BEGIN_MAIN_FRAME";
     case ACTION_COMMIT:
       return "ACTION_COMMIT";
-    case ACTION_UPDATE_VISIBLE_TILES:
-      return "ACTION_UPDATE_VISIBLE_TILES";
     case ACTION_ACTIVATE_SYNC_TREE:
       return "ACTION_ACTIVATE_SYNC_TREE";
     case ACTION_DRAW_AND_SWAP_IF_POSSIBLE:
@@ -206,8 +202,6 @@
                     last_frame_number_swap_requested_);
   state->SetInteger("last_frame_number_begin_main_frame_sent",
                     last_frame_number_begin_main_frame_sent_);
-  state->SetInteger("last_frame_number_update_visible_tiles_was_called",
-                    last_frame_number_update_visible_tiles_was_called_);
 
   state->SetInteger("manage_tiles_funnel", manage_tiles_funnel_);
   state->SetInteger("consecutive_checkerboard_animations",
@@ -217,7 +211,6 @@
   state->SetBoolean("needs_redraw", needs_redraw_);
   state->SetBoolean("needs_animate_", needs_animate_);
   state->SetBoolean("needs_manage_tiles", needs_manage_tiles_);
-  state->SetBoolean("swap_used_incomplete_tile", swap_used_incomplete_tile_);
   state->SetBoolean("needs_commit", needs_commit_);
   state->SetBoolean("visible", visible_);
   state->SetBoolean("can_start", can_start_);
@@ -265,11 +258,6 @@
          last_frame_number_begin_main_frame_sent_;
 }
 
-bool SchedulerStateMachine::HasUpdatedVisibleTilesThisFrame() const {
-  return current_frame_number_ ==
-         last_frame_number_update_visible_tiles_was_called_;
-}
-
 bool SchedulerStateMachine::HasSwappedThisFrame() const {
   return current_frame_number_ == last_frame_number_swap_performed_;
 }
@@ -394,34 +382,6 @@
   return pending_tree_is_ready_for_activation_;
 }
 
-bool SchedulerStateMachine::ShouldUpdateVisibleTiles() const {
-  if (!settings_.impl_side_painting)
-    return false;
-  if (HasUpdatedVisibleTilesThisFrame())
-    return false;
-
-  // We don't want to update visible tiles right after drawing.
-  if (HasRequestedSwapThisFrame())
-    return false;
-
-  // There's no reason to check for tiles if we don't have an output surface.
-  if (!HasInitializedOutputSurface())
-    return false;
-
-  // We should not check for visible tiles until we've entered the deadline so
-  // we check as late as possible and give the tiles more time to initialize.
-  if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE)
-    return false;
-
-  // If the last swap drew with checkerboard or missing tiles, we should
-  // poll for any new visible tiles so we can be notified to draw again
-  // when there are.
-  if (swap_used_incomplete_tile_)
-    return true;
-
-  return false;
-}
-
 bool SchedulerStateMachine::ShouldAnimate() const {
   // If a commit occurred after our last call, we need to do animation again.
   if (HasAnimatedThisFrame() && !did_commit_after_animating_)
@@ -534,8 +494,6 @@
 }
 
 SchedulerStateMachine::Action SchedulerStateMachine::NextAction() const {
-  if (ShouldUpdateVisibleTiles())
-    return ACTION_UPDATE_VISIBLE_TILES;
   if (ShouldActivatePendingTree())
     return ACTION_ACTIVATE_SYNC_TREE;
   if (ShouldCommit())
@@ -564,11 +522,6 @@
     case ACTION_NONE:
       return;
 
-    case ACTION_UPDATE_VISIBLE_TILES:
-      last_frame_number_update_visible_tiles_was_called_ =
-          current_frame_number_;
-      return;
-
     case ACTION_ACTIVATE_SYNC_TREE:
       UpdateStateOnActivation();
       return;
@@ -767,12 +720,6 @@
   if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW)
     return true;
 
-  // We need to draw a more complete frame than we did the last BeginImplFrame,
-  // so request another BeginImplFrame in anticipation that we will have
-  // additional visible tiles.
-  if (swap_used_incomplete_tile_)
-    return true;
-
   return needs_animate_ || needs_redraw_;
 }
 
@@ -963,11 +910,6 @@
   last_frame_number_swap_performed_ = current_frame_number_;
 }
 
-void SchedulerStateMachine::SetSwapUsedIncompleteTile(
-    bool used_incomplete_tile) {
-  swap_used_incomplete_tile_ = used_incomplete_tile;
-}
-
 void SchedulerStateMachine::DidSwapBuffersComplete() {
   DCHECK_GT(pending_swaps_, 0);
   pending_swaps_--;
diff --git a/cc/scheduler/scheduler_state_machine.h b/cc/scheduler/scheduler_state_machine.h
index a63a683..489ece6 100644
--- a/cc/scheduler/scheduler_state_machine.h
+++ b/cc/scheduler/scheduler_state_machine.h
@@ -95,7 +95,6 @@
     ACTION_ANIMATE,
     ACTION_SEND_BEGIN_MAIN_FRAME,
     ACTION_COMMIT,
-    ACTION_UPDATE_VISIBLE_TILES,
     ACTION_ACTIVATE_SYNC_TREE,
     ACTION_DRAW_AND_SWAP_IF_POSSIBLE,
     ACTION_DRAW_AND_SWAP_FORCED,
@@ -260,7 +259,6 @@
   bool ShouldDrawForced() const;
   bool ShouldDraw() const;
   bool ShouldActivatePendingTree() const;
-  bool ShouldUpdateVisibleTiles() const;
   bool ShouldSendBeginMainFrame() const;
   bool ShouldCommit() const;
   bool ShouldManageTiles() const;
@@ -268,7 +266,6 @@
   void AdvanceCurrentFrameNumber();
   bool HasAnimatedThisFrame() const;
   bool HasSentBeginMainFrameThisFrame() const;
-  bool HasUpdatedVisibleTilesThisFrame() const;
   bool HasRequestedSwapThisFrame() const;
   bool HasSwappedThisFrame() const;
 
@@ -292,7 +289,6 @@
   int last_frame_number_swap_performed_;
   int last_frame_number_swap_requested_;
   int last_frame_number_begin_main_frame_sent_;
-  int last_frame_number_update_visible_tiles_was_called_;
 
   // manage_tiles_funnel_ is "filled" each time ManageTiles is called
   // and "drained" on each BeginImplFrame. If the funnel gets too full,
@@ -305,7 +301,6 @@
   bool needs_redraw_;
   bool needs_animate_;
   bool needs_manage_tiles_;
-  bool swap_used_incomplete_tile_;
   bool needs_commit_;
   bool inside_poll_for_anticipated_draw_triggers_;
   bool visible_;
diff --git a/cc/scheduler/scheduler_unittest.cc b/cc/scheduler/scheduler_unittest.cc
index 91900a2..7d61df3 100644
--- a/cc/scheduler/scheduler_unittest.cc
+++ b/cc/scheduler/scheduler_unittest.cc
@@ -88,8 +88,6 @@
 
   FakeSchedulerClient()
       : automatic_swap_ack_(true),
-        swap_contains_incomplete_tile_(false),
-        redraw_will_happen_if_update_visible_tiles_happens_(false),
         now_src_(TestNowSource::Create()),
         task_runner_(new OrderedSimpleTaskRunner(now_src_, true)),
         fake_external_begin_frame_source_(nullptr),
@@ -191,10 +189,6 @@
     return -1;
   }
 
-  void SetSwapContainsIncompleteTile(bool contain) {
-    swap_contains_incomplete_tile_ = contain;
-  }
-
   bool HasAction(const char* action) const {
     return ActionIndex(action) >= 0;
   }
@@ -208,9 +202,6 @@
   void SetAutomaticSwapAck(bool automatic_swap_ack) {
     automatic_swap_ack_ = automatic_swap_ack;
   }
-  void SetRedrawWillHappenIfUpdateVisibleTilesHappens(bool redraw) {
-    redraw_will_happen_if_update_visible_tiles_happens_ = redraw;
-  }
   // SchedulerClient implementation.
   void WillBeginImplFrame(const BeginFrameArgs& args) override {
     actions_.push_back("WillBeginImplFrame");
@@ -234,12 +225,6 @@
         draw_will_happen_ && swap_will_happen_if_draw_happens_;
     if (swap_will_happen) {
       scheduler_->DidSwapBuffers();
-      if (swap_contains_incomplete_tile_) {
-        scheduler_->SetSwapUsedIncompleteTile(true);
-        swap_contains_incomplete_tile_ = false;
-      } else {
-        scheduler_->SetSwapUsedIncompleteTile(false);
-      }
 
       if (automatic_swap_ack_)
         scheduler_->DidSwapBuffersComplete();
@@ -255,12 +240,6 @@
     actions_.push_back("ScheduledActionCommit");
     states_.push_back(scheduler_->AsValue());
   }
-  void ScheduledActionUpdateVisibleTiles() override {
-    actions_.push_back("ScheduledActionUpdateVisibleTiles");
-    states_.push_back(scheduler_->AsValue());
-    if (redraw_will_happen_if_update_visible_tiles_happens_)
-      scheduler_->SetNeedsRedraw();
-  }
   void ScheduledActionActivateSyncTree() override {
     actions_.push_back("ScheduledActionActivateSyncTree");
     states_.push_back(scheduler_->AsValue());
@@ -303,8 +282,6 @@
   bool automatic_swap_ack_;
   int num_draws_;
   bool log_anticipated_draw_time_change_;
-  bool swap_contains_incomplete_tile_;
-  bool redraw_will_happen_if_update_visible_tiles_happens_;
   base::TimeTicks posted_begin_impl_frame_deadline_;
   std::vector<const char*> actions_;
   std::vector<scoped_refptr<base::debug::ConvertableToTraceFormat>> states_;
@@ -1012,68 +989,6 @@
   scheduler->DidManageTiles();  // Corresponds to ScheduledActionManageTiles
 }
 
-TEST(SchedulerTest, ShouldUpdateVisibleTiles) {
-  FakeSchedulerClient client;
-  SchedulerSettings scheduler_settings;
-  scheduler_settings.impl_side_painting = true;
-  scheduler_settings.use_external_begin_frame_source = true;
-  TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
-  scheduler->SetCanStart();
-  scheduler->SetVisible(true);
-  scheduler->SetCanDraw(true);
-  InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
-
-  client.SetRedrawWillHappenIfUpdateVisibleTilesHappens(true);
-
-  // SetNeedsCommit should begin the frame.
-  client.Reset();
-  scheduler->SetNeedsCommit();
-  EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client);
-
-  client.Reset();
-  client.AdvanceFrame();
-  EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
-  EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
-  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
-
-  client.Reset();
-  scheduler->NotifyBeginMainFrameStarted();
-  scheduler->NotifyReadyToCommit();
-  EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
-
-  client.Reset();
-  scheduler->NotifyReadyToActivate();
-  EXPECT_SINGLE_ACTION("ScheduledActionActivateSyncTree", client);
-
-  client.Reset();
-  client.SetSwapContainsIncompleteTile(true);
-  client.task_runner().RunPendingTasks();  // Run posted deadline.
-  EXPECT_ACTION("ScheduledActionAnimate", client, 0, 2);
-  EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 1, 2);
-  EXPECT_FALSE(scheduler->RedrawPending());
-
-  client.Reset();
-  client.AdvanceFrame();
-  EXPECT_SINGLE_ACTION("WillBeginImplFrame", client);
-  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
-
-  client.Reset();
-  client.task_runner().RunPendingTasks();  // Run posted deadline.
-  EXPECT_ACTION("ScheduledActionUpdateVisibleTiles", client, 0, 3);
-  EXPECT_ACTION("ScheduledActionAnimate", client, 1, 3);
-  EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 2, 3);
-
-  client.Reset();
-  client.AdvanceFrame();
-  EXPECT_SINGLE_ACTION("WillBeginImplFrame", client);
-  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
-
-  // No more UpdateVisibleTiles().
-  client.Reset();
-  client.task_runner().RunPendingTasks();  // Run posted deadline.
-  EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(false)", client);
-}
-
 TEST(SchedulerTest, TriggerBeginFrameDeadlineEarly) {
   SchedulerClientNeedsManageTilesInDraw client;
   SchedulerSettings scheduler_settings;
diff --git a/cc/surfaces/display_client.h b/cc/surfaces/display_client.h
index b0f8f79..71ee434 100644
--- a/cc/surfaces/display_client.h
+++ b/cc/surfaces/display_client.h
@@ -25,6 +25,7 @@
  protected:
   virtual ~DisplayClient() {}
 };
-}
+
+}  // namespace cc
 
 #endif  // CC_SURFACES_DISPLAY_CLIENT_H_
diff --git a/cc/test/fake_layer_tree_host_impl_client.h b/cc/test/fake_layer_tree_host_impl_client.h
index 3c44994..ced02a6 100644
--- a/cc/test/fake_layer_tree_host_impl_client.h
+++ b/cc/test/fake_layer_tree_host_impl_client.h
@@ -27,7 +27,6 @@
   void SetNeedsRedrawOnImplThread() override {}
   void SetNeedsRedrawRectOnImplThread(const gfx::Rect& damage_rect) override {}
   void SetNeedsAnimateOnImplThread() override {}
-  void DidInitializeVisibleTileOnImplThread() override {}
   void SetNeedsCommitOnImplThread() override {}
   void SetNeedsManageTilesOnImplThread() override {}
   void PostAnimationEventsToMainThreadOnImplThread(
diff --git a/cc/test/fake_picture_layer.cc b/cc/test/fake_picture_layer.cc
index bd169ba..1a19bc7 100644
--- a/cc/test/fake_picture_layer.cc
+++ b/cc/test/fake_picture_layer.cc
@@ -12,8 +12,19 @@
     : PictureLayer(client),
       update_count_(0),
       push_properties_count_(0),
-      always_update_resources_(false),
-      output_surface_created_count_(0) {
+      output_surface_created_count_(0),
+      always_update_resources_(false) {
+  SetBounds(gfx::Size(1, 1));
+  SetIsDrawable(true);
+}
+
+FakePictureLayer::FakePictureLayer(ContentLayerClient* client,
+                                   scoped_ptr<RecordingSource> source)
+    : PictureLayer(client, source.Pass()),
+      update_count_(0),
+      push_properties_count_(0),
+      output_surface_created_count_(0),
+      always_update_resources_(false) {
   SetBounds(gfx::Size(1, 1));
   SetIsDrawable(true);
 }
diff --git a/cc/test/fake_picture_layer.h b/cc/test/fake_picture_layer.h
index 7aa155e..f42a14d 100644
--- a/cc/test/fake_picture_layer.h
+++ b/cc/test/fake_picture_layer.h
@@ -8,15 +8,21 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "cc/layers/picture_layer.h"
+#include "cc/resources/recording_source.h"
 
 namespace cc {
-
 class FakePictureLayer : public PictureLayer {
  public:
   static scoped_refptr<FakePictureLayer> Create(ContentLayerClient* client) {
     return make_scoped_refptr(new FakePictureLayer(client));
   }
 
+  static scoped_refptr<FakePictureLayer> CreateWithRecordingSource(
+      ContentLayerClient* client,
+      scoped_ptr<RecordingSource> source) {
+    return make_scoped_refptr(new FakePictureLayer(client, source.Pass()));
+  }
+
   scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl) override;
 
   size_t update_count() const { return update_count_; }
@@ -41,12 +47,14 @@
 
  private:
   explicit FakePictureLayer(ContentLayerClient* client);
+  FakePictureLayer(ContentLayerClient* client,
+                   scoped_ptr<RecordingSource> source);
   ~FakePictureLayer() override;
 
   size_t update_count_;
   size_t push_properties_count_;
-  bool always_update_resources_;
   size_t output_surface_created_count_;
+  bool always_update_resources_;
 };
 
 }  // namespace cc
diff --git a/cc/test/fake_picture_pile.cc b/cc/test/fake_picture_pile.cc
new file mode 100644
index 0000000..912ec06
--- /dev/null
+++ b/cc/test/fake_picture_pile.cc
@@ -0,0 +1,15 @@
+// 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 "cc/test/fake_picture_pile.h"
+
+#include "cc/test/fake_picture_pile_impl.h"
+
+namespace cc {
+
+scoped_refptr<RasterSource> FakePicturePile::CreateRasterSource() const {
+  return FakePicturePileImpl::CreateFromPile(this, playback_allowed_event_);
+}
+
+}  // namespace cc
diff --git a/cc/test/fake_picture_pile.h b/cc/test/fake_picture_pile.h
index e486e3b..2d8f4bf 100644
--- a/cc/test/fake_picture_pile.h
+++ b/cc/test/fake_picture_pile.h
@@ -7,12 +7,20 @@
 
 #include "cc/resources/picture_pile.h"
 
+namespace base {
+class WaitableEvent;
+}
+
 namespace cc {
 
 class FakePicturePile : public PicturePile {
  public:
+  FakePicturePile() : playback_allowed_event_(nullptr) {}
   ~FakePicturePile() override {}
 
+  // PicturePile overrides.
+  scoped_refptr<RasterSource> CreateRasterSource() const override;
+
   using PicturePile::buffer_pixels;
   using PicturePile::CanRasterSlowTileCheck;
   using PicturePile::Clear;
@@ -37,6 +45,10 @@
     has_any_recordings_ = has_recordings;
   }
 
+  void SetPlaybackAllowedEvent(base::WaitableEvent* event) {
+    playback_allowed_event_ = event;
+  }
+
   TilingData& tiling() { return tiling_; }
 
   bool is_solid_color() const { return is_solid_color_; }
@@ -47,7 +59,11 @@
   typedef PicturePile::PictureInfo PictureInfo;
   typedef PicturePile::PictureMapKey PictureMapKey;
   typedef PicturePile::PictureMap PictureMap;
+
+ private:
+  base::WaitableEvent* playback_allowed_event_;
 };
+
 }  // namespace cc
 
 #endif  // CC_TEST_FAKE_PICTURE_PILE_H_
diff --git a/cc/test/fake_picture_pile_impl.cc b/cc/test/fake_picture_pile_impl.cc
index 3d31c12..cb68e87 100644
--- a/cc/test/fake_picture_pile_impl.cc
+++ b/cc/test/fake_picture_pile_impl.cc
@@ -8,6 +8,7 @@
 #include <limits>
 #include <utility>
 
+#include "base/synchronization/waitable_event.h"
 #include "cc/resources/picture_pile.h"
 #include "cc/test/fake_picture_pile.h"
 #include "cc/test/impl_side_painting_settings.h"
@@ -15,10 +16,14 @@
 
 namespace cc {
 
-FakePicturePileImpl::FakePicturePileImpl() {}
+FakePicturePileImpl::FakePicturePileImpl() : playback_allowed_event_(nullptr) {
+}
 
-FakePicturePileImpl::FakePicturePileImpl(const PicturePile* other)
+FakePicturePileImpl::FakePicturePileImpl(
+    const PicturePile* other,
+    base::WaitableEvent* playback_allowed_event)
     : PicturePileImpl(other),
+      playback_allowed_event_(playback_allowed_event),
       tile_grid_info_(other->GetTileGridInfoForTesting()) {
 }
 
@@ -34,7 +39,7 @@
   pile.SetRecordedViewport(gfx::Rect(layer_bounds));
   pile.SetHasAnyRecordings(true);
 
-  auto pile_impl = make_scoped_refptr(new FakePicturePileImpl(&pile));
+  auto pile_impl = make_scoped_refptr(new FakePicturePileImpl(&pile, nullptr));
   for (int x = 0; x < pile_impl->tiling().num_tiles_x(); ++x) {
     for (int y = 0; y < pile_impl->tiling().num_tiles_y(); ++y)
       pile_impl->AddRecordingAt(x, y);
@@ -51,7 +56,7 @@
   pile.SetTileGridSize(ImplSidePaintingSettings().default_tile_grid_size);
   pile.SetRecordedViewport(gfx::Rect());
   pile.SetHasAnyRecordings(false);
-  return make_scoped_refptr(new FakePicturePileImpl(&pile));
+  return make_scoped_refptr(new FakePicturePileImpl(&pile, nullptr));
 }
 
 scoped_refptr<FakePicturePileImpl>
@@ -65,7 +70,7 @@
   // This simulates a false positive for this flag.
   pile.SetRecordedViewport(gfx::Rect());
   pile.SetHasAnyRecordings(true);
-  return make_scoped_refptr(new FakePicturePileImpl(&pile));
+  return make_scoped_refptr(new FakePicturePileImpl(&pile, nullptr));
 }
 
 scoped_refptr<FakePicturePileImpl>
@@ -79,11 +84,26 @@
   pile.SetRecordedViewport(gfx::Rect(size));
   pile.SetHasAnyRecordings(true);
 
-  auto pile_impl = make_scoped_refptr(new FakePicturePileImpl(&pile));
+  auto pile_impl = make_scoped_refptr(new FakePicturePileImpl(&pile, nullptr));
   pile_impl->AddRecordingAt(0, 0);
   return pile_impl;
 }
 
+scoped_refptr<FakePicturePileImpl> FakePicturePileImpl::CreateFromPile(
+    const PicturePile* other,
+    base::WaitableEvent* playback_allowed_event) {
+  return make_scoped_refptr(
+      new FakePicturePileImpl(other, playback_allowed_event));
+}
+
+void FakePicturePileImpl::PlaybackToCanvas(SkCanvas* canvas,
+                                           const gfx::Rect& canvas_rect,
+                                           float contents_scale) const {
+  if (playback_allowed_event_)
+    playback_allowed_event_->Wait();
+  PicturePileImpl::PlaybackToCanvas(canvas, canvas_rect, contents_scale);
+}
+
 void FakePicturePileImpl::AddRecordingAt(int x, int y) {
   EXPECT_GE(x, 0);
   EXPECT_GE(y, 0);
diff --git a/cc/test/fake_picture_pile_impl.h b/cc/test/fake_picture_pile_impl.h
index f1a9d31..c32684c 100644
--- a/cc/test/fake_picture_pile_impl.h
+++ b/cc/test/fake_picture_pile_impl.h
@@ -9,6 +9,10 @@
 #include "cc/resources/picture_pile_impl.h"
 #include "cc/test/fake_content_layer_client.h"
 
+namespace base {
+class WaitableEvent;
+}
+
 namespace cc {
 
 class FakePicturePileImpl : public PicturePileImpl {
@@ -23,6 +27,14 @@
       CreateEmptyPileThatThinksItHasRecordings(const gfx::Size& tile_size,
                                                const gfx::Size& layer_bounds);
   static scoped_refptr<FakePicturePileImpl> CreateInfiniteFilledPile();
+  static scoped_refptr<FakePicturePileImpl> CreateFromPile(
+      const PicturePile* other,
+      base::WaitableEvent* playback_allowed_event);
+
+  // Hi-jack the PlaybackToCanvas method to delay its completion.
+  void PlaybackToCanvas(SkCanvas* canvas,
+                        const gfx::Rect& canvas_rect,
+                        float contents_scale) const override;
 
   TilingData& tiling() { return tiling_; }
 
@@ -84,11 +96,13 @@
 
  protected:
   FakePicturePileImpl();
-  explicit FakePicturePileImpl(const PicturePile* other);
+  FakePicturePileImpl(const PicturePile* other,
+                      base::WaitableEvent* playback_allowed_event);
   ~FakePicturePileImpl() override;
 
   FakeContentLayerClient client_;
   SkPaint default_paint_;
+  base::WaitableEvent* playback_allowed_event_;
   SkTileGridFactory::TileGridInfo tile_grid_info_;
 };
 
diff --git a/cc/test/layer_tree_test.cc b/cc/test/layer_tree_test.cc
index 373959d..89cc554 100644
--- a/cc/test/layer_tree_test.cc
+++ b/cc/test/layer_tree_test.cc
@@ -69,7 +69,7 @@
     DCHECK(CalledOnValidThread());
   }
 
-  virtual void OnNeedsBeginFramesChange(bool needs_begin_frames) override {
+  void OnNeedsBeginFramesChange(bool needs_begin_frames) override {
     DCHECK(CalledOnValidThread());
     if (needs_begin_frames) {
       base::MessageLoop::current()->PostDelayedTask(
@@ -80,7 +80,7 @@
     }
   }
 
-  virtual void SetClientReady() override {
+  void SetClientReady() override {
     DCHECK(CalledOnValidThread());
     is_ready_ = true;
   }
@@ -259,22 +259,17 @@
     LayerTreeHostImpl::ReclaimResources(ack);
   }
 
-  void UpdateVisibleTiles() override {
-    LayerTreeHostImpl::UpdateVisibleTiles();
-    test_hooks_->UpdateVisibleTilesOnThread(this);
-  }
-
   void NotifyReadyToActivate() override {
     if (block_notify_ready_to_activate_for_testing_) {
       notify_ready_to_activate_was_blocked_ = true;
     } else {
-      client_->NotifyReadyToActivate();
+      LayerTreeHostImpl::NotifyReadyToActivate();
       test_hooks_->NotifyReadyToActivateOnThread(this);
     }
   }
 
   void NotifyReadyToDraw() override {
-    client_->NotifyReadyToDraw();
+    LayerTreeHostImpl::NotifyReadyToDraw();
     test_hooks_->NotifyReadyToDrawOnThread(this);
   }
 
@@ -327,6 +322,11 @@
     test_hooks_->UpdateAnimationState(this, has_unfinished_animation);
   }
 
+  void NotifyTileStateChanged(const Tile* tile) override {
+    LayerTreeHostImpl::NotifyTileStateChanged(tile);
+    test_hooks_->NotifyTileStateChangedOnThread(this, tile);
+  }
+
  private:
   TestHooks* test_hooks_;
   bool block_notify_ready_to_activate_for_testing_;
@@ -513,7 +513,7 @@
   }
 }
 
-void LayerTreeTest::EndTestAfterDelay(int delay_milliseconds) {
+void LayerTreeTest::EndTestAfterDelayMs(int delay_milliseconds) {
   main_task_runner_->PostDelayedTask(
       FROM_HERE,
       base::Bind(&LayerTreeTest::EndTest, main_thread_weak_ptr_),
diff --git a/cc/test/layer_tree_test.h b/cc/test/layer_tree_test.h
index 531e28d..b801d94 100644
--- a/cc/test/layer_tree_test.h
+++ b/cc/test/layer_tree_test.h
@@ -57,9 +57,10 @@
   virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) {}
   virtual void SwapBuffersOnThread(LayerTreeHostImpl* host_impl, bool result) {}
   virtual void SwapBuffersCompleteOnThread(LayerTreeHostImpl* host_impl) {}
-  virtual void UpdateVisibleTilesOnThread(LayerTreeHostImpl* host_impl) {}
   virtual void NotifyReadyToActivateOnThread(LayerTreeHostImpl* host_impl) {}
   virtual void NotifyReadyToDrawOnThread(LayerTreeHostImpl* host_impl) {}
+  virtual void NotifyTileStateChangedOnThread(LayerTreeHostImpl* host_impl,
+                                              const Tile* tile) {}
   virtual void AnimateLayers(LayerTreeHostImpl* host_impl,
                              base::TimeTicks monotonic_time) {}
   virtual void UpdateAnimationState(LayerTreeHostImpl* host_impl,
@@ -130,7 +131,7 @@
   virtual ~LayerTreeTest();
 
   virtual void EndTest();
-  void EndTestAfterDelay(int delay_milliseconds);
+  void EndTestAfterDelayMs(int delay_milliseconds);
 
   void PostAddAnimationToMainThread(Layer* layer_to_receive_animation);
   void PostAddInstantAnimationToMainThread(Layer* layer_to_receive_animation);
diff --git a/cc/test/pixel_test.h b/cc/test/pixel_test.h
index dff2790..46cdcba 100644
--- a/cc/test/pixel_test.h
+++ b/cc/test/pixel_test.h
@@ -93,7 +93,7 @@
   bool ExpandedViewport() const;
 
  protected:
-  virtual void SetUp() override;
+  void SetUp() override;
 };
 
 // Wrappers to differentiate renderers where the the output surface and viewport
diff --git a/cc/test/pixel_test_utils.h b/cc/test/pixel_test_utils.h
index d8ff7fd..81d20ce 100644
--- a/cc/test/pixel_test_utils.h
+++ b/cc/test/pixel_test_utils.h
@@ -5,6 +5,8 @@
 #ifndef CC_TEST_PIXEL_TEST_UTILS_H_
 #define CC_TEST_PIXEL_TEST_UTILS_H_
 
+#include <string>
+
 #include "base/files/file_path.h"
 #include "cc/test/pixel_comparator.h"
 
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index 696da7a..ffe2ddb 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -174,8 +174,8 @@
 
 }  // namespace
 
-LayerTreeHostImpl::FrameData::FrameData()
-    : contains_incomplete_tile(false), has_no_damage(false) {}
+LayerTreeHostImpl::FrameData::FrameData() : has_no_damage(false) {
+}
 
 LayerTreeHostImpl::FrameData::~FrameData() {}
 
@@ -239,11 +239,11 @@
       animation_registrar_(AnimationRegistrar::Create()),
       rendering_stats_instrumentation_(rendering_stats_instrumentation),
       micro_benchmark_controller_(this),
-      need_to_update_visible_tiles_before_draw_(false),
       shared_bitmap_manager_(shared_bitmap_manager),
       gpu_memory_buffer_manager_(gpu_memory_buffer_manager),
       id_(id),
-      requires_high_res_to_draw_(false) {
+      requires_high_res_to_draw_(false),
+      required_for_draw_tile_is_top_of_raster_queue_(false) {
   DCHECK(proxy_->IsImplThread());
   DidVisibilityChange(this, visible_);
   animation_registrar_->set_supports_scroll_animations(
@@ -489,7 +489,6 @@
 
 void LayerTreeHostImpl::FrameData::AsValueInto(
     base::debug::TracedValue* value) const {
-  value->SetBoolean("contains_incomplete_tile", contains_incomplete_tile);
   value->SetBoolean("has_no_damage", has_no_damage);
 
   // Quad data can be quite large, so only dump render passes if we select
@@ -839,7 +838,6 @@
 
     if (append_quads_data.num_incomplete_tiles ||
         append_quads_data.num_missing_tiles) {
-      frame->contains_incomplete_tile = true;
       if (RequiresHighResToDraw())
         draw_result = DRAW_ABORTED_MISSING_HIGH_RES_CONTENT;
     }
@@ -1034,12 +1032,11 @@
                "LayerTreeHostImpl::PrepareToDraw",
                "SourceFrameNumber",
                active_tree_->source_frame_number());
-
-  if (need_to_update_visible_tiles_before_draw_ &&
-      tile_manager_ && tile_manager_->UpdateVisibleTiles()) {
-    DidInitializeVisibleTile();
-  }
-  need_to_update_visible_tiles_before_draw_ = true;
+  // This will cause NotifyTileStateChanged() to be called for any visible tiles
+  // that completed, which will add damage to the frame for them so they appear
+  // as part of the current frame being drawn.
+  if (settings().impl_side_painting)
+    tile_manager_->UpdateVisibleTiles();
 
   UMA_HISTOGRAM_CUSTOM_COUNTS(
       "Compositing.NumActiveLayers", active_tree_->NumLayers(), 1, 400, 20);
@@ -1051,7 +1048,6 @@
   frame->render_passes.clear();
   frame->render_passes_by_id.clear();
   frame->will_draw_layers.clear();
-  frame->contains_incomplete_tile = false;
   frame->has_no_damage = false;
 
   if (active_tree_->root_layer()) {
@@ -1082,13 +1078,6 @@
   NOTREACHED();
 }
 
-void LayerTreeHostImpl::DidInitializeVisibleTileForTesting() {
-  // Add arbitrary damage, to trigger prepare-to-draws.
-  // Here, setting damage as viewport size, used only for testing.
-  SetFullRootLayerDamage();
-  DidInitializeVisibleTile();
-}
-
 void LayerTreeHostImpl::ResetTreesForTesting() {
   if (active_tree_)
     active_tree_->DetachLayerTree();
@@ -1180,11 +1169,6 @@
   client_->SetNeedsManageTilesOnImplThread();
 }
 
-void LayerTreeHostImpl::DidInitializeVisibleTile() {
-  if (client_ && !client_->IsInsideDraw())
-    client_->DidInitializeVisibleTileOnImplThread();
-}
-
 void LayerTreeHostImpl::GetPictureLayerImplPairs(
     std::vector<PictureLayerImpl::Pair>* layer_pairs,
     bool need_valid_tile_priorities) const {
@@ -1225,6 +1209,20 @@
   picture_layer_pairs_.clear();
   GetPictureLayerImplPairs(&picture_layer_pairs_, true);
   queue->Build(picture_layer_pairs_, tree_priority);
+
+  if (!queue->IsEmpty()) {
+    // Only checking the Top() tile here isn't a definite answer that there is
+    // or isn't something required for draw in this raster queue. It's just a
+    // heuristic to let us hit the common case and proactively tell the
+    // scheduler that we expect to draw within each vsync until we get all the
+    // tiles ready to draw. If we happen to miss a required for draw tile here,
+    // then we will miss telling the scheduler each frame that we intend to draw
+    // so it may make worse scheduling decisions.
+    required_for_draw_tile_is_top_of_raster_queue_ =
+        queue->Top()->required_for_draw();
+  } else {
+    required_for_draw_tile_is_top_of_raster_queue_ = false;
+  }
 }
 
 void LayerTreeHostImpl::BuildEvictionQueue(EvictionTilePriorityQueue* queue,
@@ -1245,6 +1243,11 @@
 }
 
 void LayerTreeHostImpl::NotifyReadyToDraw() {
+  // Tiles that are ready will cause NotifyTileStateChanged() to be called so we
+  // don't need to schedule a draw here. Just stop WillBeginImplFrame() from
+  // causing optimistic requests to draw a frame.
+  required_for_draw_tile_is_top_of_raster_queue_ = false;
+
   client_->NotifyReadyToDraw();
 }
 
@@ -1264,6 +1267,13 @@
     if (layer_impl)
       layer_impl->NotifyTileStateChanged(tile);
   }
+
+  // Check for a non-null active tree to avoid doing this during shutdown.
+  if (active_tree_ && !client_->IsInsideDraw() && tile->required_for_draw()) {
+    // The LayerImpl::NotifyTileStateChanged() should damage the layer, so this
+    // redraw will make those tiles be displayed.
+    SetNeedsRedraw();
+  }
 }
 
 void LayerTreeHostImpl::SetMemoryPolicy(const ManagedMemoryPolicy& policy) {
@@ -1602,6 +1612,13 @@
   UpdateCurrentBeginFrameArgs(args);
   // Cache the begin impl frame interval
   begin_impl_frame_interval_ = args.interval;
+
+  if (required_for_draw_tile_is_top_of_raster_queue_) {
+    // Optimistically schedule a draw, as a tile required for draw is at the top
+    // of the current raster queue. This will let us expect the tile to complete
+    // and draw it within the impl frame we are beginning now.
+    SetNeedsRedraw();
+  }
 }
 
 void LayerTreeHostImpl::UpdateViewportContainerSizes() {
@@ -1729,15 +1746,7 @@
   TRACE_EVENT_ASYNC_BEGIN0("cc", "PendingTree:waiting", pending_tree_.get());
 }
 
-void LayerTreeHostImpl::UpdateVisibleTiles() {
-  if (tile_manager_ && tile_manager_->UpdateVisibleTiles())
-    DidInitializeVisibleTile();
-  need_to_update_visible_tiles_before_draw_ = false;
-}
-
 void LayerTreeHostImpl::ActivateSyncTree() {
-  need_to_update_visible_tiles_before_draw_ = true;
-
   if (pending_tree_) {
     TRACE_EVENT_ASYNC_END0("cc", "PendingTree:waiting", pending_tree_.get());
 
@@ -1940,7 +1949,6 @@
                                       scheduled_raster_task_limit);
 
   UpdateTileManagerMemoryPolicy(ActualManagedMemoryPolicy());
-  need_to_update_visible_tiles_before_draw_ = false;
 }
 
 void LayerTreeHostImpl::CreateResourceAndRasterWorkerPool(
@@ -2940,9 +2948,6 @@
   // scales that we want when we're not inside a pinch.
   active_tree_->set_needs_update_draw_properties();
   SetNeedsRedraw();
-  // TODO(danakj): Don't set root damage. Just updating draw properties and
-  // getting new tiles rastered should be enough! crbug.com/427423
-  SetFullRootLayerDamage();
 }
 
 static void CollectScrollDeltas(ScrollAndScaleSet* scroll_info,
diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h
index 24cb730..ba4fabf 100644
--- a/cc/trees/layer_tree_host_impl.h
+++ b/cc/trees/layer_tree_host_impl.h
@@ -82,7 +82,6 @@
   virtual void SetNeedsRedrawOnImplThread() = 0;
   virtual void SetNeedsRedrawRectOnImplThread(const gfx::Rect& damage_rect) = 0;
   virtual void SetNeedsAnimateOnImplThread() = 0;
-  virtual void DidInitializeVisibleTileOnImplThread() = 0;
   virtual void SetNeedsCommitOnImplThread() = 0;
   virtual void SetNeedsManageTilesOnImplThread() = 0;
   virtual void PostAnimationEventsToMainThreadOnImplThread(
@@ -172,7 +171,6 @@
     RenderPassIdHashMap render_passes_by_id;
     const LayerImplList* render_surface_layer_list;
     LayerImplList will_draw_layers;
-    bool contains_incomplete_tile;
     bool has_no_damage;
 
     // RenderPassSink implementation.
@@ -210,9 +208,6 @@
   // immediately if any notifications had been blocked while blocking.
   virtual void BlockNotifyReadyToActivateForTesting(bool block);
 
-  // This allows us to inject DidInitializeVisibleTile events for testing.
-  void DidInitializeVisibleTileForTesting();
-
   // Resets all of the trees to an empty state.
   void ResetTreesForTesting();
 
@@ -302,7 +297,6 @@
     return pending_tree_ ? pending_tree_.get() : active_tree_.get();
   }
   virtual void CreatePendingTree();
-  virtual void UpdateVisibleTiles();
   virtual void ActivateSyncTree();
 
   // Shortcuts to layers on the active tree.
@@ -574,8 +568,6 @@
                               bool zero_budget);
   void EnforceManagedMemoryPolicy(const ManagedMemoryPolicy& policy);
 
-  void DidInitializeVisibleTile();
-
   void MarkUIResourceNotEvicted(UIResourceId uid);
 
   void NotifySwapPromiseMonitorsOfSetNeedsRedraw();
@@ -699,8 +691,6 @@
   MicroBenchmarkControllerImpl micro_benchmark_controller_;
   scoped_ptr<TaskGraphRunner> single_thread_synchronous_task_graph_runner_;
 
-  bool need_to_update_visible_tiles_before_draw_;
-
   // Optional callback to notify of new tree activations.
   base::Closure tree_activation_callback_;
 
@@ -714,6 +704,7 @@
   std::vector<PictureLayerImpl::Pair> picture_layer_pairs_;
 
   bool requires_high_res_to_draw_;
+  bool required_for_draw_tile_is_top_of_raster_queue_;
 
   DISALLOW_COPY_AND_ASSIGN(LayerTreeHostImpl);
 };
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
index 17179cd..0b9d976 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -87,7 +87,6 @@
         did_request_redraw_(false),
         did_request_animate_(false),
         did_request_manage_tiles_(false),
-        did_upload_visible_tile_(false),
         reduce_memory_result_(true),
         current_limit_bytes_(0),
         current_priority_cutoff_value_(0) {
@@ -103,11 +102,11 @@
     return settings;
   }
 
-  virtual void SetUp() override {
+  void SetUp() override {
     CreateHostImpl(DefaultSettings(), CreateOutputSurface());
   }
 
-  virtual void TearDown() override {}
+  void TearDown() override {}
 
   void UpdateRendererCapabilitiesOnImplThread() override {}
   void DidLoseOutputSurfaceOnImplThread() override {}
@@ -133,9 +132,6 @@
   void SetNeedsManageTilesOnImplThread() override {
     did_request_manage_tiles_ = true;
   }
-  void DidInitializeVisibleTileOnImplThread() override {
-    did_upload_visible_tile_ = true;
-  }
   void SetNeedsCommitOnImplThread() override { did_request_commit_ = true; }
   void PostAnimationEventsToMainThreadOnImplThread(
       scoped_ptr<AnimationEventsVector> events) override {}
@@ -394,7 +390,6 @@
   bool did_request_redraw_;
   bool did_request_animate_;
   bool did_request_manage_tiles_;
-  bool did_upload_visible_tile_;
   bool reduce_memory_result_;
   base::Closure scrollbar_fade_start_;
   base::TimeDelta requested_scrollbar_animation_delay_;
@@ -6224,7 +6219,7 @@
 
 class LayerTreeHostImplTestDeferredInitialize : public LayerTreeHostImplTest {
  protected:
-  virtual void SetUp() override {
+  void SetUp() override {
     LayerTreeHostImplTest::SetUp();
 
     set_reduce_memory_result(false);
@@ -6413,7 +6408,7 @@
 
 class LayerTreeHostImplTestManageTiles : public LayerTreeHostImplTest {
  public:
-  virtual void SetUp() override {
+  void SetUp() override {
     LayerTreeSettings settings;
     settings.impl_side_painting = true;
 
@@ -7071,7 +7066,7 @@
 
 class LayerTreeHostImplWithTopControlsTest : public LayerTreeHostImplTest {
  public:
-  virtual void SetUp() override {
+  void SetUp() override {
     LayerTreeSettings settings = DefaultSettings();
     settings.calculate_top_controls_position = true;
     settings.top_controls_height = top_controls_height_;
@@ -7459,7 +7454,7 @@
 
 class LayerTreeHostImplWithImplicitLimitsTest : public LayerTreeHostImplTest {
  public:
-  virtual void SetUp() override {
+  void SetUp() override {
     LayerTreeSettings settings = DefaultSettings();
     settings.max_memory_for_prepaint_percentage = 50;
     CreateHostImpl(settings, CreateOutputSurface());
diff --git a/cc/trees/layer_tree_host_pixeltest_blending.cc b/cc/trees/layer_tree_host_pixeltest_blending.cc
index 148769e..14029b5 100644
--- a/cc/trees/layer_tree_host_pixeltest_blending.cc
+++ b/cc/trees/layer_tree_host_pixeltest_blending.cc
@@ -61,7 +61,7 @@
     pixel_comparator_.reset(new FuzzyPixelOffByOneComparator(true));
   }
 
-  virtual void InitializeSettings(LayerTreeSettings* settings) override {
+  void InitializeSettings(LayerTreeSettings* settings) override {
     settings->force_antialiasing = force_antialiasing_;
     settings->force_blending_with_shaders = force_blending_with_shaders_;
   }
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc
index 5c66790..b0ce5a5 100644
--- a/cc/trees/layer_tree_host_unittest.cc
+++ b/cc/trees/layer_tree_host_unittest.cc
@@ -25,6 +25,7 @@
 #include "cc/output/output_surface.h"
 #include "cc/quads/draw_quad.h"
 #include "cc/quads/io_surface_draw_quad.h"
+#include "cc/quads/tile_draw_quad.h"
 #include "cc/resources/prioritized_resource.h"
 #include "cc/resources/prioritized_resource_manager.h"
 #include "cc/resources/resource_update_queue.h"
@@ -36,6 +37,7 @@
 #include "cc/test/fake_painted_scrollbar_layer.h"
 #include "cc/test/fake_picture_layer.h"
 #include "cc/test/fake_picture_layer_impl.h"
+#include "cc/test/fake_picture_pile.h"
 #include "cc/test/fake_proxy.h"
 #include "cc/test/fake_scoped_ui_resource.h"
 #include "cc/test/geometry_test_utils.h"
@@ -415,12 +417,13 @@
 class LayerTreeHostTestSetNeedsRedrawRect : public LayerTreeHostTest {
  public:
   LayerTreeHostTestSetNeedsRedrawRect()
-      : num_draws_(0),
-        bounds_(50, 50),
-        invalid_rect_(10, 10, 20, 20),
-        root_layer_(ContentLayer::Create(&client_)) {}
+      : num_draws_(0), bounds_(50, 50), invalid_rect_(10, 10, 20, 20) {}
 
   void BeginTest() override {
+    if (layer_tree_host()->settings().impl_side_painting)
+      root_layer_ = FakePictureLayer::Create(&client_);
+    else
+      root_layer_ = ContentLayer::Create(&client_);
     root_layer_->SetIsDrawable(true);
     root_layer_->SetBounds(bounds_);
     layer_tree_host()->SetRootLayer(root_layer_);
@@ -464,7 +467,7 @@
   const gfx::Size bounds_;
   const gfx::Rect invalid_rect_;
   FakeContentLayerClient client_;
-  scoped_refptr<ContentLayer> root_layer_;
+  scoped_refptr<Layer> root_layer_;
 };
 
 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestSetNeedsRedrawRect);
@@ -479,7 +482,10 @@
     root_layer_ = Layer::Create();
     root_layer_->SetBounds(gfx::Size(10, 20));
 
-    scaled_layer_ = FakeContentLayer::Create(&client_);
+    if (layer_tree_host()->settings().impl_side_painting)
+      scaled_layer_ = FakePictureLayer::Create(&client_);
+    else
+      scaled_layer_ = FakeContentLayer::Create(&client_);
     scaled_layer_->SetBounds(gfx::Size(1, 1));
     root_layer_->AddChild(scaled_layer_);
 
@@ -497,10 +503,15 @@
   void DidCommit() override {
     switch (layer_tree_host()->source_frame_number()) {
       case 1:
-        // Changing the device scale factor causes a commit. It also changes
-        // the content bounds of |scaled_layer_|, which should not generate
-        // a second commit as a result.
-        layer_tree_host()->SetDeviceScaleFactor(4.f);
+        // SetBounds grows the layer and exposes new content.
+        if (layer_tree_host()->settings().impl_side_painting) {
+          scaled_layer_->SetBounds(gfx::Size(4, 4));
+        } else {
+          // Changing the device scale factor causes a commit. It also changes
+          // the content bounds of |scaled_layer_|, which should not generate
+          // a second commit as a result.
+          layer_tree_host()->SetDeviceScaleFactor(4.f);
+        }
         break;
       default:
         // No extra commits.
@@ -516,7 +527,7 @@
  private:
   FakeContentLayerClient client_;
   scoped_refptr<Layer> root_layer_;
-  scoped_refptr<FakeContentLayer> scaled_layer_;
+  scoped_refptr<Layer> scaled_layer_;
 };
 
 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestNoExtraCommitFromInvalidate);
@@ -583,12 +594,13 @@
 class LayerTreeHostTestSetNextCommitForcesRedraw : public LayerTreeHostTest {
  public:
   LayerTreeHostTestSetNextCommitForcesRedraw()
-      : num_draws_(0),
-        bounds_(50, 50),
-        invalid_rect_(10, 10, 20, 20),
-        root_layer_(ContentLayer::Create(&client_)) {}
+      : num_draws_(0), bounds_(50, 50), invalid_rect_(10, 10, 20, 20) {}
 
   void BeginTest() override {
+    if (layer_tree_host()->settings().impl_side_painting)
+      root_layer_ = FakePictureLayer::Create(&client_);
+    else
+      root_layer_ = ContentLayer::Create(&client_);
     root_layer_->SetIsDrawable(true);
     root_layer_->SetBounds(bounds_);
     layer_tree_host()->SetRootLayer(root_layer_);
@@ -665,7 +677,7 @@
   const gfx::Size bounds_;
   const gfx::Rect invalid_rect_;
   FakeContentLayerClient client_;
-  scoped_refptr<ContentLayer> root_layer_;
+  scoped_refptr<Layer> root_layer_;
 };
 
 SINGLE_AND_MULTI_THREAD_BLOCKNOTIFY_TEST_F(
@@ -675,22 +687,31 @@
 // its damage is preserved until the next time it is drawn.
 class LayerTreeHostTestUndrawnLayersDamageLater : public LayerTreeHostTest {
  public:
-  LayerTreeHostTestUndrawnLayersDamageLater()
-      : root_layer_(ContentLayer::Create(&client_)) {}
+  LayerTreeHostTestUndrawnLayersDamageLater() {}
 
   void SetupTree() override {
+    if (layer_tree_host()->settings().impl_side_painting)
+      root_layer_ = FakePictureLayer::Create(&client_);
+    else
+      root_layer_ = ContentLayer::Create(&client_);
     root_layer_->SetIsDrawable(true);
     root_layer_->SetBounds(gfx::Size(50, 50));
     layer_tree_host()->SetRootLayer(root_layer_);
 
     // The initially transparent layer has a larger child layer, which is
     // not initially drawn because of the this (parent) layer.
-    parent_layer_ = FakeContentLayer::Create(&client_);
+    if (layer_tree_host()->settings().impl_side_painting)
+      parent_layer_ = FakePictureLayer::Create(&client_);
+    else
+      parent_layer_ = FakeContentLayer::Create(&client_);
     parent_layer_->SetBounds(gfx::Size(15, 15));
     parent_layer_->SetOpacity(0.0f);
     root_layer_->AddChild(parent_layer_);
 
-    child_layer_ = FakeContentLayer::Create(&client_);
+    if (layer_tree_host()->settings().impl_side_painting)
+      child_layer_ = FakePictureLayer::Create(&client_);
+    else
+      child_layer_ = FakeContentLayer::Create(&client_);
     child_layer_->SetBounds(gfx::Size(25, 25));
     parent_layer_->AddChild(child_layer_);
 
@@ -755,9 +776,9 @@
 
  private:
   FakeContentLayerClient client_;
-  scoped_refptr<ContentLayer> root_layer_;
-  scoped_refptr<FakeContentLayer> parent_layer_;
-  scoped_refptr<FakeContentLayer> child_layer_;
+  scoped_refptr<Layer> root_layer_;
+  scoped_refptr<Layer> parent_layer_;
+  scoped_refptr<Layer> child_layer_;
 };
 
 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestUndrawnLayersDamageLater);
@@ -1130,16 +1151,27 @@
 // from being updated during commit.
 class LayerTreeHostTestOpacityChange : public LayerTreeHostTest {
  public:
-  LayerTreeHostTestOpacityChange()
-      : test_opacity_change_delegate_(),
-        update_check_layer_(ContentLayerWithUpdateTracking::Create(
-            &test_opacity_change_delegate_)) {
-    test_opacity_change_delegate_.SetTestLayer(update_check_layer_.get());
-  }
+  LayerTreeHostTestOpacityChange() : test_opacity_change_delegate_() {}
 
   void BeginTest() override {
+    if (layer_tree_host()->settings().impl_side_painting) {
+      update_check_picture_layer_ =
+          FakePictureLayer::Create(&test_opacity_change_delegate_);
+      test_opacity_change_delegate_.SetTestLayer(
+          update_check_picture_layer_.get());
+      is_impl_paint_ = true;
+    } else {
+      update_check_content_layer_ = ContentLayerWithUpdateTracking::Create(
+          &test_opacity_change_delegate_);
+      test_opacity_change_delegate_.SetTestLayer(
+          update_check_content_layer_.get());
+      is_impl_paint_ = false;
+    }
     layer_tree_host()->SetViewportSize(gfx::Size(10, 10));
-    layer_tree_host()->root_layer()->AddChild(update_check_layer_);
+    if (layer_tree_host()->settings().impl_side_painting)
+      layer_tree_host()->root_layer()->AddChild(update_check_picture_layer_);
+    else
+      layer_tree_host()->root_layer()->AddChild(update_check_content_layer_);
 
     PostSetNeedsCommitToMainThread();
   }
@@ -1148,47 +1180,36 @@
 
   void AfterTest() override {
     // Update() should have been called once.
-    EXPECT_EQ(1, update_check_layer_->PaintContentsCount());
+    if (is_impl_paint_)
+      EXPECT_EQ(1u, update_check_picture_layer_->update_count());
+    else
+      EXPECT_EQ(1, update_check_content_layer_->PaintContentsCount());
   }
 
  private:
   TestOpacityChangeLayerDelegate test_opacity_change_delegate_;
-  scoped_refptr<ContentLayerWithUpdateTracking> update_check_layer_;
+  scoped_refptr<ContentLayerWithUpdateTracking> update_check_content_layer_;
+  scoped_refptr<FakePictureLayer> update_check_picture_layer_;
+  bool is_impl_paint_;
 };
 
 MULTI_THREAD_TEST_F(LayerTreeHostTestOpacityChange);
 
-class NoScaleContentLayer : public ContentLayer {
- public:
-  static scoped_refptr<NoScaleContentLayer> Create(ContentLayerClient* client) {
-    return make_scoped_refptr(new NoScaleContentLayer(client));
-  }
-
-  void CalculateContentsScale(float ideal_contents_scale,
-                              float* contents_scale_x,
-                              float* contents_scale_y,
-                              gfx::Size* contentBounds) override {
-    // Skip over the ContentLayer's method to the base Layer class.
-    Layer::CalculateContentsScale(ideal_contents_scale,
-                                  contents_scale_x,
-                                  contents_scale_y,
-                                  contentBounds);
-  }
-
- private:
-  explicit NoScaleContentLayer(ContentLayerClient* client)
-      : ContentLayer(client) {}
-  ~NoScaleContentLayer() override {}
-};
-
 class LayerTreeHostTestDeviceScaleFactorScalesViewportAndLayers
     : public LayerTreeHostTest {
  public:
-  LayerTreeHostTestDeviceScaleFactorScalesViewportAndLayers()
-      : root_layer_(NoScaleContentLayer::Create(&client_)),
-        child_layer_(ContentLayer::Create(&client_)) {}
+  LayerTreeHostTestDeviceScaleFactorScalesViewportAndLayers() {}
+
+  void InitializeSettings(LayerTreeSettings* settings) override {
+    // PictureLayer can only be used with impl side painting enabled.
+    settings->impl_side_painting = true;
+  }
 
   void BeginTest() override {
+    client_.set_fill_with_nonsolid_color(true);
+    root_layer_ = FakePictureLayer::Create(&client_);
+    child_layer_ = FakePictureLayer::Create(&client_);
+
     layer_tree_host()->SetViewportSize(gfx::Size(60, 60));
     layer_tree_host()->SetDeviceScaleFactor(1.5);
     EXPECT_EQ(gfx::Size(60, 60), layer_tree_host()->device_viewport_size());
@@ -1219,8 +1240,10 @@
     // Device viewport is scaled.
     EXPECT_EQ(gfx::Size(60, 60), impl->DrawViewportSize());
 
-    LayerImpl* root = impl->active_tree()->root_layer();
-    LayerImpl* child = impl->active_tree()->root_layer()->children()[0];
+    FakePictureLayerImpl* root =
+        static_cast<FakePictureLayerImpl*>(impl->active_tree()->root_layer());
+    FakePictureLayerImpl* child = static_cast<FakePictureLayerImpl*>(
+        impl->active_tree()->root_layer()->children()[0]);
 
     // Positions remain in layout pixels.
     EXPECT_EQ(gfx::Point(0, 0), root->position());
@@ -1244,10 +1267,8 @@
     EXPECT_RECT_EQ(gfx::Rect(0, 0, 60, 60),
                    root->render_surface()->content_rect());
 
-    // The content bounds of the child should be scaled.
-    gfx::Size child_bounds_scaled =
-        gfx::ToCeiledSize(gfx::ScaleSize(child->bounds(), 1.5));
-    EXPECT_EQ(child_bounds_scaled, child->content_bounds());
+    // The max tiling scale of the child should be scaled.
+    EXPECT_FLOAT_EQ(1.5f, child->MaximumTilingContentsScale());
 
     gfx::Transform scale_transform;
     scale_transform.Scale(impl->device_scale_factor(),
@@ -1261,13 +1282,13 @@
     EXPECT_EQ(root_screen_space_transform, root->screen_space_transform());
 
     // The child is at position 2,2, which is transformed to 3,3 after the scale
-    gfx::Transform child_screen_space_transform;
-    child_screen_space_transform.Translate(3.f, 3.f);
-    gfx::Transform child_draw_transform = child_screen_space_transform;
+    gfx::Transform child_transform;
+    child_transform.Translate(3.f, 3.f);
+    child_transform.Scale(child->MaximumTilingContentsScale(),
+                          child->MaximumTilingContentsScale());
 
-    EXPECT_TRANSFORMATION_MATRIX_EQ(child_draw_transform,
-                                    child->draw_transform());
-    EXPECT_TRANSFORMATION_MATRIX_EQ(child_screen_space_transform,
+    EXPECT_TRANSFORMATION_MATRIX_EQ(child_transform, child->draw_transform());
+    EXPECT_TRANSFORMATION_MATRIX_EQ(child_transform,
                                     child->screen_space_transform());
 
     EndTest();
@@ -1277,12 +1298,13 @@
 
  private:
   FakeContentLayerClient client_;
-  scoped_refptr<NoScaleContentLayer> root_layer_;
-  scoped_refptr<ContentLayer> child_layer_;
+  scoped_refptr<FakePictureLayer> root_layer_;
+  scoped_refptr<FakePictureLayer> child_layer_;
 };
 
 MULTI_THREAD_TEST_F(LayerTreeHostTestDeviceScaleFactorScalesViewportAndLayers);
 
+// TODO(sohanjg) : Remove it once impl-side painting ships everywhere.
 // Verify atomicity of commits and reuse of textures.
 class LayerTreeHostTestDirectRendererAtomicCommit : public LayerTreeHostTest {
  public:
@@ -1391,6 +1413,7 @@
 MULTI_THREAD_DIRECT_RENDERER_NOIMPL_TEST_F(
     LayerTreeHostTestDirectRendererAtomicCommit);
 
+// TODO(sohanjg) : Remove it once impl-side painting ships everywhere.
 class LayerTreeHostTestDelegatingRendererAtomicCommit
     : public LayerTreeHostTestDirectRendererAtomicCommit {
  public:
@@ -1458,6 +1481,7 @@
   layer->SetContentsOpaque(opaque);
 }
 
+// TODO(sohanjg) : Remove it once impl-side painting ships everywhere.
 class LayerTreeHostTestAtomicCommitWithPartialUpdate
     : public LayerTreeHostTest {
  public:
@@ -1631,6 +1655,7 @@
 SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F(
     LayerTreeHostTestAtomicCommitWithPartialUpdate);
 
+// TODO(sohanjg) : Make it work with impl-side painting.
 class LayerTreeHostTestSurfaceNotAllocatedForLayersOutsideMemoryLimit
     : public LayerTreeHostTest {
  protected:
@@ -1951,11 +1976,15 @@
     layer_tree_host()->SetViewportSize(gfx::Size(10, 10));
     layer_tree_host()->root_layer()->SetBounds(gfx::Size(10, 10));
 
-    content_layer_ = ContentLayer::Create(&client_);
-    content_layer_->SetBounds(gfx::Size(10, 10));
-    content_layer_->SetPosition(gfx::PointF(0.f, 0.f));
-    content_layer_->SetIsDrawable(true);
-    layer_tree_host()->root_layer()->AddChild(content_layer_);
+    if (layer_tree_host()->settings().impl_side_painting)
+      layer_ = FakePictureLayer::Create(&client_);
+    else
+      layer_ = FakeContentLayer::Create(&client_);
+
+    layer_->SetBounds(gfx::Size(10, 10));
+    layer_->SetPosition(gfx::PointF(0.f, 0.f));
+    layer_->SetIsDrawable(true);
+    layer_tree_host()->root_layer()->AddChild(layer_);
 
     PostSetNeedsCommitToMainThread();
   }
@@ -1963,7 +1992,7 @@
   void DidCommitAndDrawFrame() override {
     if (num_draw_layers_ == 2)
       return;
-    content_layer_->SetNeedsDisplay();
+    layer_->SetNeedsDisplay();
   }
 
   void CommitCompleteOnThread(LayerTreeHostImpl* impl) override {
@@ -1984,12 +2013,12 @@
 
  private:
   FakeContentLayerClient client_;
-  scoped_refptr<Layer> content_layer_;
+  scoped_refptr<Layer> layer_;
   int num_commit_complete_;
   int num_draw_layers_;
 };
 
-MULTI_THREAD_NOIMPL_TEST_F(LayerTreeHostTestContinuousInvalidate);
+SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestContinuousInvalidate);
 
 class LayerTreeHostTestDeferCommits : public LayerTreeHostTest {
  public:
@@ -2192,6 +2221,7 @@
   EXPECT_EQ(0u, host->MaxPartialTextureUpdates());
 }
 
+// TODO(sohanjg) : Remove it once impl-side painting ships everywhere.
 class LayerTreeHostTestShutdownWithOnlySomeResourcesEvicted
     : public LayerTreeHostTest {
  public:
@@ -2596,9 +2626,7 @@
     test_capabilities_.gpu.texture_rectangle = true;
   }
 
-  virtual GLuint createTexture() override {
-    return 1;
-  }
+  GLuint createTexture() override { return 1; }
   MOCK_METHOD1(activeTexture, void(GLenum texture));
   MOCK_METHOD2(bindTexture, void(GLenum target,
                                  GLuint texture_id));
@@ -4482,7 +4510,10 @@
   }
 
   void SetupTree() override {
-    root_ = FakeContentLayer::Create(&client_);
+    if (layer_tree_host()->settings().impl_side_painting)
+      root_ = FakePictureLayer::Create(&client_);
+    else
+      root_ = FakeContentLayer::Create(&client_);
     root_->SetBounds(gfx::Size(20, 20));
     layer_tree_host()->SetRootLayer(root_);
     LayerTreeHostTest::SetupTree();
@@ -4524,10 +4555,9 @@
   size_t first_output_surface_memory_limit_;
   size_t second_output_surface_memory_limit_;
   FakeContentLayerClient client_;
-  scoped_refptr<FakeContentLayer> root_;
+  scoped_refptr<Layer> root_;
 };
 
-// No output to copy for delegated renderers.
 SINGLE_AND_MULTI_THREAD_TEST_F(
     LayerTreeHostTestSetMemoryPolicyOnLostOutputSurface);
 
@@ -5000,7 +5030,8 @@
   void SetupTree() override {
     LayerTreeHostTest::SetupTree();
 
-    scoped_refptr<PictureLayer> layer = PictureLayer::Create(&layer_client_);
+    scoped_refptr<FakePictureLayer> layer =
+        FakePictureLayer::Create(&layer_client_);
     layer->SetBounds(gfx::Size(10, 10));
     layer->SetIsDrawable(true);
     layer_tree_host()->root_layer()->AddChild(layer);
@@ -5330,4 +5361,358 @@
 };
 
 MULTI_THREAD_TEST_F(LayerTreeHostAcceptsDeltasFromImplWithoutRootLayer);
+
+class LayerTreeHostTestCrispUpAfterPinchEnds : public LayerTreeHostTest {
+ protected:
+  LayerTreeHostTestCrispUpAfterPinchEnds()
+      : playback_allowed_event_(true, true) {}
+
+  void InitializeSettings(LayerTreeSettings* settings) override {
+    settings->impl_side_painting = true;
+  }
+
+  void SetupTree() override {
+    frame_ = 1;
+    posted_ = false;
+    client_.set_fill_with_nonsolid_color(true);
+
+    scoped_refptr<Layer> root = Layer::Create();
+    root->SetBounds(gfx::Size(500, 500));
+
+    scoped_refptr<Layer> pinch = Layer::Create();
+    pinch->SetBounds(gfx::Size(500, 500));
+    pinch->SetScrollClipLayerId(root->id());
+    pinch->SetIsContainerForFixedPositionLayers(true);
+    root->AddChild(pinch);
+
+    scoped_ptr<FakePicturePile> pile(new FakePicturePile);
+    pile->SetPlaybackAllowedEvent(&playback_allowed_event_);
+    scoped_refptr<FakePictureLayer> layer =
+        FakePictureLayer::CreateWithRecordingSource(&client_, pile.Pass());
+    layer->SetBounds(gfx::Size(500, 500));
+    layer->SetContentsOpaque(true);
+    pinch->AddChild(layer);
+
+    layer_tree_host()->RegisterViewportLayers(root, pinch, pinch);
+    layer_tree_host()->SetPageScaleFactorAndLimits(1.f, 1.f, 4.f);
+    layer_tree_host()->SetRootLayer(root);
+    LayerTreeHostTest::SetupTree();
+  }
+
+  // Returns the delta scale of all quads in the frame's root pass from their
+  // ideal, or 0 if they are not all the same.
+  float FrameQuadScaleDeltaFromIdeal(LayerTreeHostImpl::FrameData* frame_data) {
+    if (frame_data->has_no_damage)
+      return 0.f;
+    float frame_scale = 0.f;
+    RenderPass* root_pass = frame_data->render_passes.back();
+    for (const auto& draw_quad : root_pass->quad_list) {
+      // Checkerboards mean an incomplete frame.
+      if (draw_quad->material != DrawQuad::TILED_CONTENT)
+        return 0.f;
+      const TileDrawQuad* quad = TileDrawQuad::MaterialCast(draw_quad);
+      float quad_scale =
+          quad->tex_coord_rect.width() / static_cast<float>(quad->rect.width());
+      float transform_scale =
+          SkMScalarToFloat(quad->quadTransform().matrix().get(0, 0));
+      float scale = quad_scale / transform_scale;
+      if (frame_scale != 0.f && frame_scale != scale)
+        return 0.f;
+      frame_scale = scale;
+    }
+    return frame_scale;
+  }
+
+  void BeginTest() override { PostSetNeedsCommitToMainThread(); }
+
+  DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
+                                   LayerTreeHostImpl::FrameData* frame_data,
+                                   DrawResult draw_result) override {
+    float quad_scale_delta = FrameQuadScaleDeltaFromIdeal(frame_data);
+    switch (frame_) {
+      case 1:
+        // Drew at page scale 1 before any pinching.
+        EXPECT_EQ(1.f, host_impl->active_tree()->total_page_scale_factor());
+        EXPECT_EQ(1.f, quad_scale_delta);
+        PostNextAfterDraw(host_impl);
+        break;
+      case 2:
+        if (quad_scale_delta != 1.f)
+          break;
+        // Drew at page scale 2.2 after pinching in.
+        EXPECT_EQ(2.2f, host_impl->active_tree()->total_page_scale_factor());
+        EXPECT_EQ(1.f, quad_scale_delta);
+        PostNextAfterDraw(host_impl);
+        break;
+      case 3:
+        if (quad_scale_delta != 2.2f)
+          break;
+        // Drew at page scale 1 with the 2.2 tiling while pinching out.
+        EXPECT_EQ(1.f, host_impl->active_tree()->total_page_scale_factor());
+        EXPECT_EQ(2.2f, quad_scale_delta);
+        PostNextAfterDraw(host_impl);
+        break;
+      case 4:
+        // Drew at page scale 1 with the 2.2 tiling after pinching out completed
+        // while waiting for texture uploads to complete.
+        EXPECT_EQ(1.f, host_impl->active_tree()->total_page_scale_factor());
+        // This frame will not have any damage, since it's actually the same as
+        // the last frame, and should contain no incomplete tiles. We just want
+        // to make sure we drew here at least once after the pinch ended to be
+        // sure that drawing after pinch doesn't leave us at the wrong scale
+        // forever.
+        EXPECT_TRUE(frame_data->has_no_damage);
+        PostNextAfterDraw(host_impl);
+        break;
+      case 5:
+        if (quad_scale_delta != 1.f)
+          break;
+        // Drew at scale 1 after texture uploads are done.
+        EXPECT_EQ(1.f, host_impl->active_tree()->total_page_scale_factor());
+        EXPECT_EQ(1.f, quad_scale_delta);
+        EndTest();
+        break;
+    }
+    return draw_result;
+  }
+
+  void PostNextAfterDraw(LayerTreeHostImpl* host_impl) {
+    if (posted_)
+      return;
+    posted_ = true;
+    ImplThreadTaskRunner()->PostDelayedTask(
+        FROM_HERE, base::Bind(&LayerTreeHostTestCrispUpAfterPinchEnds::Next,
+                              base::Unretained(this), host_impl),
+        // Use a delay to allow raster/upload to happen in between frames. This
+        // should cause flakiness if we fail to block raster/upload when
+        // desired.
+        base::TimeDelta::FromMilliseconds(16 * 6));
+  }
+
+  void Next(LayerTreeHostImpl* host_impl) {
+    ++frame_;
+    posted_ = false;
+    switch (frame_) {
+      case 2:
+        // Pinch zoom in.
+        host_impl->PinchGestureBegin();
+        host_impl->PinchGestureUpdate(2.2f, gfx::Point(100, 100));
+        host_impl->PinchGestureEnd();
+        break;
+      case 3:
+        // Pinch zoom back to 1.f but don't end it.
+        host_impl->PinchGestureBegin();
+        host_impl->PinchGestureUpdate(1.f / 2.2f, gfx::Point(100, 100));
+        break;
+      case 4:
+        // End the pinch, but delay tile production.
+        playback_allowed_event_.Reset();
+        host_impl->PinchGestureEnd();
+        break;
+      case 5:
+        // Let tiles complete.
+        playback_allowed_event_.Signal();
+        break;
+    }
+  }
+
+  void NotifyTileStateChangedOnThread(LayerTreeHostImpl* host_impl,
+                                      const Tile* tile) override {
+    // On frame_ == 4, we are preventing texture uploads from completing,
+    // so this verifies they are not completing before frame_ == 5.
+    // Flaky failures here indicate we're failing to prevent uploads from
+    // completing.
+    EXPECT_NE(4, frame_);
+  }
+
+  void AfterTest() override {}
+
+  FakeContentLayerClient client_;
+  int frame_;
+  bool posted_;
+  base::WaitableEvent playback_allowed_event_;
+};
+
+// TODO(danakj): Disabled for flake: crbug.com/433208
+// MULTI_THREAD_TEST_F(LayerTreeHostTestCrispUpAfterPinchEnds);
+
+class LayerTreeHostTestCrispUpAfterPinchEndsWithOneCopy
+    : public LayerTreeHostTestCrispUpAfterPinchEnds {
+ protected:
+  void InitializeSettings(LayerTreeSettings* settings) override {
+    settings->impl_side_painting = true;
+    settings->use_one_copy = true;
+  }
+
+  scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface(
+      bool fallback) override {
+    scoped_ptr<TestWebGraphicsContext3D> context3d =
+        TestWebGraphicsContext3D::Create();
+    context3d->set_support_image(true);
+    context3d->set_support_sync_query(true);
+
+    if (delegating_renderer())
+      return FakeOutputSurface::CreateDelegating3d(context3d.Pass());
+    else
+      return FakeOutputSurface::Create3d(context3d.Pass());
+  }
+};
+
+// TODO(danakj): Disabled for flake: crbug.com/433208
+#if !defined(OS_LINUX) || defined(NDEBUG)
+MULTI_THREAD_TEST_F(LayerTreeHostTestCrispUpAfterPinchEndsWithOneCopy);
+#endif
+
+class LayerTreeHostTestContinuousDrawWhenCreatingVisibleTiles
+    : public LayerTreeHostTest {
+ protected:
+  LayerTreeHostTestContinuousDrawWhenCreatingVisibleTiles()
+      : playback_allowed_event_(true, true) {}
+
+  void InitializeSettings(LayerTreeSettings* settings) override {
+    settings->impl_side_painting = true;
+  }
+
+  void SetupTree() override {
+    step_ = 1;
+    continuous_draws_ = 0;
+    client_.set_fill_with_nonsolid_color(true);
+
+    scoped_refptr<Layer> root = Layer::Create();
+    root->SetBounds(gfx::Size(500, 500));
+
+    scoped_refptr<Layer> pinch = Layer::Create();
+    pinch->SetBounds(gfx::Size(500, 500));
+    pinch->SetScrollClipLayerId(root->id());
+    pinch->SetIsContainerForFixedPositionLayers(true);
+    root->AddChild(pinch);
+
+    scoped_ptr<FakePicturePile> pile(new FakePicturePile);
+    pile->SetPlaybackAllowedEvent(&playback_allowed_event_);
+    scoped_refptr<FakePictureLayer> layer =
+        FakePictureLayer::CreateWithRecordingSource(&client_, pile.Pass());
+    layer->SetBounds(gfx::Size(500, 500));
+    layer->SetContentsOpaque(true);
+    pinch->AddChild(layer);
+
+    layer_tree_host()->RegisterViewportLayers(root, pinch, pinch);
+    layer_tree_host()->SetPageScaleFactorAndLimits(1.f, 1.f, 4.f);
+    layer_tree_host()->SetRootLayer(root);
+    LayerTreeHostTest::SetupTree();
+  }
+
+  // Returns the delta scale of all quads in the frame's root pass from their
+  // ideal, or 0 if they are not all the same.
+  float FrameQuadScaleDeltaFromIdeal(LayerTreeHostImpl::FrameData* frame_data) {
+    if (frame_data->has_no_damage)
+      return 0.f;
+    float frame_scale = 0.f;
+    RenderPass* root_pass = frame_data->render_passes.back();
+    for (const auto& draw_quad : root_pass->quad_list) {
+      const TileDrawQuad* quad = TileDrawQuad::MaterialCast(draw_quad);
+      float quad_scale =
+          quad->tex_coord_rect.width() / static_cast<float>(quad->rect.width());
+      float transform_scale =
+          SkMScalarToFloat(quad->quadTransform().matrix().get(0, 0));
+      float scale = quad_scale / transform_scale;
+      if (frame_scale != 0.f && frame_scale != scale)
+        return 0.f;
+      frame_scale = scale;
+    }
+    return frame_scale;
+  }
+
+  void BeginTest() override { PostSetNeedsCommitToMainThread(); }
+
+  DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
+                                   LayerTreeHostImpl::FrameData* frame_data,
+                                   DrawResult draw_result) override {
+    float quad_scale_delta = FrameQuadScaleDeltaFromIdeal(frame_data);
+    switch (step_) {
+      case 1:
+        // Drew at scale 1 before any pinching.
+        EXPECT_EQ(1.f, host_impl->active_tree()->total_page_scale_factor());
+        EXPECT_EQ(1.f, quad_scale_delta);
+        break;
+      case 2:
+        if (quad_scale_delta != 1.f / 1.5f)
+          break;
+        // Drew at scale 1 still though the ideal is 1.5.
+        EXPECT_EQ(1.5f, host_impl->active_tree()->total_page_scale_factor());
+        EXPECT_EQ(1.f / 1.5f, quad_scale_delta);
+        break;
+      case 3:
+        // Continuous draws are attempted.
+        EXPECT_EQ(1.5f, host_impl->active_tree()->total_page_scale_factor());
+        if (!frame_data->has_no_damage)
+          EXPECT_EQ(1.f / 1.5f, quad_scale_delta);
+        break;
+      case 4:
+        if (quad_scale_delta != 1.f)
+          break;
+        // Drew at scale 1.5 when all the tiles completed.
+        EXPECT_EQ(1.5f, host_impl->active_tree()->total_page_scale_factor());
+        EXPECT_EQ(1.f, quad_scale_delta);
+
+        // We should not continue to draw any more. End the test after a timeout
+        // to watch for any extraneous draws.
+        // TODO(brianderson): We could remove this delay and instead wait until
+        // the BeginFrameSource decides it doesn't need to send frames anymore,
+        // or test that it already doesn't here.
+        EndTestAfterDelayMs(16 * 4);
+        ++step_;
+        break;
+      case 5:
+        ADD_FAILURE()
+            << "No draws should happen once we have a complete frame.";
+        break;
+    }
+    return draw_result;
+  }
+
+  void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override {
+    switch (step_) {
+      case 1:
+        // Delay tile production.
+        playback_allowed_event_.Reset();
+        // Pinch zoom in to cause new tiles to be required.
+        host_impl->PinchGestureBegin();
+        host_impl->PinchGestureUpdate(1.5f, gfx::Point(100, 100));
+        host_impl->PinchGestureEnd();
+        ++step_;
+        break;
+      case 2:
+        ++step_;
+        break;
+      case 3:
+        // We should continue to try draw while there are incomplete visible
+        // tiles.
+        if (++continuous_draws_ > 5) {
+          // Allow the tiles to complete.
+          playback_allowed_event_.Signal();
+          ++step_;
+        }
+        break;
+    }
+  }
+
+  void NotifyTileStateChangedOnThread(LayerTreeHostImpl* host_impl,
+                                      const Tile* tile) override {
+    // On step_ == 2, we are preventing texture uploads from completing,
+    // so this verifies they are not completing before step_ == 3.
+    // Flaky failures here indicate we're failing to prevent uploads from
+    // completing.
+    EXPECT_NE(2, step_);
+  }
+
+  void AfterTest() override { EXPECT_GT(continuous_draws_, 5); }
+
+  FakeContentLayerClient client_;
+  int step_;
+  int continuous_draws_;
+  base::WaitableEvent playback_allowed_event_;
+};
+
+MULTI_THREAD_TEST_F(LayerTreeHostTestContinuousDrawWhenCreatingVisibleTiles);
+
 }  // namespace cc
diff --git a/cc/trees/layer_tree_host_unittest_context.cc b/cc/trees/layer_tree_host_unittest_context.cc
index fb05300..dc34d3c 100644
--- a/cc/trees/layer_tree_host_unittest_context.cc
+++ b/cc/trees/layer_tree_host_unittest_context.cc
@@ -133,7 +133,7 @@
 
   void DidFailToInitializeOutputSurface() override { ++times_create_failed_; }
 
-  virtual void TearDown() override {
+  void TearDown() override {
     LayerTreeTest::TearDown();
     EXPECT_EQ(times_to_expect_create_failed_, times_create_failed_);
   }
diff --git a/cc/trees/layer_tree_host_unittest_damage.cc b/cc/trees/layer_tree_host_unittest_damage.cc
index d541751..d34cd4d 100644
--- a/cc/trees/layer_tree_host_unittest_damage.cc
+++ b/cc/trees/layer_tree_host_unittest_damage.cc
@@ -529,98 +529,5 @@
 
 MULTI_THREAD_TEST_F(LayerTreeHostDamageTestScrollbarCommitDoesNoDamage);
 
-class LayerTreeHostDamageTestVisibleTilesStillTriggerDraws
-    : public LayerTreeHostDamageTest {
-  void InitializeSettings(LayerTreeSettings* settings) override {
-    settings->impl_side_painting = true;
-  }
-
-  void BeginTest() override { PostSetNeedsCommitToMainThread(); }
-
-  void SetupTree() override {
-    scoped_refptr<FakePictureLayer> root = FakePictureLayer::Create(&client_);
-    root->SetBounds(gfx::Size(500, 500));
-    layer_tree_host()->SetRootLayer(root);
-    LayerTreeHostDamageTest::SetupTree();
-
-    swap_count_ = 0;
-    prepare_to_draw_count_ = 0;
-    update_visible_tile_count_ = 0;
-  }
-
-  DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
-                                   LayerTreeHostImpl::FrameData* frame_data,
-                                   DrawResult draw_result) override {
-    EXPECT_EQ(DRAW_SUCCESS, draw_result);
-    prepare_to_draw_count_++;
-    switch (prepare_to_draw_count_) {
-      case 1:
-        // Detect that we have an incomplete tile, during the first frame.
-        // The first frame should have damage.
-        frame_data->contains_incomplete_tile = true;
-        DCHECK(!frame_data->has_no_damage);
-        break;
-      case 2:
-        // Make a no-damage frame. We early out and can't detect
-        // incomplete tiles, even if they still exist.
-        frame_data->contains_incomplete_tile = false;
-        frame_data->has_no_damage = true;
-        break;
-      case 3:
-        // Trigger the last swap for the completed tile.
-        frame_data->contains_incomplete_tile = false;
-        frame_data->has_no_damage = false;
-        EndTest();
-        break;
-      default:
-        NOTREACHED();
-        break;
-    }
-
-    return draw_result;
-  }
-
-  void UpdateVisibleTilesOnThread(LayerTreeHostImpl* host_impl) override {
-    // Simulate creating some visible tiles (that trigger prepare-to-draws).
-    // The first we make into a no-damage-frame during prepare-to-draw (see
-    // above). This is to ensure we still get UpdateVisibleTiles calls after
-    // a no-damage or aborted frame.
-    update_visible_tile_count_++;
-    switch (update_visible_tile_count_) {
-      case 3:
-      case 6:
-        host_impl->DidInitializeVisibleTileForTesting();
-        break;
-      case 7:
-        NOTREACHED();
-        break;
-    }
-  }
-
-  void SwapBuffersOnThread(LayerTreeHostImpl* host_impl,
-                           bool didSwap) override {
-    if (!didSwap)
-      return;
-    ++swap_count_;
-  }
-
-  void AfterTest() override {
-    // We should keep getting update-visible-tiles calls
-    // until we report there are no more incomplete-tiles.
-    EXPECT_EQ(update_visible_tile_count_, 6);
-    // First frame, plus two triggered by DidInitializeVisibleTile()
-    EXPECT_EQ(prepare_to_draw_count_, 3);
-    // First swap, plus final swap (contained damage).
-    EXPECT_EQ(swap_count_, 2);
-  }
-
-  FakeContentLayerClient client_;
-  int swap_count_;
-  int prepare_to_draw_count_;
-  int update_visible_tile_count_;
-};
-
-MULTI_THREAD_TEST_F(LayerTreeHostDamageTestVisibleTilesStillTriggerDraws);
-
 }  // namespace
 }  // namespace cc
diff --git a/cc/trees/occlusion_tracker_unittest.cc b/cc/trees/occlusion_tracker_unittest.cc
index 75cd243..56d830f 100644
--- a/cc/trees/occlusion_tracker_unittest.cc
+++ b/cc/trees/occlusion_tracker_unittest.cc
@@ -174,7 +174,7 @@
 
   virtual void RunMyTest() = 0;
 
-  virtual void TearDown() { DestroyLayers(); }
+  void TearDown() override { DestroyLayers(); }
 
   typename Types::HostType* GetHost();
 
diff --git a/cc/trees/single_thread_proxy.cc b/cc/trees/single_thread_proxy.cc
index f15c7ec..4cb0a9e 100644
--- a/cc/trees/single_thread_proxy.cc
+++ b/cc/trees/single_thread_proxy.cc
@@ -383,12 +383,6 @@
   SetNeedsRedrawOnImplThread();
 }
 
-void SingleThreadProxy::DidInitializeVisibleTileOnImplThread() {
-  TRACE_EVENT0("cc", "SingleThreadProxy::DidInitializeVisibleTileOnImplThread");
-  if (scheduler_on_impl_thread_)
-    scheduler_on_impl_thread_->SetNeedsRedraw();
-}
-
 void SingleThreadProxy::SetNeedsCommitOnImplThread() {
   client_->ScheduleComposite();
   if (scheduler_on_impl_thread_)
@@ -753,11 +747,6 @@
   DoAnimate();
 }
 
-void SingleThreadProxy::ScheduledActionUpdateVisibleTiles() {
-  DebugScopedSetImplThread impl(this);
-  layer_tree_host_impl_->UpdateVisibleTiles();
-}
-
 void SingleThreadProxy::ScheduledActionActivateSyncTree() {
   DebugScopedSetImplThread impl(this);
   layer_tree_host_impl_->ActivateSyncTree();
diff --git a/cc/trees/single_thread_proxy.h b/cc/trees/single_thread_proxy.h
index fa300de..e4cf793 100644
--- a/cc/trees/single_thread_proxy.h
+++ b/cc/trees/single_thread_proxy.h
@@ -67,7 +67,6 @@
   DrawResult ScheduledActionDrawAndSwapForced() override;
   void ScheduledActionCommit() override;
   void ScheduledActionAnimate() override;
-  void ScheduledActionUpdateVisibleTiles() override;
   void ScheduledActionActivateSyncTree() override;
   void ScheduledActionBeginOutputSurfaceCreation() override;
   void ScheduledActionManageTiles() override;
@@ -93,7 +92,6 @@
   void SetNeedsRedrawRectOnImplThread(const gfx::Rect& dirty_rect) override;
   void SetNeedsAnimateOnImplThread() override;
   void SetNeedsManageTilesOnImplThread() override;
-  void DidInitializeVisibleTileOnImplThread() override;
   void SetNeedsCommitOnImplThread() override;
   void PostAnimationEventsToMainThreadOnImplThread(
       scoped_ptr<AnimationEventsVector> events) override;
diff --git a/cc/trees/thread_proxy.cc b/cc/trees/thread_proxy.cc
index 0f7a2a3..bd85f01 100644
--- a/cc/trees/thread_proxy.cc
+++ b/cc/trees/thread_proxy.cc
@@ -479,23 +479,6 @@
   SetNeedsRedrawOnImplThread();
 }
 
-void ThreadProxy::SetSwapUsedIncompleteTileOnImplThread(
-    bool used_incomplete_tile) {
-  DCHECK(IsImplThread());
-  if (used_incomplete_tile) {
-    TRACE_EVENT_INSTANT0("cc",
-                         "ThreadProxy::SetSwapUsedIncompleteTileOnImplThread",
-                         TRACE_EVENT_SCOPE_THREAD);
-  }
-  impl().scheduler->SetSwapUsedIncompleteTile(used_incomplete_tile);
-}
-
-void ThreadProxy::DidInitializeVisibleTileOnImplThread() {
-  TRACE_EVENT0("cc", "ThreadProxy::DidInitializeVisibleTileOnImplThread");
-  DCHECK(IsImplThread());
-  impl().scheduler->SetNeedsRedraw();
-}
-
 void ThreadProxy::MainThreadHasStoppedFlinging() {
   DCHECK(IsMainThread());
   Proxy::ImplThreadTaskRunner()->PostTask(
@@ -989,12 +972,6 @@
   impl().timing_history.DidCommit();
 }
 
-void ThreadProxy::ScheduledActionUpdateVisibleTiles() {
-  TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionUpdateVisibleTiles");
-  DCHECK(IsImplThread());
-  impl().layer_tree_host_impl->UpdateVisibleTiles();
-}
-
 void ThreadProxy::ScheduledActionActivateSyncTree() {
   TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionActivateSyncTree");
   DCHECK(IsImplThread());
@@ -1055,15 +1032,8 @@
   bool start_ready_animations = draw_frame;
   impl().layer_tree_host_impl->UpdateAnimationState(start_ready_animations);
 
-  if (draw_frame) {
-    bool did_request_swap = impl().layer_tree_host_impl->SwapBuffers(frame);
-
-    // We don't know if we have incomplete tiles if we didn't actually swap.
-    if (did_request_swap) {
-      DCHECK(!frame.has_no_damage);
-      SetSwapUsedIncompleteTileOnImplThread(frame.contains_incomplete_tile);
-    }
-  }
+  if (draw_frame)
+    impl().layer_tree_host_impl->SwapBuffers(frame);
 
   // Tell the main thread that the the newly-commited frame was drawn.
   if (impl().next_frame_is_newly_committed_frame) {
diff --git a/cc/trees/thread_proxy.h b/cc/trees/thread_proxy.h
index adccf72..a1064ab 100644
--- a/cc/trees/thread_proxy.h
+++ b/cc/trees/thread_proxy.h
@@ -195,7 +195,6 @@
   void SetNeedsRedrawRectOnImplThread(const gfx::Rect& dirty_rect) override;
   void SetNeedsAnimateOnImplThread() override;
   void SetNeedsManageTilesOnImplThread() override;
-  void DidInitializeVisibleTileOnImplThread() override;
   void SetNeedsCommitOnImplThread() override;
   void PostAnimationEventsToMainThreadOnImplThread(
       scoped_ptr<AnimationEventsVector> queue) override;
@@ -215,7 +214,6 @@
   DrawResult ScheduledActionDrawAndSwapForced() override;
   void ScheduledActionAnimate() override;
   void ScheduledActionCommit() override;
-  void ScheduledActionUpdateVisibleTiles() override;
   void ScheduledActionActivateSyncTree() override;
   void ScheduledActionBeginOutputSurfaceCreation() override;
   void ScheduledActionManageTiles() override;
diff --git a/gin/v8.isolate b/gin/v8.isolate
index 14d8a2c..a47dd9e 100644
--- a/gin/v8.isolate
+++ b/gin/v8.isolate
@@ -5,7 +5,7 @@
   'conditions': [
     ['v8_use_external_startup_data==1', {
       'variables': {
-        'isolate_dependency_tracked': [
+        'files': [
           '<(PRODUCT_DIR)/natives_blob.bin',
           '<(PRODUCT_DIR)/snapshot_blob.bin',
         ],
diff --git a/gpu/command_buffer/client/fenced_allocator.cc b/gpu/command_buffer/client/fenced_allocator.cc
index 8003857..6db6e50 100644
--- a/gpu/command_buffer/client/fenced_allocator.cc
+++ b/gpu/command_buffer/client/fenced_allocator.cc
@@ -14,23 +14,22 @@
 
 namespace {
 
-// Allocation alignment, must be a power of two.
-const unsigned int kAllocAlignment = 16;
-
 // Round down to the largest multiple of kAllocAlignment no greater than |size|.
 unsigned int RoundDown(unsigned int size) {
-  return size & ~(kAllocAlignment - 1);
+  return size & ~(FencedAllocator::kAllocAlignment - 1);
 }
 
 // Round up to the smallest multiple of kAllocAlignment no smaller than |size|.
 unsigned int RoundUp(unsigned int size) {
-  return (size + (kAllocAlignment - 1)) & ~(kAllocAlignment - 1);
+  return (size + (FencedAllocator::kAllocAlignment - 1)) &
+      ~(FencedAllocator::kAllocAlignment - 1);
 }
 
 }  // namespace
 
 #ifndef _MSC_VER
 const FencedAllocator::Offset FencedAllocator::kInvalidOffset;
+const unsigned int FencedAllocator::kAllocAlignment;
 #endif
 
 FencedAllocator::FencedAllocator(unsigned int size,
diff --git a/gpu/command_buffer/client/fenced_allocator.h b/gpu/command_buffer/client/fenced_allocator.h
index 8e222e1..578870d 100644
--- a/gpu/command_buffer/client/fenced_allocator.h
+++ b/gpu/command_buffer/client/fenced_allocator.h
@@ -35,6 +35,9 @@
   // Invalid offset, returned by Alloc in case of failure.
   static const Offset kInvalidOffset = 0xffffffffU;
 
+  // Allocation alignment, must be a power of two.
+  static const unsigned int kAllocAlignment = 16;
+
   // Creates a FencedAllocator. Note that the size of the buffer is passed, but
   // not its base address: everything is handled as offsets into the buffer.
   FencedAllocator(unsigned int size,
diff --git a/gpu/command_buffer/client/mapped_memory.cc b/gpu/command_buffer/client/mapped_memory.cc
index fc6ca5d..1919879 100644
--- a/gpu/command_buffer/client/mapped_memory.cc
+++ b/gpu/command_buffer/client/mapped_memory.cc
@@ -26,7 +26,7 @@
 MappedMemoryManager::MappedMemoryManager(CommandBufferHelper* helper,
                                          const base::Closure& poll_callback,
                                          size_t unused_memory_reclaim_limit)
-    : chunk_size_multiple_(1),
+    : chunk_size_multiple_(FencedAllocator::kAllocAlignment),
       helper_(helper),
       poll_callback_(poll_callback),
       allocated_memory_(0),
diff --git a/gpu/command_buffer/client/mapped_memory.h b/gpu/command_buffer/client/mapped_memory.h
index 789e69c..10ac639 100644
--- a/gpu/command_buffer/client/mapped_memory.h
+++ b/gpu/command_buffer/client/mapped_memory.h
@@ -135,6 +135,7 @@
   }
 
   void set_chunk_size_multiple(unsigned int multiple) {
+    DCHECK(multiple % FencedAllocator::kAllocAlignment == 0);
     chunk_size_multiple_ = multiple;
   }
 
@@ -201,4 +202,3 @@
 }  // namespace gpu
 
 #endif  // GPU_COMMAND_BUFFER_CLIENT_MAPPED_MEMORY_H_
-
diff --git a/gpu/command_buffer/service/feature_info.cc b/gpu/command_buffer/service/feature_info.cc
index 24e1f92..6dd1f34 100644
--- a/gpu/command_buffer/service/feature_info.cc
+++ b/gpu/command_buffer/service/feature_info.cc
@@ -848,6 +848,9 @@
   if (workarounds_.disable_egl_khr_fence_sync) {
     gfx::g_driver_egl.ext.b_EGL_KHR_fence_sync = false;
   }
+  if (workarounds_.disable_egl_khr_wait_sync) {
+    gfx::g_driver_egl.ext.b_EGL_KHR_wait_sync = false;
+  }
 #endif
   if (workarounds_.disable_arb_sync)
     gfx::g_driver_gl.ext.b_GL_ARB_sync = false;
@@ -855,12 +858,14 @@
   UMA_HISTOGRAM_BOOLEAN("GPU.FenceSupport", ui_gl_fence_works);
 
   feature_flags_.map_buffer_range =
-      is_es3 || extensions.Contains("GL_ARB_map_buffer_range");
+      is_es3 || extensions.Contains("GL_ARB_map_buffer_range") ||
+      extensions.Contains("GL_EXT_map_buffer_range");
 
   // Really it's part of core OpenGL 2.1 and up, but let's assume the
   // extension is still advertised.
   bool has_pixel_buffers =
-      is_es3 || extensions.Contains("GL_ARB_pixel_buffer_object");
+      is_es3 || extensions.Contains("GL_ARB_pixel_buffer_object") ||
+      extensions.Contains("GL_NV_pixel_buffer_object");
 
   // We will use either glMapBuffer() or glMapBufferRange() for async readbacks.
   if (has_pixel_buffers && ui_gl_fence_works &&
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index 4d54739..5dd9f64 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -7578,6 +7578,11 @@
     } else {
       data = glMapBuffer(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY);
     }
+    if (!data) {
+      LOCAL_SET_GL_ERROR(GL_OUT_OF_MEMORY, "glMapBuffer",
+                         "Unable to map memory for readback.");
+      return;
+    }
     memcpy(pixels, data, pixels_size);
     // GL_PIXEL_PACK_BUFFER_ARB is currently unused, so we don't
     // have to restore the state.
@@ -7779,7 +7784,10 @@
       GLuint buffer = 0;
       glGenBuffersARB(1, &buffer);
       glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, buffer);
-      glBufferData(GL_PIXEL_PACK_BUFFER_ARB, pixels_size, NULL, GL_STREAM_READ);
+      // For ANGLE client version 2, GL_STREAM_READ is not available.
+      const GLenum usage_hint =
+          features().is_angle ? GL_STATIC_DRAW : GL_STREAM_READ;
+      glBufferData(GL_PIXEL_PACK_BUFFER_ARB, pixels_size, NULL, usage_hint);
       GLenum error = glGetError();
       if (error == GL_NO_ERROR) {
         glReadPixels(x, y, width, height, format, type, 0);
diff --git a/gpu/config/gpu_driver_bug_list_json.cc b/gpu/config/gpu_driver_bug_list_json.cc
index c9b5335..e1e9650 100644
--- a/gpu/config/gpu_driver_bug_list_json.cc
+++ b/gpu/config/gpu_driver_bug_list_json.cc
@@ -19,7 +19,7 @@
 {
   "name": "gpu driver bug list",
   // Please update the version number whenever you change this file.
-  "version": "7.7",
+  "version": "7.8",
   "entries": [
     {
       "id": 1,
@@ -1046,6 +1046,27 @@
       "features": [
         "disable_async_readpixels"
       ]
+    },
+    {
+      "id": 94,
+      "description": "Disable EGL_KHR_wait_sync on NVIDIA with GLES 3.1",
+      "cr_bugs": [433057],
+      "os": {
+        "type": "android",
+        "version": {
+          "op": "<=",
+          "value": "5.0.0"
+        }
+      },
+      "gl_vendor": "NVIDIA.*",
+      "gl_type": "gles",
+      "gl_version": {
+        "op": "=",
+        "value": "3.1"
+      },
+      "features": [
+        "disable_egl_khr_wait_sync"
+      ]
     }
   ]
 }
diff --git a/gpu/config/gpu_driver_bug_workaround_type.h b/gpu/config/gpu_driver_bug_workaround_type.h
index 871798e..0cd9761 100644
--- a/gpu/config/gpu_driver_bug_workaround_type.h
+++ b/gpu/config/gpu_driver_bug_workaround_type.h
@@ -28,6 +28,8 @@
          disable_depth_texture)                              \
   GPU_OP(DISABLE_EGL_KHR_FENCE_SYNC,                         \
          disable_egl_khr_fence_sync)                         \
+  GPU_OP(DISABLE_EGL_KHR_WAIT_SYNC,                          \
+         disable_egl_khr_wait_sync)                          \
   GPU_OP(DISABLE_EXT_DISCARD_FRAMEBUFFER,                    \
          disable_ext_discard_framebuffer)                    \
   GPU_OP(DISABLE_EXT_DRAW_BUFFERS,                           \
diff --git a/mojo/tools/roll/cc_strip_video.patch b/mojo/tools/roll/cc_strip_video.patch
index 07c6fae..90bb220 100644
--- a/mojo/tools/roll/cc_strip_video.patch
+++ b/mojo/tools/roll/cc_strip_video.patch
@@ -1,8 +1,8 @@
 diff --git a/cc/BUILD.gn b/cc/BUILD.gn
-index 9b417f0..f753895 100644
+index a296bb0..ab3aab4 100644
 --- a/cc/BUILD.gn
 +++ b/cc/BUILD.gn
-@@ -208,13 +208,6 @@ component("cc") {
+@@ -212,13 +212,6 @@ component("cc") {
      "layers/ui_resource_layer.h",
      "layers/ui_resource_layer_impl.cc",
      "layers/ui_resource_layer_impl.h",
@@ -16,7 +16,7 @@
      "output/begin_frame_args.cc",
      "output/begin_frame_args.h",
      "output/bsp_tree.cc",
-@@ -427,8 +420,6 @@ component("cc") {
+@@ -429,8 +422,6 @@ component("cc") {
      "resources/ui_resource_client.h",
      "resources/ui_resource_request.cc",
      "resources/ui_resource_request.h",
@@ -25,7 +25,7 @@
      "resources/zero_copy_raster_worker_pool.cc",
      "resources/zero_copy_raster_worker_pool.h",
      "scheduler/begin_frame_source.cc",
-@@ -490,7 +481,6 @@ component("cc") {
+@@ -492,7 +483,6 @@ component("cc") {
      "//gpu",
      "//gpu/command_buffer/client:gles2_interface",
      "//gpu/command_buffer/client:gpu_memory_buffer_manager",
@@ -33,7 +33,7 @@
      "//ui/events:events_base",
      "//ui/gfx",
      "//ui/gfx/geometry",
-@@ -559,8 +549,6 @@ source_set("test_support") {
+@@ -563,8 +553,6 @@ source_set("test_support") {
      "test/fake_tile_manager_client.h",
      "test/fake_ui_resource_layer_tree_host_impl.cc",
      "test/fake_ui_resource_layer_tree_host_impl.h",
@@ -42,7 +42,7 @@
      "test/geometry_test_utils.cc",
      "test/geometry_test_utils.h",
      "test/test_in_process_context_provider.cc",
-@@ -713,7 +701,6 @@ test("cc_unittests") {
+@@ -717,7 +705,6 @@ test("cc_unittests") {
      "layers/tiled_layer_unittest.cc",
      "layers/ui_resource_layer_impl_unittest.cc",
      "layers/ui_resource_layer_unittest.cc",
@@ -50,7 +50,7 @@
      "output/begin_frame_args_unittest.cc",
      "output/delegating_renderer_unittest.cc",
      "output/filter_operations_unittest.cc",
-@@ -743,7 +730,6 @@ test("cc_unittests") {
+@@ -747,7 +734,6 @@ test("cc_unittests") {
      "resources/texture_uploader_unittest.cc",
      "resources/tile_manager_unittest.cc",
      "resources/tile_priority_unittest.cc",
@@ -58,7 +58,7 @@
      "scheduler/begin_frame_source_unittest.cc",
      "scheduler/delay_based_time_source_unittest.cc",
      "scheduler/scheduler_state_machine_unittest.cc",
-@@ -772,7 +758,6 @@ test("cc_unittests") {
+@@ -776,7 +762,6 @@ test("cc_unittests") {
      "trees/layer_tree_host_unittest_picture.cc",
      "trees/layer_tree_host_unittest_proxy.cc",
      "trees/layer_tree_host_unittest_scroll.cc",
@@ -66,7 +66,7 @@
      "trees/layer_tree_impl_unittest.cc",
      "trees/occlusion_tracker_unittest.cc",
      "trees/occlusion_unittest.cc",
-@@ -799,7 +784,6 @@ test("cc_unittests") {
+@@ -803,7 +788,6 @@ test("cc_unittests") {
      "//gpu:test_support",
      "//gpu/command_buffer/client:gles2_interface",
      "//gpu/command_buffer/common:gles2_utils",
@@ -74,7 +74,7 @@
      "//testing/gmock",
      "//testing/gtest",
      "//ui/events:events_base",
-@@ -831,7 +815,6 @@ test("cc_perftests") {
+@@ -835,7 +819,6 @@ test("cc_perftests") {
      "//gpu",
      "//gpu:test_support",
      "//gpu/command_buffer/common:gles2_utils",
@@ -253,7 +253,7 @@
 -
 -}  // namespace cc
 diff --git a/cc/output/gl_renderer.cc b/cc/output/gl_renderer.cc
-index a472475..4eb1324 100644
+index 75dcfe8..cb6189e 100644
 --- a/cc/output/gl_renderer.cc
 +++ b/cc/output/gl_renderer.cc
 @@ -13,7 +13,6 @@
@@ -265,7 +265,7 @@
  #include "cc/output/compositor_frame_metadata.h"
  #include "cc/output/context_provider.h"
 diff --git a/cc/output/renderer_pixeltest.cc b/cc/output/renderer_pixeltest.cc
-index c172869..a0ce823 100644
+index 0c2bc3d..d112ed1 100644
 --- a/cc/output/renderer_pixeltest.cc
 +++ b/cc/output/renderer_pixeltest.cc
 @@ -12,7 +12,6 @@
@@ -421,7 +421,7 @@
 -                     color_space);
 -  }
 -
--  virtual void SetUp() override {
+-  void SetUp() override {
 -    GLRendererPixelTest::SetUp();
 -    video_resource_updater_.reset(new VideoResourceUpdater(
 -        output_surface_->context_provider(), resource_provider_.get()));
@@ -636,7 +636,7 @@
  
  namespace cc {
 diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
-index 9395639..5d2d939 100644
+index e128013..0b9d976 100644
 --- a/cc/trees/layer_tree_host_impl_unittest.cc
 +++ b/cc/trees/layer_tree_host_impl_unittest.cc
 @@ -27,7 +27,6 @@
@@ -671,7 +671,7 @@
  
  namespace cc {
  namespace {
-@@ -95,7 +91,6 @@ class LayerTreeHostImplTest : public testing::Test,
+@@ -94,7 +90,6 @@ class LayerTreeHostImplTest : public testing::Test,
          reduce_memory_result_(true),
          current_limit_bytes_(0),
          current_priority_cutoff_value_(0) {
@@ -679,7 +679,7 @@
    }
  
    LayerTreeSettings DefaultSettings() {
-@@ -5066,18 +5061,6 @@ TEST_F(LayerTreeHostImplTest, LayersFreeTextures) {
+@@ -5151,18 +5146,6 @@ TEST_F(LayerTreeHostImplTest, LayersFreeTextures) {
        LayerImpl::Create(host_impl_->active_tree(), 1);
    root_layer->SetBounds(gfx::Size(10, 10));
  
@@ -698,7 +698,7 @@
    scoped_ptr<IOSurfaceLayerImpl> io_surface_layer =
        IOSurfaceLayerImpl::Create(host_impl_->active_tree(), 5);
    io_surface_layer->SetBounds(gfx::Size(10, 10));
-@@ -6139,16 +6122,6 @@ TEST_F(LayerTreeHostImplTest,
+@@ -6225,16 +6208,6 @@ TEST_F(LayerTreeHostImplTest,
    scoped_ptr<SolidColorLayerImpl> root_layer =
        SolidColorLayerImpl::Create(host_impl_->active_tree(), 1);
  
@@ -716,7 +716,7 @@
    EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
    host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
 diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc
-index aedd0d9..0859d86 100644
+index 2abf6d3..b0ce5a5 100644
 --- a/cc/trees/layer_tree_host_unittest.cc
 +++ b/cc/trees/layer_tree_host_unittest.cc
 @@ -18,7 +18,6 @@
@@ -727,15 +727,15 @@
  #include "cc/output/begin_frame_args.h"
  #include "cc/output/compositor_frame_ack.h"
  #include "cc/output/copy_output_request.h"
-@@ -39,7 +38,6 @@
- #include "cc/test/fake_picture_layer_impl.h"
+@@ -41,7 +40,6 @@
+ #include "cc/test/fake_picture_pile.h"
  #include "cc/test/fake_proxy.h"
  #include "cc/test/fake_scoped_ui_resource.h"
 -#include "cc/test/fake_video_frame_provider.h"
  #include "cc/test/geometry_test_utils.h"
  #include "cc/test/layer_tree_test.h"
  #include "cc/test/test_shared_bitmap_manager.h"
-@@ -3972,28 +3970,6 @@ class LayerInvalidateCausesDraw : public LayerTreeHostTest {
+@@ -4149,28 +4147,6 @@ class LayerInvalidateCausesDraw : public LayerTreeHostTest {
    int num_draws_;
  };
  
@@ -765,7 +765,7 @@
  // to the compositor thread, even though no resources are updated in
  // response to that invalidation.
 diff --git a/cc/trees/layer_tree_host_unittest_context.cc b/cc/trees/layer_tree_host_unittest_context.cc
-index b12a8da..fb05300 100644
+index 134d928..dc34d3c 100644
 --- a/cc/trees/layer_tree_host_unittest_context.cc
 +++ b/cc/trees/layer_tree_host_unittest_context.cc
 @@ -15,8 +15,6 @@
diff --git a/net/BUILD.gn b/net/BUILD.gn
index 3bd06bc..be0ac53 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -473,6 +473,8 @@
     # doesn't set USE_NSS but needs some of the files.
     set_sources_assignment_filter([])
     sources += [
+      "base/net_util_mac.cc",
+      "base/net_util_mac.h",
       "base/network_change_notifier_mac.cc",
       "base/network_config_watcher_mac.cc",
       "base/platform_mime_util_mac.mm",
@@ -506,6 +508,8 @@
       "base/platform_mime_util_linux.cc",
       "base/address_tracker_linux.cc",
       "base/address_tracker_linux.h",
+      "base/net_util_linux.cc",
+      "base/net_util_linux.h"
     ]
     set_sources_assignment_filter(sources_assignment_filter)
 
diff --git a/net/base/net_info_source_list.h b/net/base/net_info_source_list.h
index be3019e..107840b 100644
--- a/net/base/net_info_source_list.h
+++ b/net/base/net_info_source_list.h
@@ -20,3 +20,4 @@
 NET_INFO_SOURCE(SPDY_ALT_PROTO_MAPPINGS, "spdyAlternateProtocolMappings",
                                                                          1 << 7)
 NET_INFO_SOURCE(HTTP_CACHE, "httpCacheInfo",                             1 << 8)
+NET_INFO_SOURCE(SDCH, "sdchInfo",                                        1 << 9)
diff --git a/net/base/net_log_event_type_list.h b/net/base/net_log_event_type_list.h
index 6dfe8c6..af7c290 100644
--- a/net/base/net_log_event_type_list.h
+++ b/net/base/net_log_event_type_list.h
@@ -2363,3 +2363,38 @@
 // This event is created (in a source of the same name) when the internal DNS
 // resolver creates a UDP socket to check for global IPv6 connectivity.
 EVENT_TYPE(IPV6_REACHABILITY_CHECK)
+
+// ------------------------------------------------------------------------
+// SDCH
+// ------------------------------------------------------------------------
+
+// This event is created when some problem occurs during sdch-encoded resource
+// handling. It contains the following parameters:
+//   {
+//     "sdch_problem_code": <SDCH problem code>,
+//     "net_error": <Always ERR_FAILED, present just to indicate this is a
+//                   failure>,
+//   }
+EVENT_TYPE(SDCH_DECODING_ERROR)
+
+// This event is created when SdchFilter initialization fails due to the
+// response corruption. It contains the following parameters:
+//   {
+//     "cause": <Response corruption detection cause>,
+//     "cached": <True if response was read from cache>,
+//   }
+EVENT_TYPE(SDCH_RESPONSE_CORRUPTION_DETECTION)
+
+// This event is created when some problem occurs during sdch dictionary fetch.
+// It contains the following parameters:
+//   {
+//     "dictionary_url": <Dictionary url>,
+//     "sdch_problem_code": <SDCH problem code>,
+//     "net_error": <Only present on unexpected errors. Always ERR_FAILED when
+//                   present. Used to indicate this is a real failure>,
+//   }
+EVENT_TYPE(SDCH_DICTIONARY_ERROR)
+
+// This event is created when SdchDictionaryFetcher starts fetch.  It contains
+// no parameters.
+EVENT_TYPE(SDCH_DICTIONARY_FETCH)
diff --git a/net/base/net_log_util.cc b/net/base/net_log_util.cc
index b8816ba..a15e899 100644
--- a/net/base/net_log_util.cc
+++ b/net/base/net_log_util.cc
@@ -15,6 +15,7 @@
 #include "net/base/load_states.h"
 #include "net/base/net_errors.h"
 #include "net/base/net_log.h"
+#include "net/base/sdch_manager.h"
 #include "net/disk_cache/disk_cache.h"
 #include "net/dns/host_cache.h"
 #include "net/dns/host_resolver.h"
@@ -66,6 +67,14 @@
 #undef NET_ERROR
 };
 
+const StringToConstant kSdchProblems[] = {
+#define SDCH_PROBLEM_CODE(label, value) \
+  { #label, value }                     \
+  ,
+#include "net/base/sdch_problem_code_list.h"
+#undef SDCH_PROBLEM_CODE
+};
+
 const char* NetInfoSourceToString(NetInfoSource source) {
   switch (source) {
     #define NET_INFO_SOURCE(label, string, value) \
@@ -187,6 +196,17 @@
     constants_dict->Set("quicRstStreamError", dict);
   }
 
+  // Add information on the relationship between SDCH problem codes and their
+  // symbolic names.
+  {
+    base::DictionaryValue* dict = new base::DictionaryValue();
+
+    for (size_t i = 0; i < arraysize(kSdchProblems); i++)
+      dict->SetInteger(kSdchProblems[i].name, kSdchProblems[i].constant);
+
+    constants_dict->Set("sdchProblemCode", dict);
+  }
+
   // Information about the relationship between event phase enums and their
   // symbolic names.
   {
@@ -455,6 +475,17 @@
                        info_dict);
   }
 
+  if (info_sources & NET_INFO_SDCH) {
+    base::Value* info_dict;
+    SdchManager* sdch_manager = context->sdch_manager();
+    if (sdch_manager) {
+      info_dict = sdch_manager->SdchInfoToValue();
+    } else {
+      info_dict = new base::DictionaryValue();
+    }
+    net_info_dict->Set(NetInfoSourceToString(NET_INFO_SDCH), info_dict);
+  }
+
   return net_info_dict.Pass();
 }
 
diff --git a/net/base/net_util_linux.cc b/net/base/net_util_linux.cc
new file mode 100644
index 0000000..e4e0f7f
--- /dev/null
+++ b/net/base/net_util_linux.cc
@@ -0,0 +1,154 @@
+// Copyright (c) 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 "net/base/net_util_linux.h"
+
+#include <net/if.h>
+#include <netinet/in.h>
+#include <set>
+#include <sys/types.h>
+
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_tokenizer.h"
+#include "base/strings/string_util.h"
+#include "base/threading/thread_restrictions.h"
+#include "net/base/address_tracker_linux.h"
+#include "net/base/escape.h"
+#include "net/base/ip_endpoint.h"
+#include "net/base/net_errors.h"
+#include "net/base/net_util_posix.h"
+#include "url/gurl.h"
+
+namespace net {
+
+namespace {
+
+// When returning true, the platform native IPv6 address attributes were
+// successfully converted to net IP address attributes. Otherwise, returning
+// false and the caller should drop the IP address which can't be used by the
+// application layer.
+bool TryConvertNativeToNetIPAttributes(int native_attributes,
+                                       int* net_attributes) {
+  // For Linux/ChromeOS/Android, we disallow addresses with attributes
+  // IFA_F_OPTIMISTIC, IFA_F_DADFAILED, and IFA_F_TENTATIVE as these
+  // are still progressing through duplicated address detection (DAD)
+  // and shouldn't be used by the application layer until DAD process
+  // is completed.
+  if (native_attributes & (
+#if !defined(OS_ANDROID)
+                              IFA_F_OPTIMISTIC | IFA_F_DADFAILED |
+#endif  // !OS_ANDROID
+                              IFA_F_TENTATIVE)) {
+    return false;
+  }
+
+  if (native_attributes & IFA_F_TEMPORARY) {
+    *net_attributes |= IP_ADDRESS_ATTRIBUTE_TEMPORARY;
+  }
+
+  if (native_attributes & IFA_F_DEPRECATED) {
+    *net_attributes |= IP_ADDRESS_ATTRIBUTE_DEPRECATED;
+  }
+
+  return true;
+}
+
+}  // namespace
+
+namespace internal {
+
+inline const unsigned char* GetIPAddressData(const IPAddressNumber& ip) {
+#if defined(OS_ANDROID)
+  return ip.begin();
+#else
+  return ip.data();
+#endif
+}
+
+bool GetNetworkListImpl(
+    NetworkInterfaceList* networks,
+    int policy,
+    const base::hash_set<int>& online_links,
+    const internal::AddressTrackerLinux::AddressMap& address_map,
+    GetInterfaceNameFunction get_interface_name) {
+  std::map<int, std::string> ifnames;
+
+  for (internal::AddressTrackerLinux::AddressMap::const_iterator it =
+           address_map.begin();
+       it != address_map.end(); ++it) {
+    // Ignore addresses whose links are not online.
+    if (online_links.find(it->second.ifa_index) == online_links.end())
+      continue;
+
+    sockaddr_storage sock_addr;
+    socklen_t sock_len = sizeof(sockaddr_storage);
+
+    // Convert to sockaddr for next check.
+    if (!IPEndPoint(it->first, 0)
+             .ToSockAddr(reinterpret_cast<sockaddr*>(&sock_addr), &sock_len)) {
+      continue;
+    }
+
+    // Skip unspecified addresses (i.e. made of zeroes) and loopback addresses
+    if (IsLoopbackOrUnspecifiedAddress(reinterpret_cast<sockaddr*>(&sock_addr)))
+      continue;
+
+    int ip_attributes = IP_ADDRESS_ATTRIBUTE_NONE;
+
+    if (it->second.ifa_family == AF_INET6) {
+      // Ignore addresses whose attributes are not actionable by
+      // the application layer.
+      if (!TryConvertNativeToNetIPAttributes(it->second.ifa_flags,
+                                             &ip_attributes))
+        continue;
+    }
+
+    // Find the name of this link.
+    std::map<int, std::string>::const_iterator itname =
+        ifnames.find(it->second.ifa_index);
+    std::string ifname;
+    if (itname == ifnames.end()) {
+      char buffer[IF_NAMESIZE] = {0};
+      if (get_interface_name(it->second.ifa_index, buffer)) {
+        ifname = ifnames[it->second.ifa_index] = buffer;
+      } else {
+        // Ignore addresses whose interface name can't be retrieved.
+        continue;
+      }
+    } else {
+      ifname = itname->second;
+    }
+
+    // Based on the interface name and policy, determine whether we
+    // should ignore it.
+    if (ShouldIgnoreInterface(ifname, policy))
+      continue;
+
+    networks->push_back(
+        NetworkInterface(ifname, ifname, it->second.ifa_index,
+                         NetworkChangeNotifier::CONNECTION_UNKNOWN, it->first,
+                         it->second.ifa_prefixlen, ip_attributes));
+  }
+
+  return true;
+}
+
+}  // namespace internal
+
+bool GetNetworkList(NetworkInterfaceList* networks, int policy) {
+  if (networks == NULL)
+    return false;
+
+  internal::AddressTrackerLinux tracker;
+  tracker.Init();
+
+  return internal::GetNetworkListImpl(networks, policy,
+                                      tracker.GetOnlineLinks(),
+                                      tracker.GetAddressMap(), &if_indextoname);
+}
+
+}  // namespace net
diff --git a/net/base/net_util_linux.h b/net/base/net_util_linux.h
new file mode 100644
index 0000000..340c380
--- /dev/null
+++ b/net/base/net_util_linux.h
@@ -0,0 +1,31 @@
+// Copyright (c) 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 NET_BASE_NET_UTIL_LINUX_H_
+#define NET_BASE_NET_UTIL_LINUX_H_
+
+// This file is only used to expose some of the internals
+// of net_util_linux.cc to tests.
+
+#include "base/containers/hash_tables.h"
+#include "net/base/address_tracker_linux.h"
+#include "net/base/net_util.h"
+
+namespace net {
+namespace internal {
+
+typedef char* (*GetInterfaceNameFunction)(unsigned int interface_index,
+                                          char* ifname);
+
+NET_EXPORT bool GetNetworkListImpl(
+    NetworkInterfaceList* networks,
+    int policy,
+    const base::hash_set<int>& online_links,
+    const internal::AddressTrackerLinux::AddressMap& address_map,
+    GetInterfaceNameFunction get_interface_name);
+
+}  // namespace internal
+}  // namespace net
+
+#endif  // NET_BASE_NET_UTIL_LINUX_H_
diff --git a/net/base/net_util_mac.cc b/net/base/net_util_mac.cc
new file mode 100644
index 0000000..5dd4630
--- /dev/null
+++ b/net/base/net_util_mac.cc
@@ -0,0 +1,246 @@
+// Copyright (c) 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 "net/base/net_util_mac.h"
+
+#include <ifaddrs.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <set>
+#include <sys/types.h>
+
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_tokenizer.h"
+#include "base/strings/string_util.h"
+#include "base/threading/thread_restrictions.h"
+#include "net/base/escape.h"
+#include "net/base/ip_endpoint.h"
+#include "net/base/net_errors.h"
+#include "net/base/net_util_posix.h"
+#include "url/gurl.h"
+
+#if !defined(OS_IOS)
+#include <net/if_media.h>
+#include <netinet/in_var.h>
+#include <sys/ioctl.h>
+#endif  // !OS_IOS
+
+namespace net {
+
+namespace {
+
+#if !defined(OS_IOS)
+
+// MacOSX implementation of IPAttributesGetterMac which calls ioctl on socket to
+// retrieve IP attributes.
+class IPAttributesGetterMacImpl : public internal::IPAttributesGetterMac {
+ public:
+  IPAttributesGetterMacImpl();
+  ~IPAttributesGetterMacImpl() override;
+  bool IsInitialized() const override;
+  bool GetIPAttributes(const char* ifname,
+                       const sockaddr* sock_addr,
+                       int* native_attributes) override;
+
+ private:
+  int ioctl_socket_;
+};
+
+IPAttributesGetterMacImpl::IPAttributesGetterMacImpl()
+    : ioctl_socket_(socket(AF_INET6, SOCK_DGRAM, 0)) {
+  DCHECK_GE(ioctl_socket_, 0);
+}
+
+bool IPAttributesGetterMacImpl::IsInitialized() const {
+  return ioctl_socket_ >= 0;
+}
+
+IPAttributesGetterMacImpl::~IPAttributesGetterMacImpl() {
+  if (ioctl_socket_ >= 0) {
+    close(ioctl_socket_);
+  }
+}
+
+bool IPAttributesGetterMacImpl::GetIPAttributes(const char* ifname,
+                                                const sockaddr* sock_addr,
+                                                int* native_attributes) {
+  struct in6_ifreq ifr = {};
+  strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name) - 1);
+  memcpy(&ifr.ifr_ifru.ifru_addr, sock_addr, sock_addr->sa_len);
+  int rv = ioctl(ioctl_socket_, SIOCGIFAFLAG_IN6, &ifr);
+  if (rv >= 0) {
+    *native_attributes = ifr.ifr_ifru.ifru_flags;
+  }
+  return (rv >= 0);
+}
+
+// When returning true, the platform native IPv6 address attributes were
+// successfully converted to net IP address attributes. Otherwise, returning
+// false and the caller should drop the IP address which can't be used by the
+// application layer.
+bool TryConvertNativeToNetIPAttributes(int native_attributes,
+                                       int* net_attributes) {
+  // For MacOSX, we disallow addresses with attributes IN6_IFF_ANYCASE,
+  // IN6_IFF_DUPLICATED, IN6_IFF_TENTATIVE, and IN6_IFF_DETACHED as these are
+  // still progressing through duplicated address detection (DAD) or are not
+  // suitable to be used in an one-to-one communication and shouldn't be used
+  // by the application layer.
+  if (native_attributes & (IN6_IFF_ANYCAST | IN6_IFF_DUPLICATED |
+                           IN6_IFF_TENTATIVE | IN6_IFF_DETACHED)) {
+    return false;
+  }
+
+  if (native_attributes & IN6_IFF_TEMPORARY) {
+    *net_attributes |= IP_ADDRESS_ATTRIBUTE_TEMPORARY;
+  }
+
+  if (native_attributes & IN6_IFF_DEPRECATED) {
+    *net_attributes |= IP_ADDRESS_ATTRIBUTE_DEPRECATED;
+  }
+
+  return true;
+}
+
+NetworkChangeNotifier::ConnectionType GetNetworkInterfaceType(
+    int addr_family,
+    const std::string& interface_name) {
+  NetworkChangeNotifier::ConnectionType type =
+      NetworkChangeNotifier::CONNECTION_UNKNOWN;
+
+  struct ifmediareq ifmr = {};
+  strncpy(ifmr.ifm_name, interface_name.c_str(), sizeof(ifmr.ifm_name) - 1);
+
+  int s = socket(addr_family, SOCK_DGRAM, 0);
+  if (s == -1) {
+    return type;
+  }
+
+  if (ioctl(s, SIOCGIFMEDIA, &ifmr) != -1) {
+    if (ifmr.ifm_current & IFM_IEEE80211) {
+      type = NetworkChangeNotifier::CONNECTION_WIFI;
+    } else if (ifmr.ifm_current & IFM_ETHER) {
+      type = NetworkChangeNotifier::CONNECTION_ETHERNET;
+    }
+  }
+  close(s);
+  return type;
+}
+
+#endif  // !OS_IOS
+}  // namespace
+
+namespace internal {
+
+bool GetNetworkListImpl(NetworkInterfaceList* networks,
+                        int policy,
+                        const ifaddrs* interfaces,
+                        IPAttributesGetterMac* ip_attributes_getter) {
+  // Enumerate the addresses assigned to network interfaces which are up.
+  for (const ifaddrs* interface = interfaces; interface != NULL;
+       interface = interface->ifa_next) {
+    // Skip loopback interfaces, and ones which are down.
+    if (!(IFF_RUNNING & interface->ifa_flags))
+      continue;
+    if (IFF_LOOPBACK & interface->ifa_flags)
+      continue;
+    // Skip interfaces with no address configured.
+    struct sockaddr* addr = interface->ifa_addr;
+    if (!addr)
+      continue;
+
+    // Skip unspecified addresses (i.e. made of zeroes) and loopback addresses
+    // configured on non-loopback interfaces.
+    if (IsLoopbackOrUnspecifiedAddress(addr))
+      continue;
+
+    const std::string& name = interface->ifa_name;
+    // Filter out VMware interfaces, typically named vmnet1 and vmnet8.
+    if (ShouldIgnoreInterface(name, policy)) {
+      continue;
+    }
+
+    NetworkChangeNotifier::ConnectionType connection_type =
+        NetworkChangeNotifier::CONNECTION_UNKNOWN;
+
+    int ip_attributes = IP_ADDRESS_ATTRIBUTE_NONE;
+
+#if !defined(OS_IOS)
+    // Retrieve native ip attributes and convert to net version if a getter is
+    // given.
+    if (ip_attributes_getter && ip_attributes_getter->IsInitialized()) {
+      int native_attributes = 0;
+      if (addr->sa_family == AF_INET6 &&
+          ip_attributes_getter->GetIPAttributes(
+              interface->ifa_name, interface->ifa_addr, &native_attributes)) {
+        if (!TryConvertNativeToNetIPAttributes(native_attributes,
+                                               &ip_attributes)) {
+          continue;
+        }
+      }
+    }
+
+    connection_type = GetNetworkInterfaceType(addr->sa_family, name);
+#endif  // !OS_IOS
+
+    IPEndPoint address;
+
+    int addr_size = 0;
+    if (addr->sa_family == AF_INET6) {
+      addr_size = sizeof(sockaddr_in6);
+    } else if (addr->sa_family == AF_INET) {
+      addr_size = sizeof(sockaddr_in);
+    }
+
+    if (address.FromSockAddr(addr, addr_size)) {
+      uint8 prefix_length = 0;
+      if (interface->ifa_netmask) {
+        // If not otherwise set, assume the same sa_family as ifa_addr.
+        if (interface->ifa_netmask->sa_family == 0) {
+          interface->ifa_netmask->sa_family = addr->sa_family;
+        }
+        IPEndPoint netmask;
+        if (netmask.FromSockAddr(interface->ifa_netmask, addr_size)) {
+          prefix_length = MaskPrefixLength(netmask.address());
+        }
+      }
+      networks->push_back(NetworkInterface(
+          name, name, if_nametoindex(name.c_str()), connection_type,
+          address.address(), prefix_length, ip_attributes));
+    }
+  }
+
+  return true;
+}
+
+}  // namespace internal
+
+bool GetNetworkList(NetworkInterfaceList* networks, int policy) {
+  if (networks == NULL)
+    return false;
+
+  // getifaddrs() may require IO operations.
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  ifaddrs* interfaces;
+  if (getifaddrs(&interfaces) < 0) {
+    PLOG(ERROR) << "getifaddrs";
+    return false;
+  }
+
+  scoped_ptr<internal::IPAttributesGetterMac> ip_attributes_getter;
+
+#if !defined(OS_IOS)
+  ip_attributes_getter.reset(new IPAttributesGetterMacImpl());
+#endif
+
+  bool result = internal::GetNetworkListImpl(networks, policy, interfaces,
+                                             ip_attributes_getter.get());
+  freeifaddrs(interfaces);
+  return result;
+}
+
+}  // namespace net
diff --git a/net/base/net_util_mac.h b/net/base/net_util_mac.h
new file mode 100644
index 0000000..178facc
--- /dev/null
+++ b/net/base/net_util_mac.h
@@ -0,0 +1,42 @@
+// Copyright (c) 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 NET_BASE_NET_UTIL_MAC_H_
+#define NET_BASE_NET_UTIL_MAC_H_
+
+// This file is only used to expose some of the internals
+// of net_util_mac.cc to tests.
+
+#include "base/macros.h"
+#include "net/base/net_export.h"
+#include "net/base/net_util.h"
+
+struct ifaddrs;
+struct sockaddr;
+
+namespace net {
+namespace internal {
+
+class NET_EXPORT IPAttributesGetterMac {
+ public:
+  IPAttributesGetterMac() {}
+  virtual ~IPAttributesGetterMac() {}
+  virtual bool IsInitialized() const = 0;
+  virtual bool GetIPAttributes(const char* ifname,
+                               const sockaddr* sock_addr,
+                               int* native_attributes) = 0;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(IPAttributesGetterMac);
+};
+
+NET_EXPORT bool GetNetworkListImpl(NetworkInterfaceList* networks,
+                                   int policy,
+                                   const ifaddrs* interfaces,
+                                   IPAttributesGetterMac* ip_attributes_getter);
+
+}  // namespace internal
+}  // namespace net
+
+#endif  // NET_BASE_NET_UTIL_MAC_H_
diff --git a/net/base/net_util_posix.cc b/net/base/net_util_posix.cc
index a2fa6cd..b8e7195 100644
--- a/net/base/net_util_posix.cc
+++ b/net/base/net_util_posix.cc
@@ -7,38 +7,18 @@
 #include <set>
 #include <sys/types.h>
 
-#include "base/files/file_path.h"
-#include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_tokenizer.h"
-#include "base/strings/string_util.h"
-#include "base/threading/thread_restrictions.h"
-#include "net/base/escape.h"
-#include "net/base/ip_endpoint.h"
-#include "net/base/net_errors.h"
-#include "url/gurl.h"
 
 #if !defined(OS_NACL)
-#if defined(OS_MACOSX)
-#include <ifaddrs.h>
-#else
-#include "net/base/address_tracker_linux.h"
 #include "net/base/net_util_posix.h"
-#endif  // OS_MACOSX
 #include <net/if.h>
 #include <netinet/in.h>
 #endif  // !defined(OS_NACL)
 
-#if defined(OS_MACOSX) && !defined(OS_IOS)
-#include <net/if_media.h>
-#include <netinet/in_var.h>
-#include <sys/ioctl.h>
-#endif
-
 namespace net {
 
-namespace {
+#if !defined(OS_NACL)
+namespace internal {
 
 // The application layer can pass |policy| defined in net_util.h to
 // request filtering out certain type of interfaces.
@@ -77,330 +57,13 @@
   return false;
 }
 
-#if defined(OS_MACOSX)
-
-struct NetworkInterfaceInfo {
-  NetworkInterfaceInfo() : permanent(true) { }
-
-  bool permanent;  // IPv6 has notion of temporary address. If the address is
-                   // IPv6 and it's temporary this field will be false.
-  NetworkInterface interface;
-};
-
-// This method will remove permanent IPv6 addresses if a temporary address
-// is available for same network interface.
-void RemovePermanentIPv6AddressesWhereTemporaryExists(
-    std::vector<NetworkInterfaceInfo>* infos) {
-  if (!infos || infos->empty())
-    return;
-
-  // Build a set containing the names of interfaces with a temp IPv6 address
-  std::set<std::string> ifaces_with_temp_addrs;
-  std::vector<NetworkInterfaceInfo>::iterator i;
-  for (i = infos->begin(); i != infos->end(); ++i) {
-    if (!i->permanent && i->interface.address.size() == kIPv6AddressSize) {
-      ifaces_with_temp_addrs.insert(i->interface.name);
-    }
-  }
-
-  // If there are no such interfaces then there's no further work.
-  if (ifaces_with_temp_addrs.empty())
-    return;
-
-  // Search for permenent addresses belonging to same network interface.
-  for (i = infos->begin(); i != infos->end(); ) {
-    // If the address is IPv6 and it's permanent and there is temporary
-    // address for it, then we can remove this address.
-    if ((i->interface.address.size() == kIPv6AddressSize) && i->permanent &&
-        (ifaces_with_temp_addrs.find(i->interface.name) !=
-            ifaces_with_temp_addrs.end())) {
-      i = infos->erase(i);
-    } else {
-      ++i;
-    }
-  }
-}
-
-#if !defined(OS_IOS)
-NetworkChangeNotifier::ConnectionType GetNetworkInterfaceType(
-    int addr_family, const std::string& interface_name) {
-  NetworkChangeNotifier::ConnectionType type =
-      NetworkChangeNotifier::CONNECTION_UNKNOWN;
-
-  struct ifmediareq ifmr = {};
-  strncpy(ifmr.ifm_name, interface_name.c_str(), sizeof(ifmr.ifm_name) - 1);
-
-  int s = socket(addr_family, SOCK_DGRAM, 0);
-  if (s == -1) {
-    return type;
-  }
-
-  if (ioctl(s, SIOCGIFMEDIA, &ifmr) != -1) {
-    if (ifmr.ifm_current & IFM_IEEE80211) {
-      type = NetworkChangeNotifier::CONNECTION_WIFI;
-    } else if (ifmr.ifm_current & IFM_ETHER) {
-      type = NetworkChangeNotifier::CONNECTION_ETHERNET;
-    }
-  }
-  close(s);
-  return type;
-}
-
-#endif                   // !defined(OS_IOS)
-#elif !defined(OS_NACL)  // OS_MACOSX
-
-// Convert platform native IPv6 address attributes to net IP address
-// attributes and drop ones that can't be used by the application
-// layer.
-bool TryConvertNativeToNetIPAttributes(int native_attributes,
-                                       int* net_attributes) {
-  // For Linux/ChromeOS/Android, we disallow addresses with attributes
-  // IFA_F_OPTIMISTIC, IFA_F_DADFAILED, and IFA_F_TENTATIVE as these
-  // are still progressing through duplicated address detection (DAD)
-  // and shouldn't be used by the application layer until DAD process
-  // is completed.
-  if (native_attributes & (
-#if !defined(OS_ANDROID)
-    IFA_F_OPTIMISTIC | IFA_F_DADFAILED |
-#endif  // !OS_ANDROID
-    IFA_F_TENTATIVE)) {
-    return false;
-  }
-
-  if (native_attributes & IFA_F_TEMPORARY) {
-    *net_attributes |= IP_ADDRESS_ATTRIBUTE_TEMPORARY;
-  }
-
-  if (native_attributes & IFA_F_DEPRECATED) {
-    *net_attributes |= IP_ADDRESS_ATTRIBUTE_DEPRECATED;
-  }
-
-  return true;
-}
-#endif  // OS_MACOSX
-}  // namespace
-
-namespace internal {
-
-#if !defined(OS_MACOSX) && !defined(OS_NACL)
-
-inline const unsigned char* GetIPAddressData(const IPAddressNumber& ip) {
-#if defined(OS_ANDROID)
-  return ip.begin();
-#else
-  return ip.data();
-#endif
-}
-
-bool GetNetworkListImpl(
-    NetworkInterfaceList* networks,
-    int policy,
-    const base::hash_set<int>& online_links,
-    const internal::AddressTrackerLinux::AddressMap& address_map,
-    GetInterfaceNameFunction get_interface_name) {
-  std::map<int, std::string> ifnames;
-
-  for (internal::AddressTrackerLinux::AddressMap::const_iterator it =
-           address_map.begin();
-       it != address_map.end();
-       ++it) {
-    // Ignore addresses whose links are not online.
-    if (online_links.find(it->second.ifa_index) == online_links.end())
-      continue;
-
-    sockaddr_storage sock_addr;
-    socklen_t sock_len = sizeof(sockaddr_storage);
-
-    // Convert to sockaddr for next check.
-    if (!IPEndPoint(it->first, 0)
-             .ToSockAddr(reinterpret_cast<sockaddr*>(&sock_addr), &sock_len)) {
-      continue;
-    }
-
-    // Skip unspecified addresses (i.e. made of zeroes) and loopback addresses
-    if (IsLoopbackOrUnspecifiedAddress(reinterpret_cast<sockaddr*>(&sock_addr)))
-      continue;
-
-    int ip_attributes = IP_ADDRESS_ATTRIBUTE_NONE;
-
-    if (it->second.ifa_family == AF_INET6) {
-      // Ignore addresses whose attributes are not actionable by
-      // the application layer.
-      if (!TryConvertNativeToNetIPAttributes(it->second.ifa_flags,
-                                             &ip_attributes))
-        continue;
-    }
-
-    // Find the name of this link.
-    std::map<int, std::string>::const_iterator itname =
-        ifnames.find(it->second.ifa_index);
-    std::string ifname;
-    if (itname == ifnames.end()) {
-      char buffer[IF_NAMESIZE] = {0};
-      if (get_interface_name(it->second.ifa_index, buffer)) {
-        ifname = ifnames[it->second.ifa_index] = buffer;
-      } else {
-        // Ignore addresses whose interface name can't be retrieved.
-        continue;
-      }
-    } else {
-      ifname = itname->second;
-    }
-
-    // Based on the interface name and policy, determine whether we
-    // should ignore it.
-    if (ShouldIgnoreInterface(ifname, policy))
-      continue;
-
-    networks->push_back(
-        NetworkInterface(ifname,
-                         ifname,
-                         it->second.ifa_index,
-                         NetworkChangeNotifier::CONNECTION_UNKNOWN,
-                         it->first,
-                         it->second.ifa_prefixlen,
-                         ip_attributes));
-  }
-
-  return true;
-}
-#endif
-
 }  // namespace internal
-
+#else   // OS_NACL
 bool GetNetworkList(NetworkInterfaceList* networks, int policy) {
-  if (networks == NULL)
-    return false;
-#if defined(OS_NACL)
   NOTIMPLEMENTED();
   return false;
-#elif !defined(OS_MACOSX)
-
-  internal::AddressTrackerLinux tracker;
-  tracker.Init();
-
-  return internal::GetNetworkListImpl(networks,
-                                      policy,
-                                      tracker.GetOnlineLinks(),
-                                      tracker.GetAddressMap(),
-                                      &if_indextoname);
-
-#else  // Only OS_MACOSX and OS_IOS will run the code below
-
-  // getifaddrs() may require IO operations.
-  base::ThreadRestrictions::AssertIOAllowed();
-
-#if !defined(OS_IOS)
-  int ioctl_socket = -1;
-  if (policy & INCLUDE_ONLY_TEMP_IPV6_ADDRESS_IF_POSSIBLE) {
-    // we need a socket to query information about temporary address.
-    ioctl_socket = socket(AF_INET6, SOCK_DGRAM, 0);
-    DCHECK_GT(ioctl_socket, 0);
-  }
-#endif
-
-  ifaddrs* interfaces;
-  if (getifaddrs(&interfaces) < 0) {
-    PLOG(ERROR) << "getifaddrs";
-    return false;
-  }
-
-  std::vector<NetworkInterfaceInfo> network_infos;
-
-  // Enumerate the addresses assigned to network interfaces which are up.
-  for (ifaddrs *interface = interfaces;
-       interface != NULL;
-       interface = interface->ifa_next) {
-    // Skip loopback interfaces, and ones which are down.
-    if (!(IFF_UP & interface->ifa_flags))
-      continue;
-    if (IFF_LOOPBACK & interface->ifa_flags)
-      continue;
-    // Skip interfaces with no address configured.
-    struct sockaddr* addr = interface->ifa_addr;
-    if (!addr)
-      continue;
-
-    // Skip unspecified addresses (i.e. made of zeroes) and loopback addresses
-    // configured on non-loopback interfaces.
-    if (IsLoopbackOrUnspecifiedAddress(addr))
-      continue;
-
-    int addr_size = 0;
-    if (addr->sa_family == AF_INET6) {
-      addr_size = sizeof(sockaddr_in6);
-    } else if (addr->sa_family == AF_INET) {
-      addr_size = sizeof(sockaddr_in);
-    }
-
-    const std::string& name = interface->ifa_name;
-    // Filter out VMware interfaces, typically named vmnet1 and vmnet8.
-    if (ShouldIgnoreInterface(name, policy)) {
-      continue;
-    }
-
-    NetworkInterfaceInfo network_info;
-    NetworkChangeNotifier::ConnectionType connection_type =
-        NetworkChangeNotifier::CONNECTION_UNKNOWN;
-#if !defined(OS_IOS)
-    // Check if this is a temporary address. Currently this is only supported
-    // on Mac.
-    if ((policy & INCLUDE_ONLY_TEMP_IPV6_ADDRESS_IF_POSSIBLE) &&
-        ioctl_socket >= 0 && addr->sa_family == AF_INET6) {
-      struct in6_ifreq ifr = {};
-      strncpy(ifr.ifr_name, interface->ifa_name, sizeof(ifr.ifr_name) - 1);
-      memcpy(&ifr.ifr_ifru.ifru_addr, interface->ifa_addr,
-             interface->ifa_addr->sa_len);
-      int rv = ioctl(ioctl_socket, SIOCGIFAFLAG_IN6, &ifr);
-      if (rv >= 0) {
-        network_info.permanent = !(ifr.ifr_ifru.ifru_flags & IN6_IFF_TEMPORARY);
-      }
-    }
-
-    connection_type = GetNetworkInterfaceType(addr->sa_family, name);
-#endif
-
-    IPEndPoint address;
-    if (address.FromSockAddr(addr, addr_size)) {
-      uint8 net_mask = 0;
-      if (interface->ifa_netmask) {
-        // If not otherwise set, assume the same sa_family as ifa_addr.
-        if (interface->ifa_netmask->sa_family == 0) {
-          interface->ifa_netmask->sa_family = addr->sa_family;
-        }
-        IPEndPoint netmask;
-        if (netmask.FromSockAddr(interface->ifa_netmask, addr_size)) {
-          net_mask = MaskPrefixLength(netmask.address());
-        }
-      }
-      network_info.interface = NetworkInterface(name,
-                                                name,
-                                                if_nametoindex(name.c_str()),
-                                                connection_type,
-                                                address.address(),
-                                                net_mask,
-                                                IP_ADDRESS_ATTRIBUTE_NONE);
-
-      network_infos.push_back(NetworkInterfaceInfo(network_info));
-    }
-  }
-  freeifaddrs(interfaces);
-#if !defined(OS_IOS)
-  if (ioctl_socket >= 0) {
-    close(ioctl_socket);
-  }
-#endif
-
-  if (policy & INCLUDE_ONLY_TEMP_IPV6_ADDRESS_IF_POSSIBLE) {
-    RemovePermanentIPv6AddressesWhereTemporaryExists(&network_infos);
-  }
-
-  for (size_t i = 0; i < network_infos.size(); ++i) {
-    networks->push_back(network_infos[i].interface);
-  }
-  return true;
-#endif
 }
+#endif  // OS_NACL
 
 WifiPHYLayerProtocol GetWifiPHYLayerProtocol() {
   return WIFI_PHY_LAYER_PROTOCOL_UNKNOWN;
diff --git a/net/base/net_util_posix.h b/net/base/net_util_posix.h
index b553d1c..93089c2 100644
--- a/net/base/net_util_posix.h
+++ b/net/base/net_util_posix.h
@@ -5,27 +5,21 @@
 #ifndef NET_BASE_NET_UTIL_POSIX_H_
 #define NET_BASE_NET_UTIL_POSIX_H_
 
-// This file is only used to expose some of the internals
-// of net_util_posix.cc to tests.
+// This file is only used to expose some of the internals of
+// net_util_posix.cc to net_util_linux.cc and net_util_mac.cc.
+
+#include <string>
+
+struct sockaddr;
 
 namespace net {
 namespace internal {
-
-#if !defined(OS_MACOSX) && !defined(OS_NACL)
-typedef char* (*GetInterfaceNameFunction)(unsigned int interface_index,
-                                          char* ifname);
-
-NET_EXPORT bool GetNetworkListImpl(
-    NetworkInterfaceList* networks,
-    int policy,
-    const base::hash_set<int>& online_links,
-    const internal::AddressTrackerLinux::AddressMap& address_map,
-    GetInterfaceNameFunction get_interface_name);
-
-#endif  // !OS_MACOSX && !OS_NACL
+#if !defined(OS_NACL)
+bool ShouldIgnoreInterface(const std::string& name, int policy);
+bool IsLoopbackOrUnspecifiedAddress(const sockaddr* addr);
+#endif  // !OS_NACL
 
 }  // namespace internal
-
 }  // namespace net
 
 #endif  // NET_BASE_NET_UTIL_POSIX_H_
diff --git a/net/base/net_util_unittest.cc b/net/base/net_util_unittest.cc
index 45f0857..a25903a 100644
--- a/net/base/net_util_unittest.cc
+++ b/net/base/net_util_unittest.cc
@@ -17,10 +17,17 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/sys_byteorder.h"
 #include "base/time/time.h"
+#include "net/base/ip_endpoint.h"
 
 #if !defined(OS_NACL) && !defined(OS_WIN)
 #include <net/if.h>
 #include <netinet/in.h>
+#if defined(OS_MACOSX)
+#include <ifaddrs.h>
+#if !defined(OS_IOS)
+#include <netinet/in_var.h>
+#endif  // !OS_IOS
+#endif  // OS_MACOSX
 #endif  // !OS_NACL && !OS_WIN
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
@@ -38,6 +45,11 @@
 
 #if !defined(OS_WIN)
 #include "net/base/net_util_posix.h"
+#if defined(OS_MACOSX)
+#include "net/base/net_util_mac.h"
+#else  // OS_MACOSX
+#include "net/base/net_util_linux.h"
+#endif
 #endif  // !OS_WIN
 
 using base::ASCIIToUTF16;
@@ -85,6 +97,58 @@
   return out;
 }
 
+#if defined(OS_MACOSX)
+class IPAttributesGetterTest : public internal::IPAttributesGetterMac {
+ public:
+  IPAttributesGetterTest() : native_attributes_(0) {}
+  bool IsInitialized() const override { return true; }
+  bool GetIPAttributes(const char* ifname,
+                       const sockaddr* sock_addr,
+                       int* native_attributes) override {
+    *native_attributes = native_attributes_;
+    return true;
+  }
+  void set_native_attributes(int native_attributes) {
+    native_attributes_ = native_attributes;
+  }
+
+ private:
+  int native_attributes_;
+};
+
+// Helper function to create a single valid ifaddrs
+bool FillIfaddrs(ifaddrs* interfaces,
+                 const char* ifname,
+                 uint flags,
+                 const IPAddressNumber& ip_address,
+                 const IPAddressNumber& ip_netmask,
+                 sockaddr_storage sock_addrs[2]) {
+  interfaces->ifa_next = NULL;
+  interfaces->ifa_name = const_cast<char*>(ifname);
+  interfaces->ifa_flags = flags;
+
+  socklen_t sock_len = sizeof(sockaddr_storage);
+
+  // Convert to sockaddr for next check.
+  if (!IPEndPoint(ip_address, 0)
+           .ToSockAddr(reinterpret_cast<sockaddr*>(&sock_addrs[0]),
+                       &sock_len)) {
+    return false;
+  }
+  interfaces->ifa_addr = reinterpret_cast<sockaddr*>(&sock_addrs[0]);
+
+  sock_len = sizeof(sockaddr_storage);
+  if (!IPEndPoint(ip_netmask, 0)
+           .ToSockAddr(reinterpret_cast<sockaddr*>(&sock_addrs[1]),
+                       &sock_len)) {
+    return false;
+  }
+  interfaces->ifa_netmask = reinterpret_cast<sockaddr*>(&sock_addrs[1]);
+
+  return true;
+}
+#endif  // OS_MACOSX
+
 }  // anonymous namespace
 
 TEST(NetUtilTest, GetIdentityFromURL) {
@@ -812,6 +876,18 @@
   }
 }
 
+static const char ifname_em1[] = "em1";
+static const char ifname_vm[] = "vmnet";
+
+static const unsigned char kIPv6LocalAddr[] = {
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
+static const unsigned char kIPv6Addr[] =
+  {0x24, 0x01, 0xfa, 0x00, 0x00, 0x04, 0x10, 0x00, 0xbe, 0x30, 0x5b, 0xff,
+   0xfe, 0xe5, 0x00, 0xc3};
+static const unsigned char kIPv6Netmask[] =
+  {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00};
+
 #if !defined(OS_MACOSX) && !defined(OS_WIN) && !defined(OS_NACL)
 
 char* CopyInterfaceName(const char* ifname, int ifname_size, char* output) {
@@ -820,30 +896,24 @@
   return output;
 }
 
-static const char ifname_em1[] = "em1";
 char* GetInterfaceName(unsigned int interface_index, char* ifname) {
   return CopyInterfaceName(ifname_em1, arraysize(ifname_em1), ifname);
 }
 
-static const char ifname_vm[] = "vmnet";
 char* GetInterfaceNameVM(unsigned int interface_index, char* ifname) {
   return CopyInterfaceName(ifname_vm, arraysize(ifname_vm), ifname);
 }
 
 TEST(NetUtilTest, GetNetworkListTrimming) {
-  NetworkInterfaceList results;
-  ::base::hash_set<int> online_links;
-  net::internal::AddressTrackerLinux::AddressMap address_map;
-
-  const unsigned char kIPv6LocalAddr[] = {
-      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
-  const unsigned char kIPv6Addr[] =
-    {0x24, 0x01, 0xfa, 0x00, 0x00, 0x04, 0x10, 0x00, 0xbe, 0x30, 0x5b, 0xff,
-     0xfe, 0xe5, 0x00, 0xc3};
-
   IPAddressNumber ipv6_local_address(
       kIPv6LocalAddr, kIPv6LocalAddr + arraysize(kIPv6LocalAddr));
   IPAddressNumber ipv6_address(kIPv6Addr, kIPv6Addr + arraysize(kIPv6Addr));
+  IPAddressNumber ipv6_netmask(kIPv6Netmask,
+                               kIPv6Netmask + arraysize(kIPv6Netmask));
+
+  NetworkInterfaceList results;
+  ::base::hash_set<int> online_links;
+  net::internal::AddressTrackerLinux::AddressMap address_map;
 
   // Interface 1 is offline.
   struct ifaddrmsg msg = {
@@ -956,7 +1026,101 @@
   results.clear();
 }
 
-#endif
+#elif defined(OS_MACOSX)
+
+TEST(NetUtilTest, GetNetworkListTrimming) {
+  IPAddressNumber ipv6_local_address(
+      kIPv6LocalAddr, kIPv6LocalAddr + arraysize(kIPv6LocalAddr));
+  IPAddressNumber ipv6_address(kIPv6Addr, kIPv6Addr + arraysize(kIPv6Addr));
+  IPAddressNumber ipv6_netmask(kIPv6Netmask,
+                               kIPv6Netmask + arraysize(kIPv6Netmask));
+
+  NetworkInterfaceList results;
+  IPAttributesGetterTest ip_attributes_getter;
+  sockaddr_storage addresses[2];
+  ifaddrs interface;
+
+  // Address of offline links should be ignored.
+  ASSERT_TRUE(FillIfaddrs(&interface, ifname_em1, IFF_UP, ipv6_address,
+                          ipv6_netmask, addresses));
+  EXPECT_TRUE(net::internal::GetNetworkListImpl(
+      &results, INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES, &interface,
+      &ip_attributes_getter));
+  EXPECT_EQ(results.size(), 0ul);
+
+  // Local address should be trimmed out.
+  ASSERT_TRUE(FillIfaddrs(&interface, ifname_em1, IFF_RUNNING,
+                          ipv6_local_address, ipv6_netmask, addresses));
+  EXPECT_TRUE(net::internal::GetNetworkListImpl(
+      &results, INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES, &interface,
+      &ip_attributes_getter));
+  EXPECT_EQ(results.size(), 0ul);
+
+  // vmware address should return by default.
+  ASSERT_TRUE(FillIfaddrs(&interface, ifname_vm, IFF_RUNNING, ipv6_address,
+                          ipv6_netmask, addresses));
+  EXPECT_TRUE(net::internal::GetNetworkListImpl(
+      &results, INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES, &interface,
+      &ip_attributes_getter));
+  EXPECT_EQ(results.size(), 1ul);
+  EXPECT_EQ(results[0].name, ifname_vm);
+  EXPECT_EQ(results[0].network_prefix, 1ul);
+  EXPECT_EQ(results[0].address, ipv6_address);
+  results.clear();
+
+  // vmware address should be trimmed out if policy specified so.
+  ASSERT_TRUE(FillIfaddrs(&interface, ifname_vm, IFF_RUNNING, ipv6_address,
+                          ipv6_netmask, addresses));
+  EXPECT_TRUE(net::internal::GetNetworkListImpl(
+      &results, EXCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES, &interface,
+      &ip_attributes_getter));
+  EXPECT_EQ(results.size(), 0ul);
+  results.clear();
+
+#if !defined(OS_IOS)
+  // Addresses with banned attributes should be ignored.
+  ip_attributes_getter.set_native_attributes(IN6_IFF_ANYCAST);
+  ASSERT_TRUE(FillIfaddrs(&interface, ifname_em1, IFF_RUNNING, ipv6_address,
+                          ipv6_netmask, addresses));
+  EXPECT_TRUE(net::internal::GetNetworkListImpl(
+      &results, INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES, &interface,
+      &ip_attributes_getter));
+  EXPECT_EQ(results.size(), 0ul);
+  results.clear();
+
+  // Addresses with allowed attribute IFA_F_TEMPORARY should be returned and
+  // attributes should be translated correctly.
+  ip_attributes_getter.set_native_attributes(IN6_IFF_TEMPORARY);
+  ASSERT_TRUE(FillIfaddrs(&interface, ifname_em1, IFF_RUNNING, ipv6_address,
+                          ipv6_netmask, addresses));
+  EXPECT_TRUE(net::internal::GetNetworkListImpl(
+      &results, INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES, &interface,
+      &ip_attributes_getter));
+  EXPECT_EQ(results.size(), 1ul);
+  EXPECT_EQ(results[0].name, ifname_em1);
+  EXPECT_EQ(results[0].network_prefix, 1ul);
+  EXPECT_EQ(results[0].address, ipv6_address);
+  EXPECT_EQ(results[0].ip_address_attributes, IP_ADDRESS_ATTRIBUTE_TEMPORARY);
+  results.clear();
+
+  // Addresses with allowed attribute IFA_F_DEPRECATED should be returned and
+  // attributes should be translated correctly.
+  ip_attributes_getter.set_native_attributes(IN6_IFF_DEPRECATED);
+  ASSERT_TRUE(FillIfaddrs(&interface, ifname_em1, IFF_RUNNING, ipv6_address,
+                          ipv6_netmask, addresses));
+  EXPECT_TRUE(net::internal::GetNetworkListImpl(
+      &results, INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES, &interface,
+      &ip_attributes_getter));
+  EXPECT_EQ(results.size(), 1ul);
+  EXPECT_EQ(results[0].name, ifname_em1);
+  EXPECT_EQ(results[0].network_prefix, 1ul);
+  EXPECT_EQ(results[0].address, ipv6_address);
+  EXPECT_EQ(results[0].ip_address_attributes, IP_ADDRESS_ATTRIBUTE_DEPRECATED);
+  results.clear();
+#endif  // !OS_IOS
+}
+
+#endif  // !OS_MACOSX && !OS_WIN && !OS_NACL
 
 namespace {
 
diff --git a/net/base/network_activity_monitor.cc b/net/base/network_activity_monitor.cc
new file mode 100644
index 0000000..78da8c8
--- /dev/null
+++ b/net/base/network_activity_monitor.cc
@@ -0,0 +1,64 @@
+// Copyright (c) 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 "net/base/network_activity_monitor.h"
+
+namespace net {
+
+namespace {
+
+base::LazyInstance<NetworkActivityMonitor>::Leaky g_network_activity_monitor =
+    LAZY_INSTANCE_INITIALIZER;
+
+}  // namespace
+
+NetworkActivityMonitor::NetworkActivityMonitor()
+    : bytes_received_(0), bytes_sent_(0) {
+}
+
+NetworkActivityMonitor::~NetworkActivityMonitor() {
+}
+
+// static
+NetworkActivityMonitor* NetworkActivityMonitor::GetInstance() {
+  return g_network_activity_monitor.Pointer();
+}
+
+void NetworkActivityMonitor::IncrementBytesReceived(uint64_t bytes_received) {
+  base::TimeTicks now = base::TimeTicks::Now();
+  base::AutoLock lock(lock_);
+  bytes_received_ += bytes_received;
+  last_received_ticks_ = now;
+}
+
+void NetworkActivityMonitor::IncrementBytesSent(uint64_t bytes_sent) {
+  base::TimeTicks now = base::TimeTicks::Now();
+  base::AutoLock lock(lock_);
+  bytes_sent_ += bytes_sent;
+  last_sent_ticks_ = now;
+}
+
+uint64_t NetworkActivityMonitor::GetBytesReceived() const {
+  base::AutoLock lock(lock_);
+  return bytes_received_;
+}
+
+uint64_t NetworkActivityMonitor::GetBytesSent() const {
+  base::AutoLock lock(lock_);
+  return bytes_sent_;
+}
+
+base::TimeDelta NetworkActivityMonitor::GetTimeSinceLastReceived() const {
+  base::TimeTicks now = base::TimeTicks::Now();
+  base::AutoLock lock(lock_);
+  return now - last_received_ticks_;
+}
+
+base::TimeDelta NetworkActivityMonitor::GetTimeSinceLastSent() const {
+  base::TimeTicks now = base::TimeTicks::Now();
+  base::AutoLock lock(lock_);
+  return now - last_sent_ticks_;
+}
+
+}  // namespace net
diff --git a/net/base/network_activity_monitor.h b/net/base/network_activity_monitor.h
new file mode 100644
index 0000000..5319477
--- /dev/null
+++ b/net/base/network_activity_monitor.h
@@ -0,0 +1,68 @@
+// Copyright (c) 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 NET_BASE_NETWORK_ACTIVITY_MONITOR_H_
+#define NET_BASE_NETWORK_ACTIVITY_MONITOR_H_
+
+#include "base/basictypes.h"
+#include "base/lazy_instance.h"
+#include "base/synchronization/lock.h"
+#include "base/time/time.h"
+#include "net/base/net_export.h"
+
+namespace net {
+
+namespace test {
+
+class NetworkActivityMonitorPeer;
+
+}  // namespace test
+
+// NetworkActivityMonitor tracks network activity across all sockets and
+// provides cumulative statistics about bytes sent to and received from
+// the network. It uses a lock to ensure thread-safety.
+//
+// There are a few caveats:
+//  * Bytes "sent" includes all send attempts and may include
+//    some bytes which were actually never sent over the network.
+//  * Bytes received includes only bytes actually received from the network,
+//    and does not include any bytes read from the the cache.
+//  * Network activity not initiated directly using chromium sockets won't
+//    be reflected here (for instance DNS queries issued by getaddrinfo()).
+class NET_EXPORT_PRIVATE NetworkActivityMonitor {
+ public:
+  // Returns the singleton instance of the monitor.
+  static NetworkActivityMonitor* GetInstance();
+
+  void IncrementBytesReceived(uint64_t bytes_received);
+  void IncrementBytesSent(uint64_t bytes_sent);
+
+  uint64_t GetBytesReceived() const;
+  uint64_t GetBytesSent() const;
+
+  base::TimeDelta GetTimeSinceLastReceived() const;
+  base::TimeDelta GetTimeSinceLastSent() const;
+
+ private:
+  friend class test::NetworkActivityMonitorPeer;
+
+  NetworkActivityMonitor();
+  ~NetworkActivityMonitor();
+  friend struct base::DefaultLazyInstanceTraits<NetworkActivityMonitor>;
+
+  // Protects all the following members.
+  mutable base::Lock lock_;
+
+  uint64_t bytes_received_;
+  uint64_t bytes_sent_;
+
+  base::TimeTicks last_received_ticks_;
+  base::TimeTicks last_sent_ticks_;
+
+  DISALLOW_COPY_AND_ASSIGN(NetworkActivityMonitor);
+};
+
+}  // namespace net
+
+#endif  // NET_BASE_NETWORK_ACTIVITY_MONITOR_H_
diff --git a/net/base/network_activity_monitor_unittest.cc b/net/base/network_activity_monitor_unittest.cc
new file mode 100644
index 0000000..e625c55
--- /dev/null
+++ b/net/base/network_activity_monitor_unittest.cc
@@ -0,0 +1,131 @@
+// Copyright (c) 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 "net/base/network_activity_monitor.h"
+
+#include <vector>
+
+#include "base/bind.h"
+#include "base/port.h"
+#include "base/stl_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+
+namespace test {
+
+class NetworkActivityMonitorPeer {
+ public:
+  static void ResetMonitor() {
+    NetworkActivityMonitor* monitor = NetworkActivityMonitor::GetInstance();
+    base::AutoLock lock(monitor->lock_);
+    monitor->bytes_sent_ = 0;
+    monitor->bytes_received_ = 0;
+    monitor->last_received_ticks_ = base::TimeTicks();
+    monitor->last_sent_ticks_ = base::TimeTicks();
+  }
+};
+
+
+class NetworkActivityMontiorTest : public testing::Test {
+ public:
+  NetworkActivityMontiorTest() {
+    NetworkActivityMonitorPeer::ResetMonitor();
+  }
+};
+
+TEST_F(NetworkActivityMontiorTest, GetInstance) {
+  NetworkActivityMonitor* monitor = NetworkActivityMonitor::GetInstance();
+  EXPECT_TRUE(monitor != NULL);
+  EXPECT_TRUE(monitor == NetworkActivityMonitor::GetInstance());
+}
+
+TEST_F(NetworkActivityMontiorTest, BytesReceived) {
+  NetworkActivityMonitor* monitor = NetworkActivityMonitor::GetInstance();
+
+  EXPECT_EQ(0u, monitor->GetBytesReceived());
+
+  base::TimeTicks start = base::TimeTicks::Now();
+  uint64_t bytes = 12345;
+  monitor->IncrementBytesReceived(bytes);
+  EXPECT_EQ(bytes, monitor->GetBytesReceived());
+  base::TimeDelta delta = monitor->GetTimeSinceLastReceived();
+  EXPECT_LE(base::TimeDelta(), delta);
+  EXPECT_GE(base::TimeTicks::Now() - start, delta);
+}
+
+TEST_F(NetworkActivityMontiorTest, BytesSent) {
+  NetworkActivityMonitor* monitor = NetworkActivityMonitor::GetInstance();
+
+  EXPECT_EQ(0u, monitor->GetBytesSent());
+
+  base::TimeTicks start = base::TimeTicks::Now();
+  uint64_t bytes = 12345;
+  monitor->IncrementBytesSent(bytes);
+  EXPECT_EQ(bytes, monitor->GetBytesSent());
+  base::TimeDelta delta = monitor->GetTimeSinceLastSent();
+  EXPECT_LE(base::TimeDelta(), delta);
+  EXPECT_GE(base::TimeTicks::Now() - start, delta);
+}
+
+namespace {
+
+void VerifyBytesReceivedIsMultipleOf(uint64_t bytes) {
+  EXPECT_EQ(0u,
+            NetworkActivityMonitor::GetInstance()->GetBytesReceived() % bytes);
+}
+
+void VerifyBytesSentIsMultipleOf(uint64_t bytes) {
+  EXPECT_EQ(0u, NetworkActivityMonitor::GetInstance()->GetBytesSent() % bytes);
+}
+
+void IncrementBytesReceived(uint64_t bytes) {
+  NetworkActivityMonitor::GetInstance()->IncrementBytesReceived(bytes);
+}
+
+void IncrementBytesSent(uint64_t bytes) {
+  NetworkActivityMonitor::GetInstance()->IncrementBytesSent(bytes);
+}
+
+}  // namespace
+
+TEST_F(NetworkActivityMontiorTest, Threading) {
+  std::vector<base::Thread*> threads;
+  for (size_t i = 0; i < 3; ++i) {
+    threads.push_back(new base::Thread(base::UintToString(i)));
+    ASSERT_TRUE(threads.back()->Start());
+  }
+
+  size_t num_increments = 157;
+  uint64_t bytes_received = GG_UINT64_C(7294954321);
+  uint64_t bytes_sent = GG_UINT64_C(91294998765);
+  for (size_t i = 0; i < num_increments; ++i) {
+    size_t thread_num = i % threads.size();
+    threads[thread_num]->task_runner()->PostTask(
+        FROM_HERE,
+        base::Bind(&IncrementBytesReceived, bytes_received));
+    threads[thread_num]->task_runner()->PostTask(
+        FROM_HERE,
+        base::Bind(&IncrementBytesSent, bytes_sent));
+    threads[thread_num]->task_runner()->PostTask(
+        FROM_HERE,
+        base::Bind(&VerifyBytesSentIsMultipleOf, bytes_sent));
+    threads[thread_num]->task_runner()->PostTask(
+        FROM_HERE,
+        base::Bind(&VerifyBytesReceivedIsMultipleOf, bytes_received));
+  }
+
+  STLDeleteElements(&threads);
+
+  NetworkActivityMonitor* monitor = NetworkActivityMonitor::GetInstance();
+  EXPECT_EQ(num_increments * bytes_received, monitor->GetBytesReceived());
+  EXPECT_EQ(num_increments * bytes_sent, monitor->GetBytesSent());
+}
+
+}  // namespace test
+
+}  // namespace net
diff --git a/net/base/sdch_manager.cc b/net/base/sdch_manager.cc
index 1285ad9..af5e6ee 100644
--- a/net/base/sdch_manager.cc
+++ b/net/base/sdch_manager.cc
@@ -9,6 +9,7 @@
 #include "base/metrics/histogram.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
+#include "base/values.h"
 #include "crypto/sha2.h"
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
 #include "net/base/sdch_observer.h"
@@ -78,7 +79,8 @@
 SdchManager::Dictionary::~Dictionary() {
 }
 
-bool SdchManager::Dictionary::CanAdvertise(const GURL& target_url) {
+SdchProblemCode SdchManager::Dictionary::CanAdvertise(
+    const GURL& target_url) const {
   /* The specific rules of when a dictionary should be advertised in an
      Avail-Dictionary header are modeled after the rules for cookie scoping. The
      terms "domain-match" and "pathmatch" are defined in RFC 2965 [6]. A
@@ -95,28 +97,28 @@
      url scheme.
     */
   if (!DomainMatch(target_url, domain_))
-    return false;
+    return SDCH_DICTIONARY_FOUND_HAS_WRONG_DOMAIN;
   if (!ports_.empty() && 0 == ports_.count(target_url.EffectiveIntPort()))
-    return false;
+    return SDCH_DICTIONARY_FOUND_HAS_WRONG_PORT_LIST;
   if (path_.size() && !PathMatch(target_url.path(), path_))
-    return false;
+    return SDCH_DICTIONARY_FOUND_HAS_WRONG_PATH;
   if (!SdchManager::secure_scheme_supported() && target_url.SchemeIsSecure())
-    return false;
+    return SDCH_DICTIONARY_FOUND_HAS_WRONG_SCHEME;
   if (target_url.SchemeIsSecure() != url_.SchemeIsSecure())
-    return false;
+    return SDCH_DICTIONARY_FOUND_HAS_WRONG_SCHEME;
   if (base::Time::Now() > expiration_)
-    return false;
-  return true;
+    return SDCH_DICTIONARY_FOUND_EXPIRED;
+  return SDCH_OK;
 }
 
 //------------------------------------------------------------------------------
 // Security functions restricting loads and use of dictionaries.
 
 // static
-bool SdchManager::Dictionary::CanSet(const std::string& domain,
-                                     const std::string& path,
-                                     const std::set<int>& ports,
-                                     const GURL& dictionary_url) {
+SdchProblemCode SdchManager::Dictionary::CanSet(const std::string& domain,
+                                                const std::string& path,
+                                                const std::set<int>& ports,
+                                                const GURL& dictionary_url) {
   /*
   A dictionary is invalid and must not be stored if any of the following are
   true:
@@ -135,20 +137,17 @@
   // and hence the conservative approach is to not allow any redirects (if there
   // were any... then don't allow the dictionary to be set).
 
-  if (domain.empty()) {
-    SdchErrorRecovery(DICTIONARY_MISSING_DOMAIN_SPECIFIER);
-    return false;  // Domain is required.
-  }
+  if (domain.empty())
+    return SDCH_DICTIONARY_MISSING_DOMAIN_SPECIFIER;  // Domain is required.
+
   if (registry_controlled_domains::GetDomainAndRegistry(
-        domain,
-        registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES).empty()) {
-    SdchErrorRecovery(DICTIONARY_SPECIFIES_TOP_LEVEL_DOMAIN);
-    return false;  // domain was a TLD.
+          domain, registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES)
+          .empty()) {
+    return SDCH_DICTIONARY_SPECIFIES_TOP_LEVEL_DOMAIN;  // domain was a TLD.
   }
-  if (!Dictionary::DomainMatch(dictionary_url, domain)) {
-    SdchErrorRecovery(DICTIONARY_DOMAIN_NOT_MATCHING_SOURCE_URL);
-    return false;
-  }
+
+  if (!Dictionary::DomainMatch(dictionary_url, domain))
+    return SDCH_DICTIONARY_DOMAIN_NOT_MATCHING_SOURCE_URL;
 
   std::string referrer_url_host = dictionary_url.host();
   size_t postfix_domain_index = referrer_url_host.rfind(domain);
@@ -156,23 +155,20 @@
   if (referrer_url_host.size() == postfix_domain_index + domain.size()) {
     // It is a postfix... so check to see if there's a dot in the prefix.
     size_t end_of_host_index = referrer_url_host.find_first_of('.');
-    if (referrer_url_host.npos != end_of_host_index  &&
+    if (referrer_url_host.npos != end_of_host_index &&
         end_of_host_index < postfix_domain_index) {
-      SdchErrorRecovery(DICTIONARY_REFERER_URL_HAS_DOT_IN_PREFIX);
-      return false;
+      return SDCH_DICTIONARY_REFERER_URL_HAS_DOT_IN_PREFIX;
     }
   }
 
-  if (!ports.empty()
-      && 0 == ports.count(dictionary_url.EffectiveIntPort())) {
-    SdchErrorRecovery(DICTIONARY_PORT_NOT_MATCHING_SOURCE_URL);
-    return false;
-  }
-  return true;
+  if (!ports.empty() && 0 == ports.count(dictionary_url.EffectiveIntPort()))
+    return SDCH_DICTIONARY_PORT_NOT_MATCHING_SOURCE_URL;
+
+  return SDCH_OK;
 }
 
-// static
-bool SdchManager::Dictionary::CanUse(const GURL& referring_url) {
+SdchProblemCode SdchManager::Dictionary::CanUse(
+    const GURL& referring_url) const {
   /*
     1. The request URL's host name domain-matches the Domain attribute of the
       dictionary.
@@ -184,39 +180,30 @@
     HTTPS support AND the dictionary acquisition scheme matches the target
      url scheme.
   */
-  if (!DomainMatch(referring_url, domain_)) {
-    SdchErrorRecovery(DICTIONARY_FOUND_HAS_WRONG_DOMAIN);
-    return false;
-  }
-  if (!ports_.empty()
-      && 0 == ports_.count(referring_url.EffectiveIntPort())) {
-    SdchErrorRecovery(DICTIONARY_FOUND_HAS_WRONG_PORT_LIST);
-    return false;
-  }
-  if (path_.size() && !PathMatch(referring_url.path(), path_)) {
-    SdchErrorRecovery(DICTIONARY_FOUND_HAS_WRONG_PATH);
-    return false;
-  }
-  if (!SdchManager::secure_scheme_supported() &&
-      referring_url.SchemeIsSecure()) {
-    SdchErrorRecovery(DICTIONARY_FOUND_HAS_WRONG_SCHEME);
-    return false;
-  }
-  if (referring_url.SchemeIsSecure() != url_.SchemeIsSecure()) {
-    SdchErrorRecovery(DICTIONARY_FOUND_HAS_WRONG_SCHEME);
-    return false;
-  }
+  if (!DomainMatch(referring_url, domain_))
+    return SDCH_DICTIONARY_FOUND_HAS_WRONG_DOMAIN;
+
+  if (!ports_.empty() && 0 == ports_.count(referring_url.EffectiveIntPort()))
+    return SDCH_DICTIONARY_FOUND_HAS_WRONG_PORT_LIST;
+
+  if (path_.size() && !PathMatch(referring_url.path(), path_))
+    return SDCH_DICTIONARY_FOUND_HAS_WRONG_PATH;
+
+  if (!SdchManager::secure_scheme_supported() && referring_url.SchemeIsSecure())
+    return SDCH_DICTIONARY_FOUND_HAS_WRONG_SCHEME;
+
+  if (referring_url.SchemeIsSecure() != url_.SchemeIsSecure())
+    return SDCH_DICTIONARY_FOUND_HAS_WRONG_SCHEME;
 
   // TODO(jar): Remove overly restrictive failsafe test (added per security
   // review) when we have a need to be more general.
-  if (!referring_url.SchemeIsHTTPOrHTTPS()) {
-    SdchErrorRecovery(ATTEMPT_TO_DECODE_NON_HTTP_DATA);
-    return false;
-  }
+  if (!referring_url.SchemeIsHTTPOrHTTPS())
+    return SDCH_ATTEMPT_TO_DECODE_NON_HTTP_DATA;
 
-  return true;
+  return SDCH_OK;
 }
 
+// static
 bool SdchManager::Dictionary::PathMatch(const std::string& path,
                                         const std::string& restriction) {
   /*  Must be either:
@@ -268,8 +255,9 @@
 }
 
 // static
-void SdchManager::SdchErrorRecovery(ProblemCodes problem) {
-  UMA_HISTOGRAM_ENUMERATION("Sdch3.ProblemCodes_4", problem, MAX_PROBLEM_CODE);
+void SdchManager::SdchErrorRecovery(SdchProblemCode problem) {
+  UMA_HISTOGRAM_ENUMERATION("Sdch3.ProblemCodes_5", problem,
+                            SDCH_MAX_PROBLEM_CODE);
 }
 
 // static
@@ -283,7 +271,7 @@
 }
 
 void SdchManager::BlacklistDomain(const GURL& url,
-                                  ProblemCodes blacklist_reason) {
+                                  SdchProblemCode blacklist_reason) {
   SetAllowLatencyExperiment(url, false);
 
   BlacklistInfo* blacklist_info =
@@ -304,7 +292,7 @@
 }
 
 void SdchManager::BlacklistDomainForever(const GURL& url,
-                                         ProblemCodes blacklist_reason) {
+                                         SdchProblemCode blacklist_reason) {
   SetAllowLatencyExperiment(url, false);
 
   BlacklistInfo* blacklist_info =
@@ -322,7 +310,7 @@
   BlacklistInfo* blacklist_info = &blacklisted_domains_[
       base::StringToLowerASCII(domain)];
   blacklist_info->count = 0;
-  blacklist_info->reason = MIN_PROBLEM_CODE;
+  blacklist_info->reason = SDCH_OK;
 }
 
 int SdchManager::BlackListDomainCount(const std::string& domain) {
@@ -341,49 +329,53 @@
   return blacklisted_domains_[domain_lower].exponential_count;
 }
 
-bool SdchManager::IsInSupportedDomain(const GURL& url) {
+SdchProblemCode SdchManager::IsInSupportedDomain(const GURL& url) {
   DCHECK(thread_checker_.CalledOnValidThread());
   if (!g_sdch_enabled_ )
-    return false;
+    return SDCH_DISABLED;
 
   if (!secure_scheme_supported() && url.SchemeIsSecure())
-    return false;
+    return SDCH_SECURE_SCHEME_NOT_SUPPORTED;
 
   if (blacklisted_domains_.empty())
-    return true;
+    return SDCH_OK;
 
   DomainBlacklistInfo::iterator it =
       blacklisted_domains_.find(base::StringToLowerASCII(url.host()));
   if (blacklisted_domains_.end() == it || it->second.count == 0)
-    return true;
+    return SDCH_OK;
 
   UMA_HISTOGRAM_ENUMERATION("Sdch3.BlacklistReason", it->second.reason,
-                            MAX_PROBLEM_CODE);
-  SdchErrorRecovery(DOMAIN_BLACKLIST_INCLUDES_TARGET);
+                            SDCH_MAX_PROBLEM_CODE);
 
   int count = it->second.count - 1;
   if (count > 0) {
     it->second.count = count;
   } else {
     it->second.count = 0;
-    it->second.reason = MIN_PROBLEM_CODE;
+    it->second.reason = SDCH_OK;
   }
 
-  return false;
+  return SDCH_DOMAIN_BLACKLIST_INCLUDES_TARGET;
 }
 
-void SdchManager::OnGetDictionary(const GURL& request_url,
-                                  const GURL& dictionary_url) {
-  if (!CanFetchDictionary(request_url, dictionary_url))
-    return;
+SdchProblemCode SdchManager::OnGetDictionary(const GURL& request_url,
+                                             const GURL& dictionary_url) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  SdchProblemCode rv = CanFetchDictionary(request_url, dictionary_url);
+  if (rv != SDCH_OK)
+    return rv;
 
   FOR_EACH_OBSERVER(SdchObserver,
                     observers_,
                     OnGetDictionary(this, request_url, dictionary_url));
+
+  return SDCH_OK;
 }
 
-bool SdchManager::CanFetchDictionary(const GURL& referring_url,
-                                     const GURL& dictionary_url) const {
+SdchProblemCode SdchManager::CanFetchDictionary(
+    const GURL& referring_url,
+    const GURL& dictionary_url) const {
   DCHECK(thread_checker_.CalledOnValidThread());
   /* The user agent may retrieve a dictionary from the dictionary URL if all of
      the following are true:
@@ -397,41 +389,40 @@
   // Item (1) above implies item (2).  Spec should be updated.
   // I take "host name match" to be "is identical to"
   if (referring_url.host() != dictionary_url.host() ||
-      referring_url.scheme() != dictionary_url.scheme()) {
-    SdchErrorRecovery(DICTIONARY_LOAD_ATTEMPT_FROM_DIFFERENT_HOST);
-    return false;
-  }
-  if (!secure_scheme_supported() && referring_url.SchemeIsSecure()) {
-    SdchErrorRecovery(DICTIONARY_SELECTED_FOR_SSL);
-    return false;
-  }
+      referring_url.scheme() != dictionary_url.scheme())
+    return SDCH_DICTIONARY_LOAD_ATTEMPT_FROM_DIFFERENT_HOST;
+
+  if (!secure_scheme_supported() && referring_url.SchemeIsSecure())
+    return SDCH_DICTIONARY_SELECTED_FOR_SSL;
 
   // TODO(jar): Remove this failsafe conservative hack which is more restrictive
   // than current SDCH spec when needed, and justified by security audit.
-  if (!referring_url.SchemeIsHTTPOrHTTPS()) {
-    SdchErrorRecovery(DICTIONARY_SELECTED_FROM_NON_HTTP);
-    return false;
-  }
+  if (!referring_url.SchemeIsHTTPOrHTTPS())
+    return SDCH_DICTIONARY_SELECTED_FROM_NON_HTTP;
 
-  return true;
+  return SDCH_OK;
 }
 
-void SdchManager::GetVcdiffDictionary(
+SdchProblemCode SdchManager::GetVcdiffDictionary(
     const std::string& server_hash,
     const GURL& referring_url,
     scoped_refptr<Dictionary>* dictionary) {
   DCHECK(thread_checker_.CalledOnValidThread());
   *dictionary = NULL;
   DictionaryMap::iterator it = dictionaries_.find(server_hash);
-  if (it == dictionaries_.end()) {
-    return;
-  }
+  if (it == dictionaries_.end())
+    return SDCH_DICTIONARY_HASH_NOT_FOUND;
+
   scoped_refptr<Dictionary> matching_dictionary = it->second;
-  if (!IsInSupportedDomain(referring_url))
-    return;
-  if (!matching_dictionary->CanUse(referring_url))
-    return;
-  *dictionary = matching_dictionary;
+
+  SdchProblemCode rv = IsInSupportedDomain(referring_url);
+  if (rv != SDCH_OK)
+    return rv;
+
+  rv = matching_dictionary->CanUse(referring_url);
+  if (rv == SDCH_OK)
+    *dictionary = matching_dictionary;
+  return rv;
 }
 
 // TODO(jar): If we have evictions from the dictionaries_, then we need to
@@ -443,9 +434,11 @@
   int count = 0;
   for (DictionaryMap::iterator it = dictionaries_.begin();
        it != dictionaries_.end(); ++it) {
-    if (!IsInSupportedDomain(target_url))
+    SdchProblemCode rv = IsInSupportedDomain(target_url);
+    if (rv != SDCH_OK)
       continue;
-    if (!it->second->CanAdvertise(target_url))
+
+    if (it->second->CanAdvertise(target_url) != SDCH_OK)
       continue;
     ++count;
     if (!list->empty())
@@ -490,7 +483,7 @@
   ExperimentSet::iterator it = allow_latency_experiment_.find(url.host());
   if (allow_latency_experiment_.end() == it)
     return;  // It was already erased, or never allowed.
-  SdchErrorRecovery(LATENCY_TEST_DISALLOWED);
+  SdchErrorRecovery(SDCH_LATENCY_TEST_DISALLOWED);
   allow_latency_experiment_.erase(it);
 }
 
@@ -502,31 +495,27 @@
   observers_.RemoveObserver(observer);
 }
 
-void SdchManager::AddSdchDictionary(const std::string& dictionary_text,
+SdchProblemCode SdchManager::AddSdchDictionary(
+    const std::string& dictionary_text,
     const GURL& dictionary_url) {
   DCHECK(thread_checker_.CalledOnValidThread());
   std::string client_hash;
   std::string server_hash;
   GenerateHash(dictionary_text, &client_hash, &server_hash);
-  if (dictionaries_.find(server_hash) != dictionaries_.end()) {
-    SdchErrorRecovery(DICTIONARY_ALREADY_LOADED);
-    return;                             // Already loaded.
-  }
+  if (dictionaries_.find(server_hash) != dictionaries_.end())
+    return SDCH_DICTIONARY_ALREADY_LOADED;  // Already loaded.
 
   std::string domain, path;
   std::set<int> ports;
   base::Time expiration(base::Time::Now() + base::TimeDelta::FromDays(30));
 
-  if (dictionary_text.empty()) {
-    SdchErrorRecovery(DICTIONARY_HAS_NO_TEXT);
-    return;                             // Missing header.
-  }
+  if (dictionary_text.empty())
+    return SDCH_DICTIONARY_HAS_NO_TEXT;  // Missing header.
 
   size_t header_end = dictionary_text.find("\n\n");
-  if (std::string::npos == header_end) {
-    SdchErrorRecovery(DICTIONARY_HAS_NO_HEADER);
-    return;                             // Missing header.
-  }
+  if (std::string::npos == header_end)
+    return SDCH_DICTIONARY_HAS_NO_HEADER;  // Missing header.
+
   size_t line_start = 0;  // Start of line being parsed.
   while (1) {
     size_t line_end = dictionary_text.find('\n', line_start);
@@ -534,10 +523,9 @@
     DCHECK_LE(line_end, header_end);
 
     size_t colon_index = dictionary_text.find(':', line_start);
-    if (std::string::npos == colon_index) {
-      SdchErrorRecovery(DICTIONARY_HEADER_LINE_MISSING_COLON);
-      return;                         // Illegal line missing a colon.
-    }
+    if (std::string::npos == colon_index)
+      return SDCH_DICTIONARY_HEADER_LINE_MISSING_COLON;  // Illegal line missing
+                                                         // a colon.
 
     if (colon_index > line_end)
       break;
@@ -556,7 +544,7 @@
         path = value;
       } else if (name == "format-version") {
         if (value != "1.0")
-          return;
+          return SDCH_DICTIONARY_UNSUPPORTED_VERSION;
       } else if (name == "max-age") {
         int64 seconds;
         base::StringToInt64(value, &seconds);
@@ -578,24 +566,23 @@
   GURL dictionary_url_normalized(dictionary_url);
   StripTrailingDot(&dictionary_url_normalized);
 
-  if (!IsInSupportedDomain(dictionary_url_normalized))
-    return;
+  SdchProblemCode rv = IsInSupportedDomain(dictionary_url_normalized);
+  if (rv != SDCH_OK)
+    return rv;
 
-  if (!Dictionary::CanSet(domain, path, ports, dictionary_url_normalized))
-    return;
+  rv = Dictionary::CanSet(domain, path, ports, dictionary_url_normalized);
+  if (rv != SDCH_OK)
+    return rv;
 
   // TODO(jar): Remove these hacks to preclude a DOS attack involving piles of
   // useless dictionaries.  We should probably have a cache eviction plan,
   // instead of just blocking additions.  For now, with the spec in flux, it
   // is probably not worth doing eviction handling.
-  if (kMaxDictionarySize < dictionary_text.size()) {
-    SdchErrorRecovery(DICTIONARY_IS_TOO_LARGE);
-    return;
-  }
-  if (kMaxDictionaryCount <= dictionaries_.size()) {
-    SdchErrorRecovery(DICTIONARY_COUNT_EXCEEDED);
-    return;
-  }
+  if (kMaxDictionarySize < dictionary_text.size())
+    return SDCH_DICTIONARY_IS_TOO_LARGE;
+
+  if (kMaxDictionaryCount <= dictionaries_.size())
+    return SDCH_DICTIONARY_COUNT_EXCEEDED;
 
   UMA_HISTOGRAM_COUNTS("Sdch3.Dictionary size loaded", dictionary_text.size());
   DVLOG(1) << "Loaded dictionary with client hash " << client_hash
@@ -605,7 +592,7 @@
                      dictionary_url_normalized, domain,
                      path, expiration, ports);
   dictionaries_[server_hash] = dictionary;
-  return;
+  return SDCH_OK;
 }
 
 // static
@@ -618,4 +605,46 @@
   std::replace(output->begin(), output->end(), '/', '_');
 }
 
+base::Value* SdchManager::SdchInfoToValue() const {
+  base::DictionaryValue* value = new base::DictionaryValue();
+
+  value->SetBoolean("sdch_enabled", sdch_enabled());
+  value->SetBoolean("secure_scheme_support", secure_scheme_supported());
+
+  base::ListValue* entry_list = new base::ListValue();
+  for (DictionaryMap::const_iterator it = dictionaries_.begin();
+       it != dictionaries_.end(); ++it) {
+    base::DictionaryValue* entry_dict = new base::DictionaryValue();
+    entry_dict->SetString("url", it->second->url().spec());
+    entry_dict->SetString("client_hash", it->second->client_hash());
+    entry_dict->SetString("domain", it->second->domain());
+    entry_dict->SetString("path", it->second->path());
+    base::ListValue* port_list = new base::ListValue();
+    for (std::set<int>::const_iterator port_it = it->second->ports().begin();
+         port_it != it->second->ports().end(); ++port_it) {
+      port_list->AppendInteger(*port_it);
+    }
+    entry_dict->Set("ports", port_list);
+    entry_dict->SetString("server_hash", it->first);
+    entry_list->Append(entry_dict);
+  }
+  value->Set("dictionaries", entry_list);
+
+  entry_list = new base::ListValue();
+  for (DomainBlacklistInfo::const_iterator it = blacklisted_domains_.begin();
+       it != blacklisted_domains_.end(); ++it) {
+    if (it->second.count == 0)
+      continue;
+    base::DictionaryValue* entry_dict = new base::DictionaryValue();
+    entry_dict->SetString("domain", it->first);
+    if (it->second.count != INT_MAX)
+      entry_dict->SetInteger("tries", it->second.count);
+    entry_dict->SetInteger("reason", it->second.reason);
+    entry_list->Append(entry_dict);
+  }
+  value->Set("blacklisted", entry_list);
+
+  return value;
+}
+
 }  // namespace net
diff --git a/net/base/sdch_manager.h b/net/base/sdch_manager.h
index ff157e5..016978a 100644
--- a/net/base/sdch_manager.h
+++ b/net/base/sdch_manager.h
@@ -16,8 +16,13 @@
 #include "base/threading/thread_checker.h"
 #include "base/time/time.h"
 #include "net/base/net_export.h"
+#include "net/base/sdch_problem_codes.h"
 #include "url/gurl.h"
 
+namespace base {
+class Value;
+}
+
 namespace net {
 
 class SdchObserver;
@@ -35,106 +40,6 @@
 // module) to decompress data.
 class NET_EXPORT SdchManager {
  public:
-  // A list of errors that appeared and were either resolved, or used to turn
-  // off sdch encoding.
-  enum ProblemCodes {
-    MIN_PROBLEM_CODE,
-
-    // Content-encoding correction problems.
-    ADDED_CONTENT_ENCODING = 1,
-    FIXED_CONTENT_ENCODING = 2,
-    FIXED_CONTENT_ENCODINGS = 3,
-
-    // Content decoding errors.
-    DECODE_HEADER_ERROR = 4,
-    DECODE_BODY_ERROR = 5,
-
-    // More content-encoding correction problems.
-    OPTIONAL_GUNZIP_ENCODING_ADDED = 6,
-
-    // Content encoding correction when we're not even tagged as HTML!?!
-    BINARY_ADDED_CONTENT_ENCODING = 7,
-    BINARY_FIXED_CONTENT_ENCODING = 8,
-    BINARY_FIXED_CONTENT_ENCODINGS = 9,
-
-    // Dictionary selection for use problems.
-    DICTIONARY_FOUND_HAS_WRONG_DOMAIN = 10,
-    DICTIONARY_FOUND_HAS_WRONG_PORT_LIST = 11,
-    DICTIONARY_FOUND_HAS_WRONG_PATH = 12,
-    DICTIONARY_FOUND_HAS_WRONG_SCHEME = 13,
-    DICTIONARY_HASH_NOT_FOUND = 14,
-    DICTIONARY_HASH_MALFORMED = 15,
-
-    // Dictionary saving problems.
-    DICTIONARY_HAS_NO_HEADER = 20,
-    DICTIONARY_HEADER_LINE_MISSING_COLON = 21,
-    DICTIONARY_MISSING_DOMAIN_SPECIFIER = 22,
-    DICTIONARY_SPECIFIES_TOP_LEVEL_DOMAIN = 23,
-    DICTIONARY_DOMAIN_NOT_MATCHING_SOURCE_URL = 24,
-    DICTIONARY_PORT_NOT_MATCHING_SOURCE_URL = 25,
-    DICTIONARY_HAS_NO_TEXT = 26,
-    DICTIONARY_REFERER_URL_HAS_DOT_IN_PREFIX = 27,
-
-    // Dictionary loading problems.
-    DICTIONARY_LOAD_ATTEMPT_FROM_DIFFERENT_HOST = 30,
-    DICTIONARY_SELECTED_FOR_SSL = 31,
-    DICTIONARY_ALREADY_LOADED = 32,
-    DICTIONARY_SELECTED_FROM_NON_HTTP = 33,
-    DICTIONARY_IS_TOO_LARGE= 34,
-    DICTIONARY_COUNT_EXCEEDED = 35,
-    DICTIONARY_ALREADY_SCHEDULED_TO_DOWNLOAD = 36,
-    DICTIONARY_ALREADY_TRIED_TO_DOWNLOAD = 37,
-    DICTIONARY_FETCH_READ_FAILED = 38,
-
-    // Failsafe hack.
-    ATTEMPT_TO_DECODE_NON_HTTP_DATA = 40,
-
-
-    // Content-Encoding problems detected, with no action taken.
-    MULTIENCODING_FOR_NON_SDCH_REQUEST = 50,
-    SDCH_CONTENT_ENCODE_FOR_NON_SDCH_REQUEST = 51,
-
-    // Dictionary manager issues.
-    DOMAIN_BLACKLIST_INCLUDES_TARGET = 61,
-
-    // Problematic decode recovery methods.
-    META_REFRESH_RECOVERY = 70,            // Dictionary not found.
-    // defunct =  71, // Almost the same as META_REFRESH_UNSUPPORTED.
-    // defunct = 72,  // Almost the same as CACHED_META_REFRESH_UNSUPPORTED.
-    // defunct = 73,  // PASSING_THROUGH_NON_SDCH plus
-                      // RESPONSE_TENTATIVE_SDCH in ../filter/sdch_filter.cc.
-    META_REFRESH_UNSUPPORTED = 74,         // Unrecoverable error.
-    CACHED_META_REFRESH_UNSUPPORTED = 75,  // As above, but pulled from cache.
-    PASSING_THROUGH_NON_SDCH = 76,  // Tagged sdch but missing dictionary-hash.
-    INCOMPLETE_SDCH_CONTENT = 77,   // Last window was not completely decoded.
-    PASS_THROUGH_404_CODE = 78,     // URL not found message passing through.
-
-    // This next report is very common, and not really an error scenario, but
-    // it exercises the error recovery logic.
-    PASS_THROUGH_OLD_CACHED = 79,   // Back button got pre-SDCH cached content.
-
-    // Common decoded recovery methods.
-    META_REFRESH_CACHED_RECOVERY = 80,  // Probably startup tab loading.
-    // defunct = 81, // Now tracked by ResponseCorruptionDetectionCause histo.
-
-    // Non SDCH problems, only accounted for to make stat counting complete
-    // (i.e., be able to be sure all dictionary advertisements are accounted
-    // for).
-
-    UNFLUSHED_CONTENT = 90,    // Possible error in filter chaining.
-    // defunct = 91,           // MISSING_TIME_STATS (Should never happen.)
-    CACHE_DECODED = 92,        // No timing stats recorded.
-    // defunct = 93,           // OVER_10_MINUTES (No timing stats recorded.)
-    UNINITIALIZED = 94,        // Filter never even got initialized.
-    PRIOR_TO_DICTIONARY = 95,  // We hadn't even parsed a dictionary selector.
-    DECODE_ERROR = 96,         // Something went wrong during decode.
-
-    // Problem during the latency test.
-    LATENCY_TEST_DISALLOWED = 100,  // SDCH now failing, but it worked before!
-
-    MAX_PROBLEM_CODE  // Used to bound histogram.
-  };
-
   // Use the following static limits to block DOS attacks until we implement
   // a cached dictionary evicition strategy.
   static const size_t kMaxDictionarySize;
@@ -167,19 +72,25 @@
 
     const GURL& url() const { return url_; }
     const std::string& client_hash() const { return client_hash_; }
+    const std::string& domain() const { return domain_; }
+    const std::string& path() const { return path_; }
+    const base::Time& expiration() const { return expiration_; }
+    const std::set<int>& ports() const { return ports_; }
 
     // Security method to check if we can advertise this dictionary for use
     // if the |target_url| returns SDCH compressed data.
-    bool CanAdvertise(const GURL& target_url);
+    SdchProblemCode CanAdvertise(const GURL& target_url) const;
 
     // Security methods to check if we can establish a new dictionary with the
     // given data, that arrived in response to get of dictionary_url.
-    static bool CanSet(const std::string& domain, const std::string& path,
-                       const std::set<int>& ports, const GURL& dictionary_url);
+    static SdchProblemCode CanSet(const std::string& domain,
+                                  const std::string& path,
+                                  const std::set<int>& ports,
+                                  const GURL& dictionary_url);
 
     // Security method to check if we can use a dictionary to decompress a
     // target that arrived with a reference to this dictionary.
-    bool CanUse(const GURL& referring_url);
+    SdchProblemCode CanUse(const GURL& referring_url) const;
 
     // Compare paths to see if they "match" for dictionary use.
     static bool PathMatch(const std::string& path,
@@ -188,7 +99,6 @@
     // Compare domains to see if the "match" for dictionary use.
     static bool DomainMatch(const GURL& url, const std::string& restriction);
 
-
     // The actual text of the dictionary.
     std::string text_;
 
@@ -218,7 +128,7 @@
   void ClearData();
 
   // Record stats on various errors.
-  static void SdchErrorRecovery(ProblemCodes problem);
+  static void SdchErrorRecovery(SdchProblemCode problem);
 
   // Enables or disables SDCH compression.
   static void EnableSdchSupport(bool enabled);
@@ -237,11 +147,12 @@
   // Used when filter errors are found from a given domain, but it is plausible
   // that the cause is temporary (such as application startup, where cached
   // entries are used, but a dictionary is not yet loaded).
-  void BlacklistDomain(const GURL& url, ProblemCodes blacklist_reason);
+  void BlacklistDomain(const GURL& url, SdchProblemCode blacklist_reason);
 
   // Used when SEVERE filter errors are found from a given domain, to prevent
   // further use of SDCH on that domain.
-  void BlacklistDomainForever(const GURL& url, ProblemCodes blacklist_reason);
+  void BlacklistDomainForever(const GURL& url,
+                              SdchProblemCode blacklist_reason);
 
   // Unit test only, this function resets enabling of sdch, and clears the
   // blacklist.
@@ -260,11 +171,12 @@
   // supported domain (i.e., not blacklisted, and either the specific supported
   // domain, or all domains were assumed supported). If it is blacklist, reduce
   // by 1 the number of times it will be reported as blacklisted.
-  bool IsInSupportedDomain(const GURL& url);
+  SdchProblemCode IsInSupportedDomain(const GURL& url);
 
   // Send out appropriate events notifying observers that a Get-Dictionary
   // header has been seen.
-  void OnGetDictionary(const GURL& request_url, const GURL& dictionary_url);
+  SdchProblemCode OnGetDictionary(const GURL& request_url,
+                                  const GURL& dictionary_url);
 
   // Find the vcdiff dictionary (the body of the sdch dictionary that appears
   // after the meta-data headers like Domain:...) with the given |server_hash|
@@ -272,9 +184,12 @@
   // be sure the returned |dictionary| can be used for decoding content supplied
   // in response to a request for |referring_url|.
   // Return null in |dictionary| if there is no matching legal dictionary.
-  void GetVcdiffDictionary(const std::string& server_hash,
-                           const GURL& referring_url,
-                           scoped_refptr<Dictionary>* dictionary);
+  // Returns SDCH_OK if dictionary is not found, SDCH(-over-https) is disabled,
+  // or if matching legal dictionary exists. Otherwise returns the
+  // corresponding problem code.
+  SdchProblemCode GetVcdiffDictionary(const std::string& server_hash,
+                                      const GURL& referring_url,
+                                      scoped_refptr<Dictionary>* dictionary);
 
   // Get list of available (pre-cached) dictionaries that we have already loaded
   // into memory. The list is a comma separated list of (client) hashes per
@@ -295,12 +210,16 @@
 
   void SetAllowLatencyExperiment(const GURL& url, bool enable);
 
+  base::Value* SdchInfoToValue() const;
+
   // Add an SDCH dictionary to our list of availible
   // dictionaries. This addition will fail if addition is illegal
   // (data in the dictionary is not acceptable from the
   // dictionary_url; dictionary already added, etc.).
-  void AddSdchDictionary(const std::string& dictionary_text,
-                         const GURL& dictionary_url);
+  // Returns SDCH_OK if the addition was successfull, and corresponding error
+  // code otherwise.
+  SdchProblemCode AddSdchDictionary(const std::string& dictionary_text,
+                                    const GURL& dictionary_url);
 
   // Registration for events generated by the SDCH subsystem.
   void AddObserver(SdchObserver* observer);
@@ -308,24 +227,20 @@
 
  private:
   struct BlacklistInfo {
-    BlacklistInfo()
-        : count(0),
-          exponential_count(0),
-          reason(MIN_PROBLEM_CODE) {}
+    BlacklistInfo() : count(0), exponential_count(0), reason(SDCH_OK) {}
 
-    int count;                   // # of times to refuse SDCH advertisement.
-    int exponential_count;       // Current exponential backoff ratchet.
-    ProblemCodes reason;         // Why domain was blacklisted.
-
+    int count;               // # of times to refuse SDCH advertisement.
+    int exponential_count;   // Current exponential backoff ratchet.
+    SdchProblemCode reason;  // Why domain was blacklisted.
   };
   typedef std::map<std::string, BlacklistInfo> DomainBlacklistInfo;
   typedef std::set<std::string> ExperimentSet;
 
   // Determines whether a "Get-Dictionary" header is legal (dictionary
   // url has appropriate relationship to referrer url) in the SDCH
-  // protocol.  Return true if fetch is legal.
-  bool CanFetchDictionary(const GURL& referring_url,
-                          const GURL& dictionary_url) const;
+  // protocol.  Return SDCH_OK if fetch is legal.
+  SdchProblemCode CanFetchDictionary(const GURL& referring_url,
+                                     const GURL& dictionary_url) const;
 
   // A map of dictionaries info indexed by the hash that the server provides.
   typedef std::map<std::string, scoped_refptr<Dictionary> > DictionaryMap;
@@ -340,6 +255,7 @@
   // A simple implementation of a RFC 3548 "URL safe" base64 encoder.
   static void UrlSafeBase64Encode(const std::string& input,
                                   std::string* output);
+
   DictionaryMap dictionaries_;
 
   // List domains where decode failures have required disabling sdch.
diff --git a/net/base/sdch_manager_unittest.cc b/net/base/sdch_manager_unittest.cc
index d986879..c20be58 100644
--- a/net/base/sdch_manager_unittest.cc
+++ b/net/base/sdch_manager_unittest.cc
@@ -8,6 +8,7 @@
 
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
+#include "net/base/net_log.h"
 #include "net/base/sdch_manager.h"
 #include "net/base/sdch_observer.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -73,14 +74,7 @@
   // failure.
   bool AddSdchDictionary(const std::string& dictionary_text,
                          const GURL& gurl) {
-    std::string list;
-    sdch_manager_->GetAvailDictionaryList(gurl, &list);
-    sdch_manager_->AddSdchDictionary(dictionary_text, gurl);
-    std::string list2;
-    sdch_manager_->GetAvailDictionaryList(gurl, &list2);
-
-    // The list of hashes should change iff the addition succeeds.
-    return (list != list2);
+    return sdch_manager_->AddSdchDictionary(dictionary_text, gurl) == SDCH_OK;
   }
 
  private:
@@ -105,31 +99,34 @@
   GURL google_url("http://www.google.com");
 
   SdchManager::EnableSdchSupport(false);
-  EXPECT_FALSE(sdch_manager()->IsInSupportedDomain(google_url));
+  EXPECT_EQ(SDCH_DISABLED, sdch_manager()->IsInSupportedDomain(google_url));
   SdchManager::EnableSdchSupport(true);
-  EXPECT_TRUE(sdch_manager()->IsInSupportedDomain(google_url));
+  EXPECT_EQ(SDCH_OK, sdch_manager()->IsInSupportedDomain(google_url));
 }
 
 TEST_F(SdchManagerTest, DomainBlacklisting) {
   GURL test_url("http://www.test.com");
   GURL google_url("http://www.google.com");
 
-  sdch_manager()->BlacklistDomain(test_url, SdchManager::MIN_PROBLEM_CODE);
-  EXPECT_FALSE(sdch_manager()->IsInSupportedDomain(test_url));
-  EXPECT_TRUE(sdch_manager()->IsInSupportedDomain(google_url));
+  sdch_manager()->BlacklistDomain(test_url, SDCH_OK);
+  EXPECT_EQ(SDCH_DOMAIN_BLACKLIST_INCLUDES_TARGET,
+            sdch_manager()->IsInSupportedDomain(test_url));
+  EXPECT_EQ(SDCH_OK, sdch_manager()->IsInSupportedDomain(google_url));
 
-  sdch_manager()->BlacklistDomain(google_url, SdchManager::MIN_PROBLEM_CODE);
-  EXPECT_FALSE(sdch_manager()->IsInSupportedDomain(google_url));
+  sdch_manager()->BlacklistDomain(google_url, SDCH_OK);
+  EXPECT_EQ(SDCH_DOMAIN_BLACKLIST_INCLUDES_TARGET,
+            sdch_manager()->IsInSupportedDomain(google_url));
 }
 
 TEST_F(SdchManagerTest, DomainBlacklistingCaseSensitivity) {
   GURL test_url("http://www.TesT.com");
   GURL test2_url("http://www.tEst.com");
 
-  EXPECT_TRUE(sdch_manager()->IsInSupportedDomain(test_url));
-  EXPECT_TRUE(sdch_manager()->IsInSupportedDomain(test2_url));
-  sdch_manager()->BlacklistDomain(test_url, SdchManager::MIN_PROBLEM_CODE);
-  EXPECT_FALSE(sdch_manager()->IsInSupportedDomain(test2_url));
+  EXPECT_EQ(SDCH_OK, sdch_manager()->IsInSupportedDomain(test_url));
+  EXPECT_EQ(SDCH_OK, sdch_manager()->IsInSupportedDomain(test2_url));
+  sdch_manager()->BlacklistDomain(test_url, SDCH_OK);
+  EXPECT_EQ(SDCH_DOMAIN_BLACKLIST_INCLUDES_TARGET,
+            sdch_manager()->IsInSupportedDomain(test2_url));
 }
 
 TEST_F(SdchManagerTest, BlacklistingReset) {
@@ -139,7 +136,7 @@
   sdch_manager()->ClearBlacklistings();
   EXPECT_EQ(sdch_manager()->BlackListDomainCount(domain), 0);
   EXPECT_EQ(sdch_manager()->BlacklistDomainExponential(domain), 0);
-  EXPECT_TRUE(sdch_manager()->IsInSupportedDomain(gurl));
+  EXPECT_EQ(SDCH_OK, sdch_manager()->IsInSupportedDomain(gurl));
 }
 
 TEST_F(SdchManagerTest, BlacklistingSingleBlacklist) {
@@ -147,14 +144,15 @@
   std::string domain(gurl.host());
   sdch_manager()->ClearBlacklistings();
 
-  sdch_manager()->BlacklistDomain(gurl, SdchManager::MIN_PROBLEM_CODE);
+  sdch_manager()->BlacklistDomain(gurl, SDCH_OK);
   EXPECT_EQ(sdch_manager()->BlackListDomainCount(domain), 1);
   EXPECT_EQ(sdch_manager()->BlacklistDomainExponential(domain), 1);
 
   // Check that any domain lookup reduces the blacklist counter.
-  EXPECT_FALSE(sdch_manager()->IsInSupportedDomain(gurl));
+  EXPECT_EQ(SDCH_DOMAIN_BLACKLIST_INCLUDES_TARGET,
+            sdch_manager()->IsInSupportedDomain(gurl));
   EXPECT_EQ(sdch_manager()->BlackListDomainCount(domain), 0);
-  EXPECT_TRUE(sdch_manager()->IsInSupportedDomain(gurl));
+  EXPECT_EQ(SDCH_OK, sdch_manager()->IsInSupportedDomain(gurl));
 }
 
 TEST_F(SdchManagerTest, BlacklistingExponential) {
@@ -164,18 +162,19 @@
 
   int exponential = 1;
   for (int i = 1; i < 100; ++i) {
-    sdch_manager()->BlacklistDomain(gurl, SdchManager::MIN_PROBLEM_CODE);
+    sdch_manager()->BlacklistDomain(gurl, SDCH_OK);
     EXPECT_EQ(sdch_manager()->BlacklistDomainExponential(domain), exponential);
 
     EXPECT_EQ(sdch_manager()->BlackListDomainCount(domain), exponential);
-    EXPECT_FALSE(sdch_manager()->IsInSupportedDomain(gurl));
+    EXPECT_EQ(SDCH_DOMAIN_BLACKLIST_INCLUDES_TARGET,
+              sdch_manager()->IsInSupportedDomain(gurl));
     EXPECT_EQ(sdch_manager()->BlackListDomainCount(domain), exponential - 1);
 
     // Simulate a large number of domain checks (which eventually remove the
     // blacklisting).
     sdch_manager()->ClearDomainBlacklisting(domain);
     EXPECT_EQ(sdch_manager()->BlackListDomainCount(domain), 0);
-    EXPECT_TRUE(sdch_manager()->IsInSupportedDomain(gurl));
+    EXPECT_EQ(SDCH_OK, sdch_manager()->IsInSupportedDomain(gurl));
 
     // Predict what exponential backoff will be.
     exponential = 1 + 2 * exponential;
@@ -246,7 +245,8 @@
   std::string client_hash;
   std::string server_hash;
   sdch_manager()->GenerateHash(dictionary_text, &client_hash, &server_hash);
-  sdch_manager()->GetVcdiffDictionary(server_hash, target_url, &dictionary);
+  EXPECT_EQ(SDCH_OK, sdch_manager()->GetVcdiffDictionary(
+                         server_hash, target_url, &dictionary));
   EXPECT_TRUE(dictionary.get() != NULL);
 }
 
@@ -269,7 +269,9 @@
   std::string client_hash;
   std::string server_hash;
   sdch_manager()->GenerateHash(dictionary_text, &client_hash, &server_hash);
-  sdch_manager()->GetVcdiffDictionary(server_hash, target_url, &dictionary);
+  EXPECT_EQ(SDCH_DICTIONARY_FOUND_HAS_WRONG_SCHEME,
+            sdch_manager()->GetVcdiffDictionary(server_hash, target_url,
+                                                &dictionary));
   EXPECT_TRUE(dictionary.get() == NULL);
 }
 
@@ -292,7 +294,9 @@
   std::string client_hash;
   std::string server_hash;
   sdch_manager()->GenerateHash(dictionary_text, &client_hash, &server_hash);
-  sdch_manager()->GetVcdiffDictionary(server_hash, target_url, &dictionary);
+  EXPECT_EQ(SDCH_DICTIONARY_FOUND_HAS_WRONG_SCHEME,
+            sdch_manager()->GetVcdiffDictionary(server_hash, target_url,
+                                                &dictionary));
   EXPECT_TRUE(dictionary.get() == NULL);
 }
 
@@ -516,10 +520,10 @@
   EXPECT_TRUE(AddSdchDictionary(dictionary_text_1,
                                 GURL("http://" + dictionary_domain_1)));
   scoped_refptr<SdchManager::Dictionary> dictionary;
-  sdch_manager()->GetVcdiffDictionary(
-      server_hash_1,
-      GURL("http://" + dictionary_domain_1 + "/random_url"),
-      &dictionary);
+  EXPECT_EQ(SDCH_OK, sdch_manager()->GetVcdiffDictionary(
+                         server_hash_1,
+                         GURL("http://" + dictionary_domain_1 + "/random_url"),
+                         &dictionary));
   EXPECT_TRUE(dictionary.get());
 
   second_manager.AddSdchDictionary(
@@ -530,16 +534,18 @@
       &dictionary);
   EXPECT_TRUE(dictionary.get());
 
-  sdch_manager()->GetVcdiffDictionary(
-      server_hash_2,
-      GURL("http://" + dictionary_domain_2 + "/random_url"),
-      &dictionary);
+  EXPECT_EQ(
+      SDCH_DICTIONARY_HASH_NOT_FOUND,
+      sdch_manager()->GetVcdiffDictionary(
+          server_hash_2, GURL("http://" + dictionary_domain_2 + "/random_url"),
+          &dictionary));
   EXPECT_FALSE(dictionary.get());
 
-  second_manager.GetVcdiffDictionary(
-      server_hash_1,
-      GURL("http://" + dictionary_domain_1 + "/random_url"),
-      &dictionary);
+  EXPECT_EQ(
+      SDCH_DICTIONARY_HASH_NOT_FOUND,
+      second_manager.GetVcdiffDictionary(
+          server_hash_1, GURL("http://" + dictionary_domain_1 + "/random_url"),
+          &dictionary));
   EXPECT_FALSE(dictionary.get());
 }
 
@@ -549,14 +555,15 @@
 
   bool expect_https_support = true;
 
-  EXPECT_TRUE(sdch_manager()->IsInSupportedDomain(url));
-  EXPECT_EQ(expect_https_support,
-            sdch_manager()->IsInSupportedDomain(secure_url));
+  SdchProblemCode expected_code =
+      expect_https_support ? SDCH_OK : SDCH_SECURE_SCHEME_NOT_SUPPORTED;
+
+  EXPECT_EQ(SDCH_OK, sdch_manager()->IsInSupportedDomain(url));
+  EXPECT_EQ(expected_code, sdch_manager()->IsInSupportedDomain(secure_url));
 
   SdchManager::EnableSecureSchemeSupport(!expect_https_support);
-  EXPECT_TRUE(sdch_manager()->IsInSupportedDomain(url));
-  EXPECT_NE(expect_https_support,
-            sdch_manager()->IsInSupportedDomain(secure_url));
+  EXPECT_EQ(SDCH_OK, sdch_manager()->IsInSupportedDomain(url));
+  EXPECT_NE(expected_code, sdch_manager()->IsInSupportedDomain(secure_url));
 }
 
 TEST_F(SdchManagerTest, ClearDictionaryData) {
@@ -572,25 +579,26 @@
   EXPECT_TRUE(AddSdchDictionary(dictionary_text,
                                 GURL("http://" + dictionary_domain)));
   scoped_refptr<SdchManager::Dictionary> dictionary;
-  sdch_manager()->GetVcdiffDictionary(
-      server_hash,
-      GURL("http://" + dictionary_domain + "/random_url"),
-      &dictionary);
+  EXPECT_EQ(SDCH_OK, sdch_manager()->GetVcdiffDictionary(
+                         server_hash,
+                         GURL("http://" + dictionary_domain + "/random_url"),
+                         &dictionary));
   EXPECT_TRUE(dictionary.get());
 
-  sdch_manager()->BlacklistDomain(GURL(blacklist_url),
-                                  SdchManager::MIN_PROBLEM_CODE);
-  EXPECT_FALSE(sdch_manager()->IsInSupportedDomain(blacklist_url));
+  sdch_manager()->BlacklistDomain(GURL(blacklist_url), SDCH_OK);
+  EXPECT_EQ(SDCH_DOMAIN_BLACKLIST_INCLUDES_TARGET,
+            sdch_manager()->IsInSupportedDomain(blacklist_url));
 
   sdch_manager()->ClearData();
 
   dictionary = NULL;
-  sdch_manager()->GetVcdiffDictionary(
-      server_hash,
-      GURL("http://" + dictionary_domain + "/random_url"),
-      &dictionary);
+  EXPECT_EQ(
+      SDCH_DICTIONARY_HASH_NOT_FOUND,
+      sdch_manager()->GetVcdiffDictionary(
+          server_hash, GURL("http://" + dictionary_domain + "/random_url"),
+          &dictionary));
   EXPECT_FALSE(dictionary.get());
-  EXPECT_TRUE(sdch_manager()->IsInSupportedDomain(blacklist_url));
+  EXPECT_EQ(SDCH_OK, sdch_manager()->IsInSupportedDomain(blacklist_url));
 }
 
 TEST_F(SdchManagerTest, GetDictionaryNotification) {
diff --git a/net/base/sdch_net_log_params.cc b/net/base/sdch_net_log_params.cc
new file mode 100644
index 0000000..02e0ad7
--- /dev/null
+++ b/net/base/sdch_net_log_params.cc
@@ -0,0 +1,34 @@
+// 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 "net/base/sdch_net_log_params.h"
+
+#include "base/values.h"
+#include "net/base/net_errors.h"
+#include "url/gurl.h"
+
+namespace net {
+
+base::Value* NetLogSdchResourceProblemCallback(SdchProblemCode problem,
+                                               NetLog::LogLevel log_level) {
+  base::DictionaryValue* dict = new base::DictionaryValue();
+  dict->SetInteger("sdch_problem_code", problem);
+  dict->SetInteger("net_error", ERR_FAILED);
+  return dict;
+}
+
+base::Value* NetLogSdchDictionaryFetchProblemCallback(
+    SdchProblemCode problem,
+    const GURL& url,
+    bool is_error,
+    NetLog::LogLevel log_level) {
+  base::DictionaryValue* dict = new base::DictionaryValue();
+  dict->SetInteger("sdch_problem_code", problem);
+  dict->SetString("dictionary_url", url.spec());
+  if (is_error)
+    dict->SetInteger("net_error", ERR_FAILED);
+  return dict;
+}
+
+}  // namespace net
diff --git a/net/base/sdch_net_log_params.h b/net/base/sdch_net_log_params.h
new file mode 100644
index 0000000..7421a0a
--- /dev/null
+++ b/net/base/sdch_net_log_params.h
@@ -0,0 +1,32 @@
+// 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 NET_BASE_SDCH_NET_LOG_PARAMS_H_
+#define NET_BASE_SDCH_NET_LOG_PARAMS_H_
+
+#include <string>
+
+#include "net/base/net_export.h"
+#include "net/base/net_log.h"
+#include "net/base/sdch_problem_codes.h"
+
+class GURL;
+
+namespace net {
+
+NET_EXPORT base::Value* NetLogSdchResourceProblemCallback(
+    SdchProblemCode problem,
+    NetLog::LogLevel log_level);
+
+// If |is_error| is false, "net_error" field won't be added to the JSON and the
+// event won't be painted red in the netlog.
+NET_EXPORT base::Value* NetLogSdchDictionaryFetchProblemCallback(
+    SdchProblemCode problem,
+    const GURL& url,
+    bool is_error,
+    NetLog::LogLevel log_level);
+
+}  // namespace net
+
+#endif  // NET_BASE_SDCH_NET_LOG_PARAMS_H_
diff --git a/net/base/sdch_problem_code_list.h b/net/base/sdch_problem_code_list.h
new file mode 100644
index 0000000..4efc17c
--- /dev/null
+++ b/net/base/sdch_problem_code_list.h
@@ -0,0 +1,127 @@
+// 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.
+
+// This file intentionally does not have header guards, it's included
+// inside a macro to generate enum values.
+
+// This file contains list of sdch-related problem codes.
+// No error.
+SDCH_PROBLEM_CODE(OK, 0)
+
+// Content-encoding correction problems.
+SDCH_PROBLEM_CODE(ADDED_CONTENT_ENCODING, 1)
+SDCH_PROBLEM_CODE(FIXED_CONTENT_ENCODING, 2)
+SDCH_PROBLEM_CODE(FIXED_CONTENT_ENCODINGS, 3)
+
+// Content decoding errors.
+SDCH_PROBLEM_CODE(DECODE_HEADER_ERROR, 4)
+SDCH_PROBLEM_CODE(DECODE_BODY_ERROR, 5)
+
+// More content-encoding correction problems.
+SDCH_PROBLEM_CODE(OPTIONAL_GUNZIP_ENCODING_ADDED, 6)
+
+// Content encoding correction when we're not even tagged as HTML!?!
+SDCH_PROBLEM_CODE(BINARY_ADDED_CONTENT_ENCODING, 7)
+SDCH_PROBLEM_CODE(BINARY_FIXED_CONTENT_ENCODING, 8)
+SDCH_PROBLEM_CODE(BINARY_FIXED_CONTENT_ENCODINGS, 9)
+
+// Dictionary selection for use problems.
+SDCH_PROBLEM_CODE(DICTIONARY_FOUND_HAS_WRONG_DOMAIN, 10)
+SDCH_PROBLEM_CODE(DICTIONARY_FOUND_HAS_WRONG_PORT_LIST, 11)
+SDCH_PROBLEM_CODE(DICTIONARY_FOUND_HAS_WRONG_PATH, 12)
+SDCH_PROBLEM_CODE(DICTIONARY_FOUND_HAS_WRONG_SCHEME, 13)
+SDCH_PROBLEM_CODE(DICTIONARY_HASH_NOT_FOUND, 14)
+SDCH_PROBLEM_CODE(DICTIONARY_HASH_MALFORMED, 15)
+SDCH_PROBLEM_CODE(DICTIONARY_FOUND_EXPIRED, 16)
+
+// Dictionary saving problems.
+SDCH_PROBLEM_CODE(DICTIONARY_HAS_NO_HEADER, 20)
+SDCH_PROBLEM_CODE(DICTIONARY_HEADER_LINE_MISSING_COLON, 21)
+SDCH_PROBLEM_CODE(DICTIONARY_MISSING_DOMAIN_SPECIFIER, 22)
+SDCH_PROBLEM_CODE(DICTIONARY_SPECIFIES_TOP_LEVEL_DOMAIN, 23)
+SDCH_PROBLEM_CODE(DICTIONARY_DOMAIN_NOT_MATCHING_SOURCE_URL, 24)
+SDCH_PROBLEM_CODE(DICTIONARY_PORT_NOT_MATCHING_SOURCE_URL, 25)
+SDCH_PROBLEM_CODE(DICTIONARY_HAS_NO_TEXT, 26)
+SDCH_PROBLEM_CODE(DICTIONARY_REFERER_URL_HAS_DOT_IN_PREFIX, 27)
+SDCH_PROBLEM_CODE(DICTIONARY_UNSUPPORTED_VERSION, 28)
+
+// Dictionary loading problems.
+SDCH_PROBLEM_CODE(DICTIONARY_LOAD_ATTEMPT_FROM_DIFFERENT_HOST, 30)
+SDCH_PROBLEM_CODE(DICTIONARY_SELECTED_FOR_SSL, 31)
+SDCH_PROBLEM_CODE(DICTIONARY_ALREADY_LOADED, 32)
+SDCH_PROBLEM_CODE(DICTIONARY_SELECTED_FROM_NON_HTTP, 33)
+SDCH_PROBLEM_CODE(DICTIONARY_IS_TOO_LARGE, 34)
+SDCH_PROBLEM_CODE(DICTIONARY_COUNT_EXCEEDED, 35)
+// defunct = 36, // DICTIONARY_PREVIOUSLY_SCHEDULED_TO_DOWNLOAD used instead.
+// defunct = 37, // DICTIONARY_PREVIOUSLY_SCHEDULED_TO_DOWNLOAD used instead.
+SDCH_PROBLEM_CODE(DICTIONARY_FETCH_READ_FAILED, 38)
+SDCH_PROBLEM_CODE(DICTIONARY_PREVIOUSLY_SCHEDULED_TO_DOWNLOAD, 39)
+
+// Failsafe hack.
+SDCH_PROBLEM_CODE(ATTEMPT_TO_DECODE_NON_HTTP_DATA, 40)
+
+// Content-Encoding problems detected, with no action taken.
+SDCH_PROBLEM_CODE(MULTIENCODING_FOR_NON_SDCH_REQUEST, 50)
+SDCH_PROBLEM_CODE(SDCH_CONTENT_ENCODE_FOR_NON_SDCH_REQUEST, 51)
+
+// Dictionary manager issues.
+SDCH_PROBLEM_CODE(DOMAIN_BLACKLIST_INCLUDES_TARGET, 61)
+
+// Problematic decode recovery methods.
+// Dictionary not found.
+SDCH_PROBLEM_CODE(META_REFRESH_RECOVERY, 70)
+// defunct =  71, // Almost the same as META_REFRESH_UNSUPPORTED.
+// defunct = 72,  // Almost the same as CACHED_META_REFRESH_UNSUPPORTED.
+// defunct = 73,  // PASSING_THROUGH_NON_SDCH plus DISCARD_TENTATIVE_SDCH.
+// Unrecoverable error.
+SDCH_PROBLEM_CODE(META_REFRESH_UNSUPPORTED, 74)
+// As above, but pulled from cache.
+SDCH_PROBLEM_CODE(CACHED_META_REFRESH_UNSUPPORTED, 75)
+// Tagged sdch but missing dictionary-hash.
+SDCH_PROBLEM_CODE(PASSING_THROUGH_NON_SDCH, 76)
+// Last window was not completely decoded.
+SDCH_PROBLEM_CODE(INCOMPLETE_SDCH_CONTENT, 77)
+// URL not found message passing through.
+SDCH_PROBLEM_CODE(PASS_THROUGH_404_CODE, 78)
+
+// This next report is very common, and not really an error scenario, but
+// it exercises the error recovery logic.
+// Back button got pre-SDCH cached content.
+SDCH_PROBLEM_CODE(PASS_THROUGH_OLD_CACHED, 79)
+
+// Common decoded recovery methods.
+// Probably startup tab loading.
+SDCH_PROBLEM_CODE(META_REFRESH_CACHED_RECOVERY, 80)
+// defunct = 81, // Now tracked by ResponseCorruptionDetectionCause histo.
+
+// Non SDCH problems, only accounted for to make stat counting complete
+// (i.e., be able to be sure all dictionary advertisements are accounted
+// for).
+// Possible error in filter chaining.
+SDCH_PROBLEM_CODE(UNFLUSHED_CONTENT, 90)
+// defunct = 91,           // MISSING_TIME_STATS (Should never happen.)
+// No timing stats recorded.
+SDCH_PROBLEM_CODE(CACHE_DECODED, 92)
+// defunct = 93,           // OVER_10_MINUTES (No timing stats recorded.)
+// Filter never even got initialized.
+SDCH_PROBLEM_CODE(UNINITIALIZED, 94)
+// We hadn't even parsed a dictionary selector.
+SDCH_PROBLEM_CODE(PRIOR_TO_DICTIONARY, 95)
+// Something went wrong during decode.
+SDCH_PROBLEM_CODE(DECODE_ERROR, 96)
+
+// Problem during the latency test.
+// SDCH now failing, but it worked before!
+SDCH_PROBLEM_CODE(LATENCY_TEST_DISALLOWED, 100)
+
+// General SDCH problems.
+// SDCH is disabled.
+SDCH_PROBLEM_CODE(DISABLED, 105)
+// SDCH over https is disabled.
+SDCH_PROBLEM_CODE(SECURE_SCHEME_NOT_SUPPORTED, 106)
+
+// Used to bound histogram.
+SDCH_PROBLEM_CODE(MAX_PROBLEM_CODE, 110)
+
+// These values are not used in histograms.
diff --git a/net/base/sdch_problem_codes.h b/net/base/sdch_problem_codes.h
new file mode 100644
index 0000000..da979fc
--- /dev/null
+++ b/net/base/sdch_problem_codes.h
@@ -0,0 +1,20 @@
+// 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 NET_BASE_SDCH_PROBLEM_CODES_H_
+#define NET_BASE_SDCH_PROBLEM_CODES_H_
+
+namespace net {
+
+// A list of errors that appeared and were either resolved, or used to turn
+// off sdch encoding.
+enum SdchProblemCode {
+#define SDCH_PROBLEM_CODE(label, value) SDCH_##label = value,
+#include "net/base/sdch_problem_code_list.h"
+#undef SDCH_PROBLEM_CODE
+};
+
+}  // namespace net
+
+#endif  // NET_BASE_SDCH_PROBLEM_CODES_H_
diff --git a/net/filter/filter.cc b/net/filter/filter.cc
index c8a4740..c9a56bd 100644
--- a/net/filter/filter.cc
+++ b/net/filter/filter.cc
@@ -28,11 +28,14 @@
 #include "net/base/filename_util_unsafe.h"
 #include "net/base/io_buffer.h"
 #include "net/base/mime_util.h"
+#include "net/base/sdch_net_log_params.h"
 #include "net/filter/gzip_filter.h"
 #include "net/filter/sdch_filter.h"
 #include "net/url_request/url_request_context.h"
 #include "url/gurl.h"
 
+namespace net {
+
 namespace {
 
 // Filter types (using canonical lower case only):
@@ -53,9 +56,15 @@
 // Buffer size allocated when de-compressing data.
 const int kFilterBufSize = 32 * 1024;
 
-}  // namespace
+void LogSdchProblem(const FilterContext& filter_context,
+                    SdchProblemCode problem) {
+  SdchManager::SdchErrorRecovery(problem);
+  filter_context.GetNetLog().AddEvent(
+      NetLog::TYPE_SDCH_DECODING_ERROR,
+      base::Bind(&NetLogSdchResourceProblemCallback, problem));
+}
 
-namespace net {
+}  // namespace
 
 FilterContext::~FilterContext() {
 }
@@ -233,13 +242,12 @@
     // It was not an SDCH request, so we'll just record stats.
     if (1 < encoding_types->size()) {
       // Multiple filters were intended to only be used for SDCH (thus far!)
-      SdchManager::SdchErrorRecovery(
-          SdchManager::MULTIENCODING_FOR_NON_SDCH_REQUEST);
+      LogSdchProblem(filter_context, SDCH_MULTIENCODING_FOR_NON_SDCH_REQUEST);
     }
     if ((1 == encoding_types->size()) &&
         (FILTER_TYPE_SDCH == encoding_types->front())) {
-        SdchManager::SdchErrorRecovery(
-            SdchManager::SDCH_CONTENT_ENCODE_FOR_NON_SDCH_REQUEST);
+      LogSdchProblem(filter_context,
+                     SDCH_SDCH_CONTENT_ENCODE_FOR_NON_SDCH_REQUEST);
     }
     return;
   }
@@ -259,8 +267,7 @@
     // no-op pass through filter if it doesn't get gzip headers where expected.
     if (1 == encoding_types->size()) {
       encoding_types->push_back(FILTER_TYPE_GZIP_HELPING_SDCH);
-      SdchManager::SdchErrorRecovery(
-          SdchManager::OPTIONAL_GUNZIP_ENCODING_ADDED);
+      LogSdchProblem(filter_context, SDCH_OPTIONAL_GUNZIP_ENCODING_ADDED);
     }
     return;
   }
@@ -294,14 +301,11 @@
     // Suspicious case: Advertised dictionary, but server didn't use sdch, and
     // we're HTML tagged.
     if (encoding_types->empty()) {
-      SdchManager::SdchErrorRecovery(
-          SdchManager::ADDED_CONTENT_ENCODING);
+      LogSdchProblem(filter_context, SDCH_ADDED_CONTENT_ENCODING);
     } else if (1 == encoding_types->size()) {
-      SdchManager::SdchErrorRecovery(
-          SdchManager::FIXED_CONTENT_ENCODING);
+      LogSdchProblem(filter_context, SDCH_FIXED_CONTENT_ENCODING);
     } else {
-      SdchManager::SdchErrorRecovery(
-          SdchManager::FIXED_CONTENT_ENCODINGS);
+      LogSdchProblem(filter_context, SDCH_FIXED_CONTENT_ENCODINGS);
     }
   } else {
     // Remarkable case!?!  We advertised an SDCH dictionary, content-encoding
@@ -313,14 +317,11 @@
     // start with "text/html" for some other reason??  We'll report this as a
     // fixup to a binary file, but it probably really is text/html (some how).
     if (encoding_types->empty()) {
-      SdchManager::SdchErrorRecovery(
-          SdchManager::BINARY_ADDED_CONTENT_ENCODING);
+      LogSdchProblem(filter_context, SDCH_BINARY_ADDED_CONTENT_ENCODING);
     } else if (1 == encoding_types->size()) {
-      SdchManager::SdchErrorRecovery(
-          SdchManager::BINARY_FIXED_CONTENT_ENCODING);
+      LogSdchProblem(filter_context, SDCH_BINARY_FIXED_CONTENT_ENCODING);
     } else {
-      SdchManager::SdchErrorRecovery(
-          SdchManager::BINARY_FIXED_CONTENT_ENCODINGS);
+      LogSdchProblem(filter_context, SDCH_BINARY_FIXED_CONTENT_ENCODINGS);
     }
   }
 
diff --git a/net/filter/filter.h b/net/filter/filter.h
index 37f55e2..13489ef 100644
--- a/net/filter/filter.h
+++ b/net/filter/filter.h
@@ -60,8 +60,9 @@
 
 namespace net {
 
-class URLRequestContext;
+class BoundNetLog;
 class IOBuffer;
+class URLRequestContext;
 
 //------------------------------------------------------------------------------
 // Define an interface class that allows access to contextual information
@@ -122,6 +123,9 @@
   // The following method forces the context to emit a specific set of
   // statistics as selected by the argument.
   virtual void RecordPacketStats(StatisticSelector statistic) const = 0;
+
+  // The BoundNetLog of the associated request.
+  virtual const BoundNetLog& GetNetLog() const = 0;
 };
 
 //------------------------------------------------------------------------------
diff --git a/net/filter/mock_filter_context.cc b/net/filter/mock_filter_context.cc
index e1e4793..35ab9ee 100644
--- a/net/filter/mock_filter_context.cc
+++ b/net/filter/mock_filter_context.cc
@@ -66,4 +66,8 @@
   return context_.get();
 }
 
+const BoundNetLog& MockFilterContext::GetNetLog() const {
+  return net_log_;
+}
+
 }  // namespace net
diff --git a/net/filter/mock_filter_context.h b/net/filter/mock_filter_context.h
index 8150e8b..41c9e9e 100644
--- a/net/filter/mock_filter_context.h
+++ b/net/filter/mock_filter_context.h
@@ -8,6 +8,7 @@
 #include <string>
 
 #include "base/memory/scoped_ptr.h"
+#include "net/base/net_log.h"
 #include "net/filter/filter.h"
 #include "url/gurl.h"
 
@@ -73,6 +74,8 @@
 
   void RecordPacketStats(StatisticSelector statistic) const override {}
 
+  const BoundNetLog& GetNetLog() const override;
+
  private:
   int buffer_size_;
   std::string mime_type_;
@@ -85,6 +88,7 @@
   bool ok_to_call_get_url_;
   int response_code_;
   scoped_ptr<URLRequestContext> context_;
+  BoundNetLog net_log_;
 
   DISALLOW_COPY_AND_ASSIGN(MockFilterContext);
 };
diff --git a/net/filter/sdch_filter.cc b/net/filter/sdch_filter.cc
index df72367..d03ff7f 100644
--- a/net/filter/sdch_filter.cc
+++ b/net/filter/sdch_filter.cc
@@ -11,7 +11,9 @@
 
 #include "base/logging.h"
 #include "base/metrics/histogram.h"
+#include "base/values.h"
 #include "net/base/sdch_manager.h"
+#include "net/base/sdch_net_log_params.h"
 #include "net/url_request/url_request_context.h"
 
 #include "sdch/open-vcdiff/src/google/vcdecoder.h"
@@ -50,6 +52,51 @@
   RESPONSE_MAX,
 };
 
+const char* ResponseCorruptionDetectionCauseToString(
+    ResponseCorruptionDetectionCause cause) {
+  const char* cause_string = "<unknown>";
+  switch (cause) {
+    case RESPONSE_NONE:
+      cause_string = "NONE";
+      break;
+    case RESPONSE_404:
+      cause_string = "404";
+      break;
+    case RESPONSE_NOT_200:
+      cause_string = "NOT_200";
+      break;
+    case RESPONSE_OLD_UNENCODED:
+      cause_string = "OLD_UNENCODED";
+      break;
+    case RESPONSE_TENTATIVE_SDCH:
+      cause_string = "TENTATIVE_SDCH";
+      break;
+    case RESPONSE_NO_DICTIONARY:
+      cause_string = "NO_DICTIONARY";
+      break;
+    case RESPONSE_CORRUPT_SDCH:
+      cause_string = "CORRUPT_SDCH";
+      break;
+    case RESPONSE_ENCODING_LIE:
+      cause_string = "ENCODING_LIE";
+      break;
+    case RESPONSE_MAX:
+      cause_string = "<Error: max enum value>";
+      break;
+  }
+  return cause_string;
+}
+
+base::Value* NetLogSdchResponseCorruptionDetectionCallback(
+    ResponseCorruptionDetectionCause cause,
+    bool cached,
+    NetLog::LogLevel log_level) {
+  base::DictionaryValue* dict = new base::DictionaryValue();
+  dict->SetString("cause", ResponseCorruptionDetectionCauseToString(cause));
+  dict->SetBoolean("cached", cached);
+  return dict;
+}
+
 }  // namespace
 
 SdchFilter::SdchFilter(const FilterContext& filter_context)
@@ -84,12 +131,12 @@
   if (vcdiff_streaming_decoder_.get()) {
     if (!vcdiff_streaming_decoder_->FinishDecoding()) {
       decoding_status_ = DECODING_ERROR;
-      SdchManager::SdchErrorRecovery(SdchManager::INCOMPLETE_SDCH_CONTENT);
+      LogSdchProblem(SDCH_INCOMPLETE_SDCH_CONTENT);
       // Make it possible for the user to hit reload, and get non-sdch content.
       // Note this will "wear off" quickly enough, and is just meant to assure
       // in some rare case that the user is not stuck.
       url_request_context_->sdch_manager()->BlacklistDomain(
-          url_, SdchManager::INCOMPLETE_SDCH_CONTENT);
+          url_, SDCH_INCOMPLETE_SDCH_CONTENT);
       UMA_HISTOGRAM_COUNTS("Sdch3.PartialBytesIn",
            static_cast<int>(filter_context_.GetByteReadCount()));
       UMA_HISTOGRAM_COUNTS("Sdch3.PartialVcdiffIn", source_bytes_);
@@ -99,7 +146,7 @@
 
   if (!dest_buffer_excess_.empty()) {
     // Filter chaining error, or premature teardown.
-    SdchManager::SdchErrorRecovery(SdchManager::UNFLUSHED_CONTENT);
+    LogSdchProblem(SDCH_UNFLUSHED_CONTENT);
     UMA_HISTOGRAM_COUNTS("Sdch3.UnflushedBytesIn",
          static_cast<int>(filter_context_.GetByteReadCount()));
     UMA_HISTOGRAM_COUNTS("Sdch3.UnflushedBufferSize",
@@ -111,7 +158,7 @@
   if (filter_context_.IsCachedContent()) {
     // Not a real error, but it is useful to have this tally.
     // TODO(jar): Remove this stat after SDCH stability is validated.
-    SdchManager::SdchErrorRecovery(SdchManager::CACHE_DECODED);
+    LogSdchProblem(SDCH_CACHE_DECODED);
     return;  // We don't need timing stats, and we aready got ratios.
   }
 
@@ -135,15 +182,15 @@
       return;
     }
     case DECODING_UNINITIALIZED: {
-      SdchManager::SdchErrorRecovery(SdchManager::UNINITIALIZED);
+      LogSdchProblem(SDCH_UNINITIALIZED);
       return;
     }
     case WAITING_FOR_DICTIONARY_SELECTION: {
-      SdchManager::SdchErrorRecovery(SdchManager::PRIOR_TO_DICTIONARY);
+      LogSdchProblem(SDCH_PRIOR_TO_DICTIONARY);
       return;
     }
     case DECODING_ERROR: {
-      SdchManager::SdchErrorRecovery(SdchManager::DECODE_ERROR);
+      LogSdchProblem(SDCH_DECODE_ERROR);
       return;
     }
     case META_REFRESH_RECOVERY: {
@@ -210,7 +257,7 @@
         // We could be more generous, but for now, only a "NOT FOUND" code will
         // cause a pass through.  All other bad codes will fall into a
         // meta-refresh.
-        SdchManager::SdchErrorRecovery(SdchManager::PASS_THROUGH_404_CODE);
+        LogSdchProblem(SDCH_PASS_THROUGH_404_CODE);
         cause = RESPONSE_404;
         decoding_status_ = PASS_THROUGH;
       } else if (filter_context_.GetResponseCode() != 200) {
@@ -220,7 +267,7 @@
                  && !dictionary_hash_is_plausible_) {
         // We must have hit the back button, and gotten content that was fetched
         // before we *really* advertised SDCH and a dictionary.
-        SdchManager::SdchErrorRecovery(SdchManager::PASS_THROUGH_OLD_CACHED);
+        LogSdchProblem(SDCH_PASS_THROUGH_OLD_CACHED);
         decoding_status_ = PASS_THROUGH;
         cause = RESPONSE_OLD_UNENCODED;
       } else if (possible_pass_through_) {
@@ -256,11 +303,11 @@
         // though it is not!
         // Meta-refresh won't help, as we didn't advertise an SDCH dictionary!!
         // Worse yet, meta-refresh could lead to an infinite refresh loop.
-        SdchManager::SdchErrorRecovery(SdchManager::PASSING_THROUGH_NON_SDCH);
+        LogSdchProblem(SDCH_PASSING_THROUGH_NON_SDCH);
         decoding_status_ = PASS_THROUGH;
         // ... but further back-off on advertising SDCH support.
         url_request_context_->sdch_manager()->BlacklistDomain(
-            url_, SdchManager::PASSING_THROUGH_NON_SDCH);
+            url_, SDCH_PASSING_THROUGH_NON_SDCH);
         cause = RESPONSE_ENCODING_LIE;
       }
       DCHECK_NE(RESPONSE_NONE, cause);
@@ -274,6 +321,10 @@
         UMA_HISTOGRAM_ENUMERATION(
             "Sdch3.ResponseCorruptionDetection.Uncached", cause, RESPONSE_MAX);
       }
+      filter_context_.GetNetLog().AddEvent(
+          NetLog::TYPE_SDCH_RESPONSE_CORRUPTION_DETECTION,
+          base::Bind(&NetLogSdchResponseCorruptionDetectionCallback, cause,
+                     filter_context_.IsCachedContent()));
 
       if (decoding_status_ == PASS_THROUGH) {
         dest_buffer_excess_ = dictionary_hash_;  // Send what we scanned.
@@ -282,13 +333,12 @@
         if (std::string::npos == mime_type_.find("text/html")) {
           // Since we can't do a meta-refresh (along with an exponential
           // backoff), we'll just make sure this NEVER happens again.
-          SdchManager::ProblemCodes problem =
-              (filter_context_.IsCachedContent() ?
-               SdchManager::CACHED_META_REFRESH_UNSUPPORTED :
-               SdchManager::META_REFRESH_UNSUPPORTED);
+          SdchProblemCode problem = (filter_context_.IsCachedContent()
+                                         ? SDCH_CACHED_META_REFRESH_UNSUPPORTED
+                                         : SDCH_META_REFRESH_UNSUPPORTED);
           url_request_context_->sdch_manager()->BlacklistDomainForever(
               url_, problem);
-          SdchManager::SdchErrorRecovery(problem);
+          LogSdchProblem(problem);
           return FILTER_ERROR;
         }
         // HTML content means we can issue a meta-refresh, and get the content
@@ -296,14 +346,13 @@
         if (filter_context_.IsCachedContent()) {
           // Cached content is probably a startup tab, so we'll just get fresh
           // content and try again, without disabling sdch.
-          SdchManager::SdchErrorRecovery(
-              SdchManager::META_REFRESH_CACHED_RECOVERY);
+          LogSdchProblem(SDCH_META_REFRESH_CACHED_RECOVERY);
         } else {
           // Since it wasn't in the cache, we definately need at least some
           // period of blacklisting to get the correct content.
           url_request_context_->sdch_manager()->BlacklistDomain(
-              url_, SdchManager::META_REFRESH_RECOVERY);
-          SdchManager::SdchErrorRecovery(SdchManager::META_REFRESH_RECOVERY);
+              url_, SDCH_META_REFRESH_RECOVERY);
+          LogSdchProblem(SDCH_META_REFRESH_RECOVERY);
         }
         decoding_status_ = META_REFRESH_RECOVERY;
         // Issue a meta redirect with SDCH disabled.
@@ -357,7 +406,7 @@
   if (!ret) {
     vcdiff_streaming_decoder_.reset(NULL);  // Don't call it again.
     decoding_status_ = DECODING_ERROR;
-    SdchManager::SdchErrorRecovery(SdchManager::DECODE_BODY_ERROR);
+    LogSdchProblem(SDCH_DECODE_BODY_ERROR);
     return FILTER_ERROR;
   }
 
@@ -394,32 +443,35 @@
   DCHECK(!dictionary_.get());
   dictionary_hash_is_plausible_ = true;  // Assume plausible, but check.
 
+  SdchProblemCode rv = SDCH_OK;
   if ('\0' == dictionary_hash_[kServerIdLength - 1]) {
     SdchManager* manager(url_request_context_->sdch_manager());
-    manager->GetVcdiffDictionary(
-        std::string(dictionary_hash_, 0, kServerIdLength - 1),
-        url_, &dictionary_);
-  } else {
-    dictionary_hash_is_plausible_ = false;
-  }
-
-  if (!dictionary_.get()) {
-    DCHECK(dictionary_hash_.size() == kServerIdLength);
-    // Since dictionary was not found, check to see if hash was even plausible.
-    for (size_t i = 0; i < kServerIdLength - 1; ++i) {
-      char base64_char = dictionary_hash_[i];
-      if (!isalnum(base64_char) && '-' != base64_char && '_' != base64_char) {
-        dictionary_hash_is_plausible_ = false;
-        break;
+    rv = manager->GetVcdiffDictionary(
+        std::string(dictionary_hash_, 0, kServerIdLength - 1), url_,
+        &dictionary_);
+    if (rv == SDCH_DICTIONARY_HASH_NOT_FOUND) {
+      DCHECK(dictionary_hash_.size() == kServerIdLength);
+      // Since dictionary was not found, check to see if hash was even
+      // plausible.
+      for (size_t i = 0; i < kServerIdLength - 1; ++i) {
+        char base64_char = dictionary_hash_[i];
+        if (!isalnum(base64_char) && '-' != base64_char && '_' != base64_char) {
+          rv = SDCH_DICTIONARY_HASH_MALFORMED;
+          dictionary_hash_is_plausible_ = false;
+          break;
+        }
       }
     }
-    if (dictionary_hash_is_plausible_)
-      SdchManager::SdchErrorRecovery(SdchManager::DICTIONARY_HASH_NOT_FOUND);
-    else
-      SdchManager::SdchErrorRecovery(SdchManager::DICTIONARY_HASH_MALFORMED);
+  } else {
+    dictionary_hash_is_plausible_ = false;
+    rv = SDCH_DICTIONARY_HASH_MALFORMED;
+  }
+  if (rv != SDCH_OK) {
+    LogSdchProblem(rv);
     decoding_status_ = DECODING_ERROR;
     return FILTER_ERROR;
   }
+  DCHECK(dictionary_.get());
   vcdiff_streaming_decoder_.reset(new open_vcdiff::VCDiffStreamingDecoder);
   vcdiff_streaming_decoder_->SetAllowVcdTarget(false);
   vcdiff_streaming_decoder_->StartDecoding(dictionary_->text().data(),
@@ -446,4 +498,11 @@
   return amount;
 }
 
+void SdchFilter::LogSdchProblem(SdchProblemCode problem) {
+  SdchManager::SdchErrorRecovery(problem);
+  filter_context_.GetNetLog().AddEvent(
+      NetLog::TYPE_SDCH_DECODING_ERROR,
+      base::Bind(&NetLogSdchResourceProblemCallback, problem));
+}
+
 }  // namespace net
diff --git a/net/filter/sdch_filter.h b/net/filter/sdch_filter.h
index e9648b1..a1a6607 100644
--- a/net/filter/sdch_filter.h
+++ b/net/filter/sdch_filter.h
@@ -64,6 +64,9 @@
   // specified dest_buffer.
   int OutputBufferExcess(char* const dest_buffer, size_t available_space);
 
+  // Add SDCH Problem to net-log and record histogram.
+  void LogSdchProblem(SdchProblemCode problem);
+
   // Context data from the owner of this filter.
   const FilterContext& filter_context_;
 
diff --git a/net/filter/sdch_filter_unittest.cc b/net/filter/sdch_filter_unittest.cc
index 2263001..79b5673 100644
--- a/net/filter/sdch_filter_unittest.cc
+++ b/net/filter/sdch_filter_unittest.cc
@@ -67,14 +67,7 @@
   // the attempt succeeded.
   bool AddSdchDictionary(const std::string& dictionary_text,
                          const GURL& gurl) {
-    std::string list;
-    sdch_manager_->GetAvailDictionaryList(gurl, &list);
-    sdch_manager_->AddSdchDictionary(dictionary_text, gurl);
-    std::string list2;
-    sdch_manager_->GetAvailDictionaryList(gurl, &list2);
-
-    // The list of hashes should change iff the addition succeeds.
-    return (list != list2);
+    return sdch_manager_->AddSdchDictionary(dictionary_text, gurl) == SDCH_OK;
   }
 
   MockFilterContext* filter_context() { return filter_context_.get(); }
@@ -412,9 +405,10 @@
   EXPECT_EQ(0, output_bytes_or_buffer_size);
   EXPECT_EQ(Filter::FILTER_ERROR, status);
 
-  EXPECT_FALSE(sdch_manager_->IsInSupportedDomain(GURL(url_string)));
+  EXPECT_EQ(SDCH_DOMAIN_BLACKLIST_INCLUDES_TARGET,
+            sdch_manager_->IsInSupportedDomain(GURL(url_string)));
   sdch_manager_->ClearBlacklistings();
-  EXPECT_TRUE(sdch_manager_->IsInSupportedDomain(GURL(url_string)));
+  EXPECT_EQ(SDCH_OK, sdch_manager_->IsInSupportedDomain(GURL(url_string)));
 }
 
 TEST_F(SdchFilterTest, DictionaryAddOnce) {
@@ -667,10 +661,11 @@
                               filter.get(), &output));
   EXPECT_EQ(output.size(), 0u);  // No output written.
 
-  EXPECT_TRUE(sdch_manager_->IsInSupportedDomain(GURL(url_string)));
-  EXPECT_FALSE(sdch_manager_->IsInSupportedDomain(wrong_domain_url));
+  EXPECT_EQ(SDCH_OK, sdch_manager_->IsInSupportedDomain(GURL(url_string)));
+  EXPECT_EQ(SDCH_DOMAIN_BLACKLIST_INCLUDES_TARGET,
+            sdch_manager_->IsInSupportedDomain(wrong_domain_url));
   sdch_manager_->ClearBlacklistings();
-  EXPECT_TRUE(sdch_manager_->IsInSupportedDomain(wrong_domain_url));
+  EXPECT_EQ(SDCH_OK, sdch_manager_->IsInSupportedDomain(wrong_domain_url));
 }
 
 TEST_F(SdchFilterTest, DictionaryPathValidation) {
@@ -723,9 +718,10 @@
                               output_block_size, filter.get(), &output));
   EXPECT_EQ(output.size(), 0u);  // No output written.
 
-  EXPECT_FALSE(sdch_manager_->IsInSupportedDomain(GURL(url_string)));
+  EXPECT_EQ(SDCH_DOMAIN_BLACKLIST_INCLUDES_TARGET,
+            sdch_manager_->IsInSupportedDomain(GURL(url_string)));
   sdch_manager_->ClearBlacklistings();
-  EXPECT_TRUE(sdch_manager_->IsInSupportedDomain(GURL(url_string)));
+  EXPECT_EQ(SDCH_OK, sdch_manager_->IsInSupportedDomain(GURL(url_string)));
 }
 
 TEST_F(SdchFilterTest, DictionaryPortValidation) {
@@ -789,9 +785,10 @@
                               output_block_size, filter.get(), &output));
   EXPECT_EQ(output.size(), 0u);  // No output written.
 
-  EXPECT_FALSE(sdch_manager_->IsInSupportedDomain(GURL(url_string)));
+  EXPECT_EQ(SDCH_DOMAIN_BLACKLIST_INCLUDES_TARGET,
+            sdch_manager_->IsInSupportedDomain(GURL(url_string)));
   sdch_manager_->ClearBlacklistings();
-  EXPECT_TRUE(sdch_manager_->IsInSupportedDomain(GURL(url_string)));
+  EXPECT_EQ(SDCH_OK, sdch_manager_->IsInSupportedDomain(GURL(url_string)));
 }
 
 //------------------------------------------------------------------------------
diff --git a/net/net.gyp b/net/net.gyp
index e9379e0..3c9a520 100644
--- a/net/net.gyp
+++ b/net/net.gyp
@@ -487,10 +487,14 @@
             ['include', '^base/platform_mime_util_linux\\.cc$'],
             ['include', '^base/address_tracker_linux\\.cc$'],
             ['include', '^base/address_tracker_linux\\.h$'],
+            ['include', '^base/net_util_linux\\.cc$'],
+            ['include', '^base/net_util_linux\\.h$'],
           ],
         }],
         ['OS == "ios"', {
           'sources/': [
+            ['include', '^base/net_util_mac\\.cc$'],
+            ['include', '^base/net_util_mac\\.h$'],
             ['include', '^base/network_change_notifier_mac\\.cc$'],
             ['include', '^base/network_config_watcher_mac\\.cc$'],
             ['include', '^base/platform_mime_util_mac\\.mm$'],
diff --git a/net/net.gypi b/net/net.gypi
index fef6136..337f016 100644
--- a/net/net.gypi
+++ b/net/net.gypi
@@ -246,7 +246,11 @@
       'base/net_log_logger.h',
       'base/net_log_util.cc',
       'base/net_log_util.h',
+      'base/net_util_linux.cc',
+      'base/net_util_mac.cc',
       'base/net_util_win.cc',
+      'base/network_activity_monitor.cc',
+      'base/network_activity_monitor.h',
       'base/network_change_notifier.cc',
       'base/network_change_notifier.h',
       'base/network_change_notifier_factory.h',
@@ -275,8 +279,12 @@
       'base/request_priority.h',
       'base/sdch_manager.cc',
       'base/sdch_manager.h',
+      'base/sdch_net_log_params.cc',
+      'base/sdch_net_log_params.h',
       'base/sdch_observer.cc',
       'base/sdch_observer.h',
+      'base/sdch_problem_code_list.h',
+      'base/sdch_problem_codes.h',
       'base/static_cookie_policy.cc',
       'base/static_cookie_policy.h',
       'base/test_data_stream.cc',
@@ -751,8 +759,6 @@
       'quic/congestion_control/cubic.h',
       'quic/congestion_control/hybrid_slow_start.cc',
       'quic/congestion_control/hybrid_slow_start.h',
-      'quic/congestion_control/leaky_bucket.cc',
-      'quic/congestion_control/leaky_bucket.h',
       'quic/congestion_control/loss_detection_interface.cc',
       'quic/congestion_control/loss_detection_interface.h',
       'quic/congestion_control/pacing_sender.cc',
@@ -785,6 +791,8 @@
       'quic/crypto/aes_128_gcm_12_encrypter.h',
       'quic/crypto/aes_128_gcm_12_encrypter_nss.cc',
       'quic/crypto/aes_128_gcm_12_encrypter_openssl.cc',
+      'quic/crypto/cached_network_parameters.cc',
+      'quic/crypto/cached_network_parameters.h',
       'quic/crypto/cert_compressor.cc',
       'quic/crypto/cert_compressor.h',
       'quic/crypto/chacha20_poly1305_decrypter.h',
@@ -1276,6 +1284,7 @@
       'base/net_log_util_unittest.cc',
       'base/net_util_unittest.cc',
       'base/net_util_icu_unittest.cc',
+      'base/network_activity_monitor_unittest.cc',
       'base/network_change_notifier_unittest.cc',
       'base/network_change_notifier_win_unittest.cc',
       'base/prioritized_dispatcher_unittest.cc',
@@ -1440,7 +1449,6 @@
       'quic/congestion_control/cube_root_test.cc',
       'quic/congestion_control/cubic_test.cc',
       'quic/congestion_control/hybrid_slow_start_test.cc',
-      'quic/congestion_control/leaky_bucket_test.cc',
       'quic/congestion_control/pacing_sender_test.cc',
       'quic/congestion_control/prr_sender_test.cc',
       'quic/congestion_control/rtt_stats_test.cc',
diff --git a/net/quic/congestion_control/hybrid_slow_start.cc b/net/quic/congestion_control/hybrid_slow_start.cc
index 4b1e842..e3789b4 100644
--- a/net/quic/congestion_control/hybrid_slow_start.cc
+++ b/net/quic/congestion_control/hybrid_slow_start.cc
@@ -23,6 +23,7 @@
 
 HybridSlowStart::HybridSlowStart(const QuicClock* clock)
     : clock_(clock),
+      ack_train_detection_(true),
       started_(false),
       hystart_found_(NOT_FOUND),
       last_sent_sequence_number_(0),
@@ -84,12 +85,8 @@
   // more than the capacity.
   // This first trigger will not come into play until we hit roughly 9.6 Mbps
   // with delayed acks (or 4.8Mbps without delayed acks)
-  // TODO(ianswett): QUIC always uses delayed acks, even at the beginning, so
-  // this should likely be at least 4ms.
-  // TODO(pwestin): we need to make sure our pacing don't trigger this detector.
-  // TODO(ianswett): Pacing or other cases could be handled by checking the send
-  // time of the first acked packet in a receive round.
-  if (current_time.Subtract(last_close_ack_pair_time_).ToMicroseconds() <=
+  if (ack_train_detection_ &&
+      current_time.Subtract(last_close_ack_pair_time_).ToMicroseconds() <=
           kHybridStartDelayMinThresholdUs) {
     last_close_ack_pair_time_ = current_time;
     if (current_time.Subtract(round_start_).ToMicroseconds() >=
diff --git a/net/quic/congestion_control/hybrid_slow_start.h b/net/quic/congestion_control/hybrid_slow_start.h
index 5d36c53..cee9a60 100644
--- a/net/quic/congestion_control/hybrid_slow_start.h
+++ b/net/quic/congestion_control/hybrid_slow_start.h
@@ -53,6 +53,14 @@
   // Call for the start of each receive round (burst) in the slow start phase.
   void StartReceiveRound(QuicPacketSequenceNumber last_sent);
 
+  void set_ack_train_detection(bool ack_train_detection) {
+    ack_train_detection_ = ack_train_detection;
+  }
+
+  bool ack_train_detection() const {
+    return ack_train_detection_;
+  }
+
   // Whether slow start has started.
   bool started() const {
     return started_;
@@ -67,6 +75,7 @@
   };
 
   const QuicClock* clock_;
+  bool ack_train_detection_;
   // Whether the hybrid slow start has been started.
   bool started_;
   HystartState hystart_found_;
diff --git a/net/quic/congestion_control/hybrid_slow_start_test.cc b/net/quic/congestion_control/hybrid_slow_start_test.cc
index dd74933..bcdf8d9 100644
--- a/net/quic/congestion_control/hybrid_slow_start_test.cc
+++ b/net/quic/congestion_control/hybrid_slow_start_test.cc
@@ -54,26 +54,33 @@
   // At a typical RTT 60 ms, assuming that the inter arrival timestamp is 1 ms,
   // we expect to be able to send a burst of 30 packet before we trigger the
   // ack train detection.
-  const int kMaxLoopCount = 5;
-  QuicPacketSequenceNumber sequence_number = 2;
-  QuicPacketSequenceNumber end_sequence_number = 2;
-  for (int burst = 0; burst < kMaxLoopCount; ++burst) {
+  // Run this test for both enabled and disabled ack train detection.
+  for (int i = 0; i < 2; ++i) {
+    const bool ack_train_detection = (i == 1);
+    slow_start_->set_ack_train_detection(ack_train_detection);
+
+    const int kMaxLoopCount = 5;
+    QuicPacketSequenceNumber sequence_number = 2;
+    QuicPacketSequenceNumber end_sequence_number = 2;
+    for (int burst = 0; burst < kMaxLoopCount; ++burst) {
+      slow_start_->StartReceiveRound(end_sequence_number);
+      do {
+        clock_.AdvanceTime(one_ms_);
+        EXPECT_FALSE(slow_start_->ShouldExitSlowStart(rtt_, rtt_, 100));
+      } while (!slow_start_->IsEndOfRound(sequence_number++));
+      end_sequence_number *= 2;  // Exponential growth.
+    }
     slow_start_->StartReceiveRound(end_sequence_number);
-    do {
+
+    for (int n = 0;
+         n < 29 && !slow_start_->IsEndOfRound(sequence_number++); ++n) {
       clock_.AdvanceTime(one_ms_);
       EXPECT_FALSE(slow_start_->ShouldExitSlowStart(rtt_, rtt_, 100));
-    }  while (!slow_start_->IsEndOfRound(sequence_number++));
-    end_sequence_number *= 2;  // Exponential growth.
-  }
-  slow_start_->StartReceiveRound(end_sequence_number);
-
-  for (int n = 0;
-       n < 29 && !slow_start_->IsEndOfRound(sequence_number++); ++n) {
+    }
     clock_.AdvanceTime(one_ms_);
-    EXPECT_FALSE(slow_start_->ShouldExitSlowStart(rtt_, rtt_, 100));
+    EXPECT_EQ(ack_train_detection,
+              slow_start_->ShouldExitSlowStart(rtt_, rtt_, 100));
   }
-  clock_.AdvanceTime(one_ms_);
-  EXPECT_TRUE(slow_start_->ShouldExitSlowStart(rtt_, rtt_, 100));
 }
 
 TEST_F(HybridSlowStartTest, Delay) {
diff --git a/net/quic/congestion_control/leaky_bucket.cc b/net/quic/congestion_control/leaky_bucket.cc
deleted file mode 100644
index f3972f6..0000000
--- a/net/quic/congestion_control/leaky_bucket.cc
+++ /dev/null
@@ -1,54 +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 "net/quic/congestion_control/leaky_bucket.h"
-
-#include "base/time/time.h"
-
-namespace net {
-
-LeakyBucket::LeakyBucket(QuicBandwidth draining_rate)
-    : bytes_(0),
-      time_last_updated_(QuicTime::Zero()),
-      draining_rate_(draining_rate) {
-}
-
-void LeakyBucket::SetDrainingRate(QuicTime now, QuicBandwidth draining_rate) {
-  Update(now);
-  draining_rate_ = draining_rate;
-}
-
-void LeakyBucket::Add(QuicTime now, QuicByteCount bytes) {
-  Update(now);
-  bytes_ += bytes;
-}
-
-QuicTime::Delta LeakyBucket::TimeRemaining(QuicTime now) const {
-  QuicTime::Delta time_since_last_update = now.Subtract(time_last_updated_);
-  QuicTime::Delta send_delay = QuicTime::Delta::FromMicroseconds(
-      (bytes_ * base::Time::kMicrosecondsPerSecond) /
-      draining_rate_.ToBytesPerSecond());
-  if (send_delay < time_since_last_update) {
-    return QuicTime::Delta::Zero();
-  }
-  return send_delay.Subtract(time_since_last_update);
-}
-
-QuicByteCount LeakyBucket::BytesPending(QuicTime now) {
-  Update(now);
-  return bytes_;
-}
-
-void LeakyBucket::Update(QuicTime now) {
-  QuicTime::Delta elapsed_time = now.Subtract(time_last_updated_);
-  QuicByteCount bytes_cleared = draining_rate_.ToBytesPerPeriod(elapsed_time);
-  if (bytes_cleared >= bytes_) {
-    bytes_ = 0;
-  } else {
-    bytes_ -= bytes_cleared;
-  }
-  time_last_updated_ = now;
-}
-
-}  // namespace net
diff --git a/net/quic/congestion_control/leaky_bucket.h b/net/quic/congestion_control/leaky_bucket.h
deleted file mode 100644
index eb4cdb0..0000000
--- a/net/quic/congestion_control/leaky_bucket.h
+++ /dev/null
@@ -1,49 +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.
-//
-// Helper class to track the rate data can leave the buffer for pacing.
-// A leaky bucket drains the data at a constant rate regardless of fullness of
-// the buffer.
-// See http://en.wikipedia.org/wiki/Leaky_bucket for more details.
-
-#ifndef NET_QUIC_CONGESTION_CONTROL_LEAKY_BUCKET_H_
-#define NET_QUIC_CONGESTION_CONTROL_LEAKY_BUCKET_H_
-
-#include "base/basictypes.h"
-#include "net/base/net_export.h"
-#include "net/quic/quic_bandwidth.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_time.h"
-
-namespace net {
-
-class NET_EXPORT_PRIVATE LeakyBucket {
- public:
-  explicit LeakyBucket(QuicBandwidth draining_rate);
-
-  // Set the rate at which the bytes leave the buffer.
-  void SetDrainingRate(QuicTime now, QuicBandwidth draining_rate);
-
-  // Add data to the buffer.
-  void Add(QuicTime now, QuicByteCount bytes);
-
-  // Time until the buffer is empty.
-  QuicTime::Delta TimeRemaining(QuicTime now) const;
-
-  // Number of bytes in the buffer.
-  QuicByteCount BytesPending(QuicTime now);
-
- private:
-  void Update(QuicTime now);
-
-  QuicByteCount bytes_;
-  QuicTime time_last_updated_;
-  QuicBandwidth draining_rate_;
-
-  DISALLOW_COPY_AND_ASSIGN(LeakyBucket);
-};
-
-}  // namespace net
-
-#endif  // NET_QUIC_CONGESTION_CONTROL_LEAKY_BUCKET_H_
diff --git a/net/quic/congestion_control/leaky_bucket_test.cc b/net/quic/congestion_control/leaky_bucket_test.cc
deleted file mode 100644
index 8387ada..0000000
--- a/net/quic/congestion_control/leaky_bucket_test.cc
+++ /dev/null
@@ -1,75 +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 "base/logging.h"
-#include "base/memory/scoped_ptr.h"
-#include "net/quic/congestion_control/leaky_bucket.h"
-#include "net/quic/test_tools/mock_clock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace net {
-namespace test {
-
-class LeakyBucketTest : public ::testing::Test {
- protected:
-  void SetUp() override {
-    leaky_bucket_.reset(new LeakyBucket(QuicBandwidth::Zero()));
-  }
-  MockClock clock_;
-  scoped_ptr<LeakyBucket> leaky_bucket_;
-};
-
-TEST_F(LeakyBucketTest, Basic) {
-  QuicBandwidth draining_rate = QuicBandwidth::FromBytesPerSecond(200000);
-  leaky_bucket_->SetDrainingRate(clock_.Now(), draining_rate);
-  leaky_bucket_->Add(clock_.Now(), 2000);
-  EXPECT_EQ(2000u, leaky_bucket_->BytesPending(clock_.Now()));
-  EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10),
-            leaky_bucket_->TimeRemaining(clock_.Now()));
-  clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
-  EXPECT_EQ(1000u, leaky_bucket_->BytesPending(clock_.Now()));
-  EXPECT_EQ(QuicTime::Delta::FromMilliseconds(5),
-            leaky_bucket_->TimeRemaining(clock_.Now()));
-  clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
-  EXPECT_EQ(0u, leaky_bucket_->BytesPending(clock_.Now()));
-  EXPECT_TRUE(leaky_bucket_->TimeRemaining(clock_.Now()).IsZero());
-  clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
-  EXPECT_EQ(0u, leaky_bucket_->BytesPending(clock_.Now()));
-  EXPECT_TRUE(leaky_bucket_->TimeRemaining(clock_.Now()).IsZero());
-  leaky_bucket_->Add(clock_.Now(), 2000);
-  clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(11));
-  EXPECT_EQ(0u, leaky_bucket_->BytesPending(clock_.Now()));
-  EXPECT_TRUE(leaky_bucket_->TimeRemaining(clock_.Now()).IsZero());
-  leaky_bucket_->Add(clock_.Now(), 2000);
-  clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
-  leaky_bucket_->Add(clock_.Now(), 2000);
-  clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
-  EXPECT_EQ(2000u, leaky_bucket_->BytesPending(clock_.Now()));
-  EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10),
-            leaky_bucket_->TimeRemaining(clock_.Now()));
-  clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(10));
-  EXPECT_EQ(0u, leaky_bucket_->BytesPending(clock_.Now()));
-  EXPECT_TRUE(leaky_bucket_->TimeRemaining(clock_.Now()).IsZero());
-}
-
-TEST_F(LeakyBucketTest, ChangeDrainRate) {
-  QuicBandwidth draining_rate = QuicBandwidth::FromBytesPerSecond(200000);
-  leaky_bucket_->SetDrainingRate(clock_.Now(), draining_rate);
-  leaky_bucket_->Add(clock_.Now(), 2000);
-  EXPECT_EQ(2000u, leaky_bucket_->BytesPending(clock_.Now()));
-  EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10),
-            leaky_bucket_->TimeRemaining(clock_.Now()));
-  clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
-  EXPECT_EQ(1000u, leaky_bucket_->BytesPending(clock_.Now()));
-  EXPECT_EQ(QuicTime::Delta::FromMilliseconds(5),
-            leaky_bucket_->TimeRemaining(clock_.Now()));
-  draining_rate = draining_rate.Scale(0.5f);  // Cut drain rate in half.
-  leaky_bucket_->SetDrainingRate(clock_.Now(), draining_rate);
-  EXPECT_EQ(1000u, leaky_bucket_->BytesPending(clock_.Now()));
-  EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10),
-            leaky_bucket_->TimeRemaining(clock_.Now()));
-}
-
-}  // namespace test
-}  // namespace net
diff --git a/net/quic/congestion_control/pacing_sender.cc b/net/quic/congestion_control/pacing_sender.cc
index 061f6ec..8073c5b 100644
--- a/net/quic/congestion_control/pacing_sender.cc
+++ b/net/quic/congestion_control/pacing_sender.cc
@@ -20,8 +20,11 @@
 
 PacingSender::~PacingSender() {}
 
-void PacingSender::SetFromConfig(const QuicConfig& config, bool is_server) {
-  sender_->SetFromConfig(config, is_server);
+void PacingSender::SetFromConfig(const QuicConfig& config,
+                                 bool is_server,
+                                 bool using_pacing) {
+  DCHECK(using_pacing);
+  sender_->SetFromConfig(config, is_server, using_pacing);
 }
 
 void PacingSender::SetNumEmulatedConnections(int num_connections) {
diff --git a/net/quic/congestion_control/pacing_sender.h b/net/quic/congestion_control/pacing_sender.h
index f16172a..4eb3dab 100644
--- a/net/quic/congestion_control/pacing_sender.h
+++ b/net/quic/congestion_control/pacing_sender.h
@@ -35,7 +35,9 @@
   ~PacingSender() override;
 
   // SendAlgorithmInterface methods.
-  void SetFromConfig(const QuicConfig& config, bool is_server) override;
+  void SetFromConfig(const QuicConfig& config,
+                     bool is_server,
+                     bool using_pacing) override;
   void SetNumEmulatedConnections(int num_connections) override;
   void OnCongestionEvent(bool rtt_updated,
                          QuicByteCount bytes_in_flight,
diff --git a/net/quic/congestion_control/rtt_stats.cc b/net/quic/congestion_control/rtt_stats.cc
index dfb50ef..32e3b58 100644
--- a/net/quic/congestion_control/rtt_stats.cc
+++ b/net/quic/congestion_control/rtt_stats.cc
@@ -28,7 +28,7 @@
       min_rtt_(QuicTime::Delta::Zero()),
       smoothed_rtt_(QuicTime::Delta::Zero()),
       mean_deviation_(QuicTime::Delta::Zero()),
-      initial_rtt_us_(kInitialRttMs * base::Time::kMicrosecondsPerMillisecond),
+      initial_rtt_us_(kInitialRttMs * kNumMicrosPerMilli),
       num_min_rtt_samples_remaining_(0),
       recent_min_rtt_window_(QuicTime::Delta::Infinite()) {}
 
diff --git a/net/quic/congestion_control/send_algorithm_interface.cc b/net/quic/congestion_control/send_algorithm_interface.cc
index 7245e33..82f1135 100644
--- a/net/quic/congestion_control/send_algorithm_interface.cc
+++ b/net/quic/congestion_control/send_algorithm_interface.cc
@@ -16,17 +16,23 @@
     const QuicClock* clock,
     const RttStats* rtt_stats,
     CongestionControlType congestion_control_type,
-    QuicConnectionStats* stats) {
+    QuicConnectionStats* stats,
+    QuicPacketCount initial_congestion_window) {
   switch (congestion_control_type) {
     case kCubic:
-      return new TcpCubicSender(clock, rtt_stats,
-                                false /* don't use Reno */,
+      return new TcpCubicSender(clock, rtt_stats, false /* don't use Reno */,
+                                initial_congestion_window,
                                 kMaxTcpCongestionWindow, stats);
     case kReno:
-      return new TcpCubicSender(clock, rtt_stats,
-                                true /* use Reno */,
+      return new TcpCubicSender(clock, rtt_stats, true /* use Reno */,
+                                initial_congestion_window,
                                 kMaxTcpCongestionWindow, stats);
     case kBBR:
+  // TODO(rtenneti): Enable BbrTcpSender.
+#if 0
+      return new BbrTcpSender(clock, rtt_stats, initial_congestion_window,
+                              kMaxTcpCongestionWindow, stats);
+#endif
       LOG(DFATAL) << "BbrTcpSender is not supported.";
       return nullptr;
   }
diff --git a/net/quic/congestion_control/send_algorithm_interface.h b/net/quic/congestion_control/send_algorithm_interface.h
index 4f74628..7195f81 100644
--- a/net/quic/congestion_control/send_algorithm_interface.h
+++ b/net/quic/congestion_control/send_algorithm_interface.h
@@ -29,14 +29,17 @@
   typedef std::vector<std::pair<QuicPacketSequenceNumber, TransmissionInfo>>
       CongestionVector;
 
-  static SendAlgorithmInterface* Create(const QuicClock* clock,
-                                        const RttStats* rtt_stats,
-                                        CongestionControlType type,
-                                        QuicConnectionStats* stats);
+  static SendAlgorithmInterface* Create(
+      const QuicClock* clock,
+      const RttStats* rtt_stats,
+      CongestionControlType type,
+      QuicConnectionStats* stats,
+      QuicPacketCount initial_congestion_window);
 
   virtual ~SendAlgorithmInterface() {}
 
-  virtual void SetFromConfig(const QuicConfig& config, bool is_server) = 0;
+  virtual void SetFromConfig(
+      const QuicConfig& config, bool is_server, bool using_pacing) = 0;
 
   // Sets the number of connections to emulate when doing congestion control,
   // particularly for congestion avoidance.  Can be set any time.
diff --git a/net/quic/congestion_control/tcp_cubic_sender.cc b/net/quic/congestion_control/tcp_cubic_sender.cc
index 5f20597..2d0efd7 100644
--- a/net/quic/congestion_control/tcp_cubic_sender.cc
+++ b/net/quic/congestion_control/tcp_cubic_sender.cc
@@ -31,6 +31,7 @@
     const QuicClock* clock,
     const RttStats* rtt_stats,
     bool reno,
+    QuicPacketCount initial_tcp_congestion_window,
     QuicPacketCount max_tcp_congestion_window,
     QuicConnectionStats* stats)
     : hybrid_slow_start_(clock),
@@ -43,7 +44,7 @@
       largest_sent_sequence_number_(0),
       largest_acked_sequence_number_(0),
       largest_sent_at_last_cutback_(0),
-      congestion_window_(kDefaultInitialWindow),
+      congestion_window_(initial_tcp_congestion_window),
       previous_congestion_window_(0),
       slowstart_threshold_(max_tcp_congestion_window),
       previous_slowstart_threshold_(0),
@@ -55,20 +56,19 @@
   UMA_HISTOGRAM_COUNTS("Net.QuicSession.FinalTcpCwnd", congestion_window_);
 }
 
-void TcpCubicSender::SetFromConfig(const QuicConfig& config, bool is_server) {
+void TcpCubicSender::SetFromConfig(const QuicConfig& config,
+                                   bool is_server,
+                                   bool using_pacing) {
   if (is_server) {
     if (config.HasReceivedConnectionOptions() &&
         ContainsQuicTag(config.ReceivedConnectionOptions(), kIW10)) {
-      // Initial window experiment.  Ignore the initial congestion
-      // window suggested by the client and use the default ICWND of
-      // 10 instead.
-      congestion_window_ = kDefaultInitialWindow;
-    } else if (config.HasReceivedInitialCongestionWindow()) {
-      // Set the initial window size.
-      congestion_window_ = max(kMinimumCongestionWindow,
-          min(kMaxInitialWindow,
-              static_cast<QuicPacketCount>(
-                  config.ReceivedInitialCongestionWindow())));
+      // Initial window experiment.
+      congestion_window_ = 10;
+    }
+    if (using_pacing) {
+      // Disable the ack train mode in hystart when pacing is enabled, since it
+      // may be falsely triggered.
+      hybrid_slow_start_.set_ack_train_detection(false);
     }
   }
 }
diff --git a/net/quic/congestion_control/tcp_cubic_sender.h b/net/quic/congestion_control/tcp_cubic_sender.h
index 7491565..a7507a2 100644
--- a/net/quic/congestion_control/tcp_cubic_sender.h
+++ b/net/quic/congestion_control/tcp_cubic_sender.h
@@ -34,12 +34,15 @@
   TcpCubicSender(const QuicClock* clock,
                  const RttStats* rtt_stats,
                  bool reno,
+                 QuicPacketCount initial_tcp_congestion_window,
                  QuicPacketCount max_tcp_congestion_window,
                  QuicConnectionStats* stats);
   ~TcpCubicSender() override;
 
   // Start implementation of SendAlgorithmInterface.
-  void SetFromConfig(const QuicConfig& config, bool is_server) override;
+  void SetFromConfig(const QuicConfig& config,
+                     bool is_server,
+                     bool using_pacing) override;
   void SetNumEmulatedConnections(int num_connections) override;
   void OnCongestionEvent(bool rtt_updated,
                          QuicByteCount bytes_in_flight,
diff --git a/net/quic/congestion_control/tcp_cubic_sender_test.cc b/net/quic/congestion_control/tcp_cubic_sender_test.cc
index 48a1300..427dd8c 100644
--- a/net/quic/congestion_control/tcp_cubic_sender_test.cc
+++ b/net/quic/congestion_control/tcp_cubic_sender_test.cc
@@ -21,19 +21,22 @@
 namespace net {
 namespace test {
 
-const uint32 kDefaultWindowTCP = kDefaultInitialWindow * kDefaultTCPMSS;
+// TODO(ianswett): A number of theses tests were written with the assumption of
+// an initial CWND of 10. They have carefully calculated values which should be
+// updated to be based on kInitialCongestionWindowInsecure.
+const uint32 kInitialCongestionWindowPackets = 10;
+const uint32 kDefaultWindowTCP =
+    kInitialCongestionWindowPackets * kDefaultTCPMSS;
 const float kRenoBeta = 0.7f;  // Reno backoff factor.
 
-// TODO(ianswett): Remove 10000 once b/10075719 is fixed.
-const QuicPacketCount kDefaultMaxCongestionWindowTCP = 10000;
-
 class TcpCubicSenderPeer : public TcpCubicSender {
  public:
   TcpCubicSenderPeer(const QuicClock* clock,
                      bool reno,
                      QuicPacketCount max_tcp_congestion_window)
       : TcpCubicSender(
-            clock, &rtt_stats_, reno, max_tcp_congestion_window, &stats_) {
+            clock, &rtt_stats_, reno, kInitialCongestionWindowPackets,
+            max_tcp_congestion_window, &stats_) {
   }
 
   QuicPacketCount congestion_window() {
@@ -61,7 +64,7 @@
   TcpCubicSenderTest()
       : one_ms_(QuicTime::Delta::FromMilliseconds(1)),
         sender_(new TcpCubicSenderPeer(&clock_, true,
-                                       kDefaultMaxCongestionWindowTCP)),
+                                       kMaxTcpCongestionWindow)),
         receiver_(new TcpReceiver()),
         sequence_number_(1),
         acked_sequence_number_(0),
@@ -209,7 +212,7 @@
 
 TEST_F(TcpCubicSenderTest, SlowStartAckTrain) {
   sender_->SetNumEmulatedConnections(1);
-  EXPECT_EQ(kDefaultMaxCongestionWindowTCP * kDefaultTCPMSS,
+  EXPECT_EQ(kMaxTcpCongestionWindow * kDefaultTCPMSS,
             sender_->GetSlowStartThreshold());
 
   // Make sure that we fall out of slow start when we send ACK train longer
@@ -305,7 +308,7 @@
 
 TEST_F(TcpCubicSenderTest, NoPRRWhenLessThanOnePacketInFlight) {
   SendAvailableSendWindow();
-  LoseNPackets(kDefaultInitialWindow - 1);
+  LoseNPackets(kInitialCongestionWindowPackets - 1);
   AckNPackets(1);
   // PRR will allow 2 packets for every ack during recovery.
   EXPECT_EQ(2, SendAvailableSendWindow());
@@ -424,7 +427,7 @@
 
 TEST_F(TcpCubicSenderTest, RTOCongestionWindowAndRevert) {
   EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow());
-  EXPECT_EQ(10000u, sender_->slowstart_threshold());
+  EXPECT_EQ(kMaxTcpCongestionWindow, sender_->slowstart_threshold());
 
   // Expect the window to decrease to the minimum once the RTO fires
   // and slow start threshold to be set to 1/2 of the CWND.
@@ -435,7 +438,7 @@
   // Now repair the RTO and ensure the slowstart threshold reverts.
   sender_->RevertRetransmissionTimeout();
   EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow());
-  EXPECT_EQ(10000u, sender_->slowstart_threshold());
+  EXPECT_EQ(kMaxTcpCongestionWindow, sender_->slowstart_threshold());
 }
 
 TEST_F(TcpCubicSenderTest, RTOCongestionWindowNoRetransmission) {
@@ -574,20 +577,26 @@
 }
 
 TEST_F(TcpCubicSenderTest, ConfigureMaxInitialWindow) {
-  QuicPacketCount congestion_window = sender_->congestion_window();
   QuicConfig config;
-  QuicConfigPeer::SetReceivedInitialWindow(&config, 2 * congestion_window);
 
-  sender_->SetFromConfig(config, true);
-  EXPECT_EQ(2 * congestion_window, sender_->congestion_window());
-
-  // Verify that kCOPT: kIW10 forces the congestion window to the
-  // default of 10 regardless of ReceivedInitialWindow.
+  // Verify that kCOPT: kIW10 forces the congestion window to the default of 10.
   QuicTagVector options;
   options.push_back(kIW10);
   QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
-  sender_->SetFromConfig(config, true);
-  EXPECT_EQ(congestion_window, sender_->congestion_window());
+  sender_->SetFromConfig(config,
+                         /* is_server= */ true,
+                         /* using_pacing= */ false);
+  EXPECT_EQ(10u, sender_->congestion_window());
+}
+
+TEST_F(TcpCubicSenderTest, DisableAckTrainDetectionWithPacing) {
+  EXPECT_TRUE(sender_->hybrid_slow_start().ack_train_detection());
+
+  QuicConfig config;
+  sender_->SetFromConfig(config,
+                         /* is_server= */ true,
+                         /* using_pacing= */ true);
+  EXPECT_FALSE(sender_->hybrid_slow_start().ack_train_detection());
 }
 
 TEST_F(TcpCubicSenderTest, 2ConnectionCongestionAvoidanceAtEndOfRecovery) {
diff --git a/net/quic/crypto/cached_network_parameters.cc b/net/quic/crypto/cached_network_parameters.cc
new file mode 100644
index 0000000..20a438b
--- /dev/null
+++ b/net/quic/crypto/cached_network_parameters.cc
@@ -0,0 +1,40 @@
+// Copyright (c) 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 "net/quic/crypto/cached_network_parameters.h"
+
+namespace net {
+
+CachedNetworkParameters::CachedNetworkParameters()
+    : bandwidth_estimate_bytes_per_second_(0),
+      max_bandwidth_estimate_bytes_per_second_(0),
+      max_bandwidth_timestamp_seconds_(0),
+      min_rtt_ms_(0),
+      previous_connection_state_(0),
+      timestamp_(0) {
+}
+
+CachedNetworkParameters::~CachedNetworkParameters() {
+}
+
+bool CachedNetworkParameters::operator==(
+    const CachedNetworkParameters& other) const {
+  return serving_region_ == other.serving_region_ &&
+      bandwidth_estimate_bytes_per_second_ ==
+          other.bandwidth_estimate_bytes_per_second_ &&
+      max_bandwidth_estimate_bytes_per_second_ ==
+          other.max_bandwidth_estimate_bytes_per_second_ &&
+      max_bandwidth_timestamp_seconds_ ==
+          other.max_bandwidth_timestamp_seconds_ &&
+      min_rtt_ms_ == other.min_rtt_ms_ &&
+      previous_connection_state_ == other.previous_connection_state_ &&
+      timestamp_ == other.timestamp_;
+}
+
+bool CachedNetworkParameters::operator!=(
+    const CachedNetworkParameters& other) const {
+  return !(*this == other);
+}
+
+}  // namespace net
diff --git a/net/quic/crypto/cached_network_parameters.h b/net/quic/crypto/cached_network_parameters.h
new file mode 100644
index 0000000..5f22070
--- /dev/null
+++ b/net/quic/crypto/cached_network_parameters.h
@@ -0,0 +1,109 @@
+// Copyright (c) 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 NET_QUIC_CRYPTO_CACHED_NETWORK_PARAMETERS_H_
+#define NET_QUIC_CRYPTO_CACHED_NETWORK_PARAMETERS_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/strings/string_piece.h"
+#include "net/base/net_export.h"
+
+namespace net {
+
+// TODO(rtenneti): sync with server more rationally.
+// CachedNetworkParameters contains data that can be used to choose appropriate
+// connection parameters (initial RTT, initial CWND, etc.) in new connections.
+class NET_EXPORT_PRIVATE CachedNetworkParameters {
+ public:
+  // Describes the state of the connection during which the supplied network
+  // parameters were calculated.
+  enum PreviousConnectionState {
+    SLOW_START = 0,
+    CONGESTION_AVOIDANCE = 1,
+  };
+
+  CachedNetworkParameters();
+  ~CachedNetworkParameters();
+
+  bool operator==(const CachedNetworkParameters& other) const;
+  bool operator!=(const CachedNetworkParameters& other) const;
+
+  std::string serving_region() const {
+    return serving_region_;
+  }
+  void set_serving_region(base::StringPiece serving_region) {
+    serving_region_ = serving_region.as_string();
+  }
+
+  int32 bandwidth_estimate_bytes_per_second() const {
+    return bandwidth_estimate_bytes_per_second_;
+  }
+  void set_bandwidth_estimate_bytes_per_second(
+      int32 bandwidth_estimate_bytes_per_second) {
+    bandwidth_estimate_bytes_per_second_ = bandwidth_estimate_bytes_per_second;
+  }
+
+  int32 max_bandwidth_estimate_bytes_per_second() const {
+    return max_bandwidth_estimate_bytes_per_second_;
+  }
+  void set_max_bandwidth_estimate_bytes_per_second(
+      int32 max_bandwidth_estimate_bytes_per_second) {
+    max_bandwidth_estimate_bytes_per_second_ =
+        max_bandwidth_estimate_bytes_per_second;
+  }
+
+  int64 max_bandwidth_timestamp_seconds() const {
+    return max_bandwidth_timestamp_seconds_;
+  }
+  void set_max_bandwidth_timestamp_seconds(
+      int64 max_bandwidth_timestamp_seconds) {
+    max_bandwidth_timestamp_seconds_ = max_bandwidth_timestamp_seconds;
+  }
+
+  int32 min_rtt_ms() const {
+    return min_rtt_ms_;
+  }
+  void set_min_rtt_ms(int32 min_rtt_ms) {
+    min_rtt_ms_ = min_rtt_ms;
+  }
+
+  int32 previous_connection_state() const {
+    return previous_connection_state_;
+  }
+  void set_previous_connection_state(int32 previous_connection_state) {
+    previous_connection_state_ = previous_connection_state;
+  }
+
+  int64 timestamp() const { return timestamp_; }
+  void set_timestamp(int64 timestamp) { timestamp_ = timestamp; }
+
+ private:
+  // serving_region_ is used to decide whether or not the bandwidth estimate and
+  // min RTT are reasonable and if they should be used.
+  // For example a group of geographically close servers may share the same
+  // serving_region_ string if they are expected to have similar network
+  // performance.
+  std::string serving_region_;
+  // The server can supply a bandwidth estimate (in bytes/s) which it may re-use
+  // on receipt of a source-address token with this field set.
+  int32 bandwidth_estimate_bytes_per_second_;
+  // The maximum bandwidth seen by the client, not necessarily the latest.
+  int32 max_bandwidth_estimate_bytes_per_second_;
+  // Timestamp (seconds since UNIX epoch) that indicates when the max bandwidth
+  // was seen by the server.
+  int64 max_bandwidth_timestamp_seconds_;
+  // The min RTT seen on a previous connection can be used by the server to
+  // inform initial connection parameters for new connections.
+  int32 min_rtt_ms_;
+  // Encodes the PreviousConnectionState enum.
+  int32 previous_connection_state_;
+  // UNIX timestamp when this bandwidth estimate was created.
+  int64 timestamp_;
+};
+
+}  // namespace net
+
+#endif  // NET_QUIC_CRYPTO_CACHED_NETWORK_PARAMETERS_H_
diff --git a/net/quic/crypto/quic_crypto_client_config.cc b/net/quic/crypto/quic_crypto_client_config.cc
index 4828c3a..268c8ee 100644
--- a/net/quic/crypto/quic_crypto_client_config.cc
+++ b/net/quic/crypto/quic_crypto_client_config.cc
@@ -847,8 +847,9 @@
       break;
     }
   }
-  if (i == canonical_suffixes_.size())
+  if (i == canonical_suffixes_.size()) {
     return false;
+  }
 
   QuicServerId suffix_server_id(canonical_suffixes_[i], server_id.port(),
                                 server_id.is_https(),
diff --git a/net/quic/crypto/quic_crypto_server_config.h b/net/quic/crypto/quic_crypto_server_config.h
index dbbff1a..8a58aea 100644
--- a/net/quic/crypto/quic_crypto_server_config.h
+++ b/net/quic/crypto/quic_crypto_server_config.h
@@ -15,11 +15,11 @@
 #include "base/synchronization/lock.h"
 #include "net/base/ip_endpoint.h"
 #include "net/base/net_export.h"
+#include "net/quic/crypto/cached_network_parameters.h"
 #include "net/quic/crypto/crypto_handshake.h"
 #include "net/quic/crypto/crypto_handshake_message.h"
 #include "net/quic/crypto/crypto_protocol.h"
 #include "net/quic/crypto/crypto_secret_boxer.h"
-#include "net/quic/crypto/source_address_token.h"
 #include "net/quic/quic_time.h"
 
 namespace net {
diff --git a/net/quic/crypto/source_address_token.cc b/net/quic/crypto/source_address_token.cc
index 0b514fe..5faedaa 100644
--- a/net/quic/crypto/source_address_token.cc
+++ b/net/quic/crypto/source_address_token.cc
@@ -11,37 +11,6 @@
 
 namespace net {
 
-CachedNetworkParameters::CachedNetworkParameters()
-    : bandwidth_estimate_bytes_per_second_(0),
-      max_bandwidth_estimate_bytes_per_second_(0),
-      max_bandwidth_timestamp_seconds_(0),
-      min_rtt_ms_(0),
-      previous_connection_state_(0),
-      timestamp_(0) {
-}
-
-CachedNetworkParameters::~CachedNetworkParameters() {
-}
-
-bool CachedNetworkParameters::operator==(
-    const CachedNetworkParameters& other) const {
-  return serving_region_ == other.serving_region_ &&
-      bandwidth_estimate_bytes_per_second_ ==
-          other.bandwidth_estimate_bytes_per_second_ &&
-      max_bandwidth_estimate_bytes_per_second_ ==
-          other.max_bandwidth_estimate_bytes_per_second_ &&
-      max_bandwidth_timestamp_seconds_ ==
-          other.max_bandwidth_timestamp_seconds_ &&
-      min_rtt_ms_ == other.min_rtt_ms_ &&
-      previous_connection_state_ == other.previous_connection_state_ &&
-      timestamp_ == other.timestamp_;
-}
-
-bool CachedNetworkParameters::operator!=(
-    const CachedNetworkParameters& other) const {
-  return !(*this == other);
-}
-
 SourceAddressToken::SourceAddressToken()
     : has_cached_network_parameters_(false) {
 }
diff --git a/net/quic/crypto/source_address_token.h b/net/quic/crypto/source_address_token.h
index 76c3454..f9a5098 100644
--- a/net/quic/crypto/source_address_token.h
+++ b/net/quic/crypto/source_address_token.h
@@ -10,101 +10,11 @@
 #include "base/basictypes.h"
 #include "base/strings/string_piece.h"
 #include "net/base/net_export.h"
+#include "net/quic/crypto/cached_network_parameters.h"
 
 namespace net {
 
 // TODO(rtenneti): sync with server more rationally.
-// CachedNetworkParameters contains data that can be used to choose appropriate
-// connection parameters (initial RTT, initial CWND, etc.) in new connections.
-class NET_EXPORT_PRIVATE CachedNetworkParameters {
- public:
-  // Describes the state of the connection during which the supplied network
-  // parameters were calculated.
-  enum PreviousConnectionState {
-    SLOW_START = 0,
-    CONGESTION_AVOIDANCE = 1,
-  };
-
-  CachedNetworkParameters();
-  ~CachedNetworkParameters();
-
-  bool operator==(const CachedNetworkParameters& other) const;
-  bool operator!=(const CachedNetworkParameters& other) const;
-
-  std::string serving_region() const {
-    return serving_region_;
-  }
-  void set_serving_region(base::StringPiece serving_region) {
-    serving_region_ = serving_region.as_string();
-  }
-
-  int32 bandwidth_estimate_bytes_per_second() const {
-    return bandwidth_estimate_bytes_per_second_;
-  }
-  void set_bandwidth_estimate_bytes_per_second(
-      int32 bandwidth_estimate_bytes_per_second) {
-    bandwidth_estimate_bytes_per_second_ = bandwidth_estimate_bytes_per_second;
-  }
-
-  int32 max_bandwidth_estimate_bytes_per_second() const {
-    return max_bandwidth_estimate_bytes_per_second_;
-  }
-  void set_max_bandwidth_estimate_bytes_per_second(
-      int32 max_bandwidth_estimate_bytes_per_second) {
-    max_bandwidth_estimate_bytes_per_second_ =
-        max_bandwidth_estimate_bytes_per_second;
-  }
-
-  int64 max_bandwidth_timestamp_seconds() const {
-    return max_bandwidth_timestamp_seconds_;
-  }
-  void set_max_bandwidth_timestamp_seconds(
-      int64 max_bandwidth_timestamp_seconds) {
-    max_bandwidth_timestamp_seconds_ = max_bandwidth_timestamp_seconds;
-  }
-
-  int32 min_rtt_ms() const {
-    return min_rtt_ms_;
-  }
-  void set_min_rtt_ms(int32 min_rtt_ms) {
-    min_rtt_ms_ = min_rtt_ms;
-  }
-
-  int32 previous_connection_state() const {
-    return previous_connection_state_;
-  }
-  void set_previous_connection_state(int32 previous_connection_state) {
-    previous_connection_state_ = previous_connection_state;
-  }
-
-  int64 timestamp() const { return timestamp_; }
-  void set_timestamp(int64 timestamp) { timestamp_ = timestamp; }
-
- private:
-  // serving_region_ is used to decide whether or not the bandwidth estimate and
-  // min RTT are reasonable and if they should be used.
-  // For example a group of geographically close servers may share the same
-  // serving_region_ string if they are expected to have similar network
-  // performance.
-  std::string serving_region_;
-  // The server can supply a bandwidth estimate (in bytes/s) which it may re-use
-  // on receipt of a source-address token with this field set.
-  int32 bandwidth_estimate_bytes_per_second_;
-  // The maximum bandwidth seen by the client, not necessarily the latest.
-  int32 max_bandwidth_estimate_bytes_per_second_;
-  // Timestamp (seconds since UNIX epoch) that indicates when the max bandwidth
-  // was seen by the server.
-  int64 max_bandwidth_timestamp_seconds_;
-  // The min RTT seen on a previous connection can be used by the server to
-  // inform initial connection parameters for new connections.
-  int32 min_rtt_ms_;
-  // Encodes the PreviousConnectionState enum.
-  int32 previous_connection_state_;
-  // UNIX timestamp when this bandwidth estimate was created.
-  int64 timestamp_;
-};
-
-// TODO(rtenneti): sync with server more rationally.
 // A SourceAddressToken is serialised, encrypted and sent to clients so that
 // they can prove ownership of an IP address.
 class NET_EXPORT_PRIVATE SourceAddressToken {
diff --git a/net/quic/quic_client_session.cc b/net/quic/quic_client_session.cc
index 73a5aec..274099c 100644
--- a/net/quic/quic_client_session.cc
+++ b/net/quic/quic_client_session.cc
@@ -155,10 +155,9 @@
     TransportSecurityState* transport_security_state,
     scoped_ptr<QuicServerInfo> server_info,
     const QuicConfig& config,
-    bool is_secure,
     base::TaskRunner* task_runner,
     NetLog* net_log)
-    : QuicClientSessionBase(connection, config, is_secure),
+    : QuicClientSessionBase(connection, config),
       require_confirmation_(false),
       stream_factory_(stream_factory),
       socket_(socket.Pass()),
diff --git a/net/quic/quic_client_session.h b/net/quic/quic_client_session.h
index 6c33eb5..b1a35d9 100644
--- a/net/quic/quic_client_session.h
+++ b/net/quic/quic_client_session.h
@@ -96,7 +96,6 @@
                     TransportSecurityState* transport_security_state,
                     scoped_ptr<QuicServerInfo> server_info,
                     const QuicConfig& config,
-                    bool is_secure,
                     base::TaskRunner* task_runner,
                     NetLog* net_log);
   ~QuicClientSession() override;
diff --git a/net/quic/quic_client_session_base.cc b/net/quic/quic_client_session_base.cc
index 5b5902b..40d4b86 100644
--- a/net/quic/quic_client_session_base.cc
+++ b/net/quic/quic_client_session_base.cc
@@ -10,9 +10,8 @@
 
 QuicClientSessionBase::QuicClientSessionBase(
     QuicConnection* connection,
-    const QuicConfig& config,
-    bool is_secure)
-    : QuicSession(connection, config, is_secure) {}
+    const QuicConfig& config)
+    : QuicSession(connection, config) {}
 
 QuicClientSessionBase::~QuicClientSessionBase() {}
 
diff --git a/net/quic/quic_client_session_base.h b/net/quic/quic_client_session_base.h
index a7f64fb..d72996c 100644
--- a/net/quic/quic_client_session_base.h
+++ b/net/quic/quic_client_session_base.h
@@ -14,8 +14,7 @@
 class NET_EXPORT_PRIVATE QuicClientSessionBase : public QuicSession {
  public:
   QuicClientSessionBase(QuicConnection* connection,
-                        const QuicConfig& config,
-                        bool is_secure);
+                        const QuicConfig& config);
 
   ~QuicClientSessionBase() override;
 
diff --git a/net/quic/quic_client_session_test.cc b/net/quic/quic_client_session_test.cc
index 8860f2e..66583b8 100644
--- a/net/quic/quic_client_session_test.cc
+++ b/net/quic/quic_client_session_test.cc
@@ -46,7 +46,6 @@
         session_(connection_, GetSocket().Pass(), nullptr,
                  &transport_security_state_,
                  make_scoped_ptr((QuicServerInfo*)nullptr), DefaultQuicConfig(),
-                 /*is_secure=*/false,
                  base::MessageLoop::current()->message_loop_proxy().get(),
                  &net_log_) {
     session_.InitializeSession(QuicServerId(kServerHostname, kServerPort,
diff --git a/net/quic/quic_config.cc b/net/quic/quic_config.cc
index b1b7343..622cf3f 100644
--- a/net/quic/quic_config.cc
+++ b/net/quic/quic_config.cc
@@ -434,7 +434,6 @@
       keepalive_timeout_seconds_(kKATO, PRESENCE_OPTIONAL),
       max_streams_per_connection_(kMSPC, PRESENCE_REQUIRED),
       bytes_for_connection_id_(kTCID, PRESENCE_OPTIONAL),
-      initial_congestion_window_(kSWND, PRESENCE_OPTIONAL),
       initial_round_trip_time_us_(kIRTT, PRESENCE_OPTIONAL),
       // TODO(rjshade): Remove this when retiring QUIC_VERSION_19.
       initial_flow_control_window_bytes_(kIFCW, PRESENCE_OPTIONAL),
@@ -524,18 +523,6 @@
   return bytes_for_connection_id_.GetReceivedValue();
 }
 
-void QuicConfig::SetInitialCongestionWindowToSend(size_t initial_window) {
-  initial_congestion_window_.SetSendValue(initial_window);
-}
-
-bool QuicConfig::HasReceivedInitialCongestionWindow() const {
-  return initial_congestion_window_.HasReceivedValue();
-}
-
-uint32 QuicConfig::ReceivedInitialCongestionWindow() const {
-  return initial_congestion_window_.GetReceivedValue();
-}
-
 void QuicConfig::SetInitialRoundTripTimeUsToSend(size_t rtt) {
   initial_round_trip_time_us_.SetSendValue(rtt);
 }
@@ -675,7 +662,6 @@
   keepalive_timeout_seconds_.ToHandshakeMessage(out);
   max_streams_per_connection_.ToHandshakeMessage(out);
   bytes_for_connection_id_.ToHandshakeMessage(out);
-  initial_congestion_window_.ToHandshakeMessage(out);
   initial_round_trip_time_us_.ToHandshakeMessage(out);
   initial_flow_control_window_bytes_.ToHandshakeMessage(out);
   initial_stream_flow_control_window_bytes_.ToHandshakeMessage(out);
@@ -712,10 +698,6 @@
         peer_hello, hello_type, error_details);
   }
   if (error == QUIC_NO_ERROR) {
-    error = initial_congestion_window_.ProcessPeerHello(
-        peer_hello, hello_type, error_details);
-  }
-  if (error == QUIC_NO_ERROR) {
     error = initial_round_trip_time_us_.ProcessPeerHello(
         peer_hello, hello_type, error_details);
   }
diff --git a/net/quic/quic_config.h b/net/quic/quic_config.h
index a4d6129..cf3775c 100644
--- a/net/quic/quic_config.h
+++ b/net/quic/quic_config.h
@@ -319,13 +319,6 @@
 
   uint32 ReceivedBytesForConnectionId() const;
 
-  // Sets the peer's default initial congestion window in packets.
-  void SetInitialCongestionWindowToSend(size_t initial_window);
-
-  bool HasReceivedInitialCongestionWindow() const;
-
-  uint32 ReceivedInitialCongestionWindow() const;
-
   // Sets an estimated initial round trip time in us.
   void SetInitialRoundTripTimeUsToSend(size_t rtt_us);
 
@@ -413,8 +406,6 @@
   QuicNegotiableUint32 max_streams_per_connection_;
   // The number of bytes required for the connection ID.
   QuicFixedUint32 bytes_for_connection_id_;
-  // Initial congestion window in packets.
-  QuicFixedUint32 initial_congestion_window_;
   // Initial round trip time estimate in microseconds.
   QuicFixedUint32 initial_round_trip_time_us_;
 
diff --git a/net/quic/quic_config_test.cc b/net/quic/quic_config_test.cc
index 914b137..413d7fb 100644
--- a/net/quic/quic_config_test.cc
+++ b/net/quic/quic_config_test.cc
@@ -81,8 +81,7 @@
       QuicTime::Delta::FromSeconds(kMaximumIdleTimeoutSecs));
   client_config.SetMaxStreamsPerConnection(
       2 * kDefaultMaxStreamsPerConnection, kDefaultMaxStreamsPerConnection);
-  client_config.SetInitialRoundTripTimeUsToSend(
-      10 * base::Time::kMicrosecondsPerMillisecond);
+  client_config.SetInitialRoundTripTimeUsToSend(10 * kNumMicrosPerMilli);
   client_config.SetInitialFlowControlWindowToSend(
       2 * kInitialSessionFlowControlWindowForTest);
   client_config.SetInitialStreamFlowControlWindowToSend(
@@ -107,8 +106,7 @@
   EXPECT_EQ(kDefaultMaxStreamsPerConnection,
             config_.MaxStreamsPerConnection());
   EXPECT_EQ(QuicTime::Delta::FromSeconds(0), config_.KeepaliveTimeout());
-  EXPECT_EQ(10 * base::Time::kMicrosecondsPerMillisecond,
-            config_.ReceivedInitialRoundTripTimeUs());
+  EXPECT_EQ(10 * kNumMicrosPerMilli, config_.ReceivedInitialRoundTripTimeUs());
   EXPECT_TRUE(config_.HasReceivedConnectionOptions());
   EXPECT_EQ(2u, config_.ReceivedConnectionOptions().size());
   EXPECT_EQ(config_.ReceivedConnectionOptions()[0], kTBBR);
@@ -134,9 +132,7 @@
   server_config.SetMaxStreamsPerConnection(
       kDefaultMaxStreamsPerConnection / 2,
       kDefaultMaxStreamsPerConnection / 2);
-  server_config.SetInitialCongestionWindowToSend(kDefaultInitialWindow / 2);
-  server_config.SetInitialRoundTripTimeUsToSend(
-      10 * base::Time::kMicrosecondsPerMillisecond);
+  server_config.SetInitialRoundTripTimeUsToSend(10 * kNumMicrosPerMilli);
   server_config.SetInitialFlowControlWindowToSend(
       2 * kInitialSessionFlowControlWindowForTest);
   server_config.SetInitialStreamFlowControlWindowToSend(
@@ -156,11 +152,8 @@
             config_.IdleConnectionStateLifetime());
   EXPECT_EQ(kDefaultMaxStreamsPerConnection / 2,
             config_.MaxStreamsPerConnection());
-  EXPECT_EQ(kDefaultInitialWindow / 2,
-            config_.ReceivedInitialCongestionWindow());
   EXPECT_EQ(QuicTime::Delta::FromSeconds(0), config_.KeepaliveTimeout());
-  EXPECT_EQ(10 * base::Time::kMicrosecondsPerMillisecond,
-            config_.ReceivedInitialRoundTripTimeUs());
+  EXPECT_EQ(10 * kNumMicrosPerMilli, config_.ReceivedInitialRoundTripTimeUs());
   EXPECT_EQ(config_.ReceivedInitialFlowControlWindowBytes(),
             2 * kInitialSessionFlowControlWindowForTest);
   EXPECT_EQ(config_.ReceivedInitialStreamFlowControlWindowBytes(),
diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc
index 6308d88..fd9ec5f 100644
--- a/net/quic/quic_connection.cc
+++ b/net/quic/quic_connection.cc
@@ -189,6 +189,7 @@
                                const PacketWriterFactory& writer_factory,
                                bool owns_writer,
                                bool is_server,
+                               bool is_secure,
                                const QuicVersionVector& supported_versions)
     : framer_(supported_versions, helper->GetClock()->ApproximateNow(),
               is_server),
@@ -222,9 +223,7 @@
       timeout_alarm_(helper->CreateAlarm(new TimeoutAlarm(this))),
       ping_alarm_(helper->CreateAlarm(new PingAlarm(this))),
       packet_generator_(connection_id_, &framer_, random_generator_, this),
-      idle_network_timeout_(FLAGS_quic_unified_timeouts ?
-          QuicTime::Delta::Infinite() :
-          QuicTime::Delta::FromSeconds(kDefaultIdleTimeoutSecs)),
+      idle_network_timeout_(QuicTime::Delta::Infinite()),
       overall_connection_timeout_(QuicTime::Delta::Infinite()),
       time_of_last_received_packet_(clock_->ApproximateNow()),
       time_of_last_sent_new_packet_(clock_->ApproximateNow()),
@@ -232,7 +231,8 @@
       sent_packet_manager_(
           is_server, clock_, &stats_,
           FLAGS_quic_use_bbr_congestion_control ? kBBR : kCubic,
-          FLAGS_quic_use_time_loss_detection ? kTime : kNack),
+          FLAGS_quic_use_time_loss_detection ? kTime : kNack,
+          is_secure),
       version_negotiation_state_(START_NEGOTIATION),
       is_server_(is_server),
       connected_(true),
@@ -240,12 +240,10 @@
       peer_port_changed_(false),
       self_ip_changed_(false),
       self_port_changed_(false),
-      can_truncate_connection_ids_(true) {
+      can_truncate_connection_ids_(true),
+      is_secure_(is_secure) {
   DVLOG(1) << ENDPOINT << "Created connection with connection_id: "
            << connection_id;
-  if (!FLAGS_quic_unified_timeouts) {
-    timeout_alarm_->Set(clock_->ApproximateNow().Add(idle_network_timeout_));
-  }
   framer_.set_visitor(this);
   framer_.set_received_entropy_calculator(&received_packet_manager_);
   stats_.connection_creation_time = clock_->ApproximateNow();
@@ -266,17 +264,14 @@
 }
 
 void QuicConnection::SetFromConfig(const QuicConfig& config) {
-  if (FLAGS_quic_unified_timeouts) {
-    if (config.negotiated()) {
-      SetNetworkTimeouts(QuicTime::Delta::Infinite(),
-                         config.IdleConnectionStateLifetime());
-    } else {
-      SetNetworkTimeouts(config.max_time_before_crypto_handshake(),
-                         config.max_idle_time_before_crypto_handshake());
-    }
+  if (config.negotiated()) {
+    SetNetworkTimeouts(QuicTime::Delta::Infinite(),
+                       config.IdleConnectionStateLifetime());
   } else {
-    SetIdleNetworkTimeout(config.IdleConnectionStateLifetime());
+    SetNetworkTimeouts(config.max_time_before_crypto_handshake(),
+                       config.max_idle_time_before_crypto_handshake());
   }
+
   sent_packet_manager_.SetFromConfig(config);
   if (FLAGS_allow_truncated_connection_ids_for_quic &&
       config.HasReceivedBytesForConnectionId() &&
@@ -1898,11 +1893,11 @@
   }
 }
 
-size_t QuicConnection::max_packet_length() const {
+QuicByteCount QuicConnection::max_packet_length() const {
   return packet_generator_.max_packet_length();
 }
 
-void QuicConnection::set_max_packet_length(size_t length) {
+void QuicConnection::set_max_packet_length(QuicByteCount length) {
   return packet_generator_.set_max_packet_length(length);
 }
 
@@ -1928,32 +1923,6 @@
                               pending_handshake);
 }
 
-void QuicConnection::SetIdleNetworkTimeout(QuicTime::Delta timeout) {
-  // Adjust the idle timeout on client and server to prevent clients from
-  // sending requests to servers which have already closed the connection.
-  if (is_server_) {
-    timeout = timeout.Add(QuicTime::Delta::FromSeconds(3));
-  } else if (timeout > QuicTime::Delta::FromSeconds(1)) {
-    timeout = timeout.Subtract(QuicTime::Delta::FromSeconds(1));
-  }
-
-  if (timeout < idle_network_timeout_) {
-    idle_network_timeout_ = timeout;
-    SetTimeoutAlarm();
-  } else {
-    idle_network_timeout_ = timeout;
-  }
-}
-
-void QuicConnection::SetOverallConnectionTimeout(QuicTime::Delta timeout) {
-  if (timeout < overall_connection_timeout_) {
-    overall_connection_timeout_ = timeout;
-    SetTimeoutAlarm();
-  } else {
-    overall_connection_timeout_ = timeout;
-  }
-}
-
 void QuicConnection::SetNetworkTimeouts(QuicTime::Delta overall_timeout,
                                         QuicTime::Delta idle_timeout) {
   LOG_IF(DFATAL, idle_timeout > overall_timeout)
diff --git a/net/quic/quic_connection.h b/net/quic/quic_connection.h
index f9f8733..96f5cbc 100644
--- a/net/quic/quic_connection.h
+++ b/net/quic/quic_connection.h
@@ -251,6 +251,7 @@
                  const PacketWriterFactory& writer_factory,
                  bool owns_writer,
                  bool is_server,
+                 bool is_secure,
                  const QuicVersionVector& supported_versions);
   ~QuicConnection() override;
 
@@ -397,8 +398,8 @@
   QuicConnectionId connection_id() const { return connection_id_; }
   const QuicClock* clock() const { return clock_; }
   QuicRandom* random_generator() const { return random_generator_; }
-  size_t max_packet_length() const;
-  void set_max_packet_length(size_t length);
+  QuicByteCount max_packet_length() const;
+  void set_max_packet_length(QuicByteCount length);
 
   bool connected() const { return connected_; }
 
@@ -425,16 +426,6 @@
   // Returns true if the connection has queued packets or frames.
   bool HasQueuedData() const;
 
-  // TODO(ianswett): Remove when quic_unified_timeouts is removed.
-  // Sets (or resets) the idle state connection timeout. Also, checks and times
-  // out the connection if network timer has expired for |timeout|.
-  void SetIdleNetworkTimeout(QuicTime::Delta timeout);
-
-  // Sets (or resets) the total time delta the connection can be alive for.
-  // Used to limit the time a connection can be alive before crypto handshake
-  // finishes.
-  void SetOverallConnectionTimeout(QuicTime::Delta timeout);
-
   // Sets the overall and idle state connection timeouts.
   void SetNetworkTimeouts(QuicTime::Delta overall_timeout,
                           QuicTime::Delta idle_timeout);
@@ -530,6 +521,9 @@
   QuicPacketSequenceNumber sequence_number_of_last_sent_packet() const {
     return sequence_number_of_last_sent_packet_;
   }
+  const QuicPacketWriter* writer() const { return writer_; }
+
+  bool is_secure() const { return is_secure_; }
 
  protected:
   // Packets which have not been written to the wire.
@@ -567,7 +561,6 @@
   bool SelectMutualVersion(const QuicVersionVector& available_versions);
 
   QuicPacketWriter* writer() { return writer_; }
-  const QuicPacketWriter* writer() const { return writer_; }
 
   bool peer_port_changed() const { return peer_port_changed_; }
 
@@ -702,7 +695,7 @@
   // decrypted.
   bool last_packet_decrypted_;
   bool last_packet_revived_;  // True if the last packet was revived from FEC.
-  size_t last_size_;  // Size of the last received packet.
+  QuicByteCount last_size_;  // Size of the last received packet.
   EncryptionLevel last_decrypted_packet_level_;
   QuicPacketHeader last_header_;
   std::vector<QuicStreamFrame> last_stream_frames_;
@@ -837,6 +830,9 @@
   // version negotiation packet.
   QuicVersionVector server_supported_versions_;
 
+  // True if this is a secure QUIC connection.
+  bool is_secure_;
+
   DISALLOW_COPY_AND_ASSIGN(QuicConnection);
 };
 
diff --git a/net/quic/quic_connection_test.cc b/net/quic/quic_connection_test.cc
index 66cb89c..4e58dfd 100644
--- a/net/quic/quic_connection_test.cc
+++ b/net/quic/quic_connection_test.cc
@@ -408,6 +408,7 @@
                        factory,
                        /* owns_writer= */ false,
                        is_server,
+                       /* is_secure= */ false,
                        SupportedVersions(version)) {
     // Disable tail loss probes for most tests.
     QuicSentPacketManagerPeer::SetMaxTailLossProbes(
@@ -2506,7 +2507,7 @@
 
 TEST_P(QuicConnectionTest, BufferNonDecryptablePackets) {
   // SetFromConfig is always called after construction from InitializeSession.
-  EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _, _));
   QuicConfig config;
   connection_.SetFromConfig(config);
   EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
@@ -2536,7 +2537,7 @@
 
 TEST_P(QuicConnectionTest, Buffer100NonDecryptablePackets) {
   // SetFromConfig is always called after construction from InitializeSession.
-  EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _, _));
   QuicConfig config;
   config.set_max_undecryptable_packets(100);
   connection_.SetFromConfig(config);
@@ -2775,36 +2776,12 @@
 }
 
 TEST_P(QuicConnectionTest, InitialTimeout) {
-  if (!FLAGS_quic_unified_timeouts) {
-    EXPECT_TRUE(connection_.connected());
-    EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_CONNECTION_TIMED_OUT, false));
-    EXPECT_CALL(*send_algorithm_,
-                OnPacketSent(_, _, _, _, _)).Times(AnyNumber());
-
-    QuicTime default_timeout = clock_.ApproximateNow().Add(
-        QuicTime::Delta::FromSeconds(kDefaultIdleTimeoutSecs));
-    EXPECT_EQ(default_timeout, connection_.GetTimeoutAlarm()->deadline());
-
-    // Simulate the timeout alarm firing.
-    clock_.AdvanceTime(QuicTime::Delta::FromSeconds(kDefaultIdleTimeoutSecs));
-    connection_.GetTimeoutAlarm()->Fire();
-
-    EXPECT_FALSE(connection_.GetTimeoutAlarm()->IsSet());
-    EXPECT_FALSE(connection_.connected());
-
-    EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
-    EXPECT_FALSE(connection_.GetPingAlarm()->IsSet());
-    EXPECT_FALSE(connection_.GetResumeWritesAlarm()->IsSet());
-    EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
-    EXPECT_FALSE(connection_.GetSendAlarm()->IsSet());
-    return;
-  }
   EXPECT_TRUE(connection_.connected());
   EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AnyNumber());
   EXPECT_FALSE(connection_.GetTimeoutAlarm()->IsSet());
 
   // SetFromConfig sets the initial timeouts before negotiation.
-  EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _, _));
   QuicConfig config;
   connection_.SetFromConfig(config);
   // Subtract a second from the idle timeout on the client side.
@@ -2913,44 +2890,8 @@
 }
 
 TEST_P(QuicConnectionTest, TimeoutAfterSend) {
-  if (!FLAGS_quic_unified_timeouts) {
-    EXPECT_TRUE(connection_.connected());
-
-    QuicTime default_timeout = clock_.ApproximateNow().Add(
-        QuicTime::Delta::FromSeconds(kDefaultIdleTimeoutSecs));
-
-    // When we send a packet, the timeout will change to 5000 +
-    // kDefaultInitialTimeoutSecs.
-    clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
-
-    // Send an ack so we don't set the retransmission alarm.
-    SendAckPacketToPeer();
-    EXPECT_EQ(default_timeout, connection_.GetTimeoutAlarm()->deadline());
-
-    // The original alarm will fire.  We should not time out because we had a
-    // network event at t=5000.  The alarm will reregister.
-    clock_.AdvanceTime(QuicTime::Delta::FromMicroseconds(
-        kDefaultIdleTimeoutSecs * 1000000 - 5000));
-    EXPECT_EQ(default_timeout, clock_.ApproximateNow());
-    connection_.GetTimeoutAlarm()->Fire();
-    EXPECT_TRUE(connection_.GetTimeoutAlarm()->IsSet());
-    EXPECT_TRUE(connection_.connected());
-    EXPECT_EQ(default_timeout.Add(QuicTime::Delta::FromMilliseconds(5)),
-              connection_.GetTimeoutAlarm()->deadline());
-
-    // This time, we should time out.
-    EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_CONNECTION_TIMED_OUT, false));
-    EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
-    clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
-    EXPECT_EQ(default_timeout.Add(QuicTime::Delta::FromMilliseconds(5)),
-              clock_.ApproximateNow());
-    connection_.GetTimeoutAlarm()->Fire();
-    EXPECT_FALSE(connection_.GetTimeoutAlarm()->IsSet());
-    EXPECT_FALSE(connection_.connected());
-    return;
-  }
   EXPECT_TRUE(connection_.connected());
-  EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _, _));
   QuicConfig config;
   connection_.SetFromConfig(config);
 
@@ -3055,7 +2996,7 @@
 
   // Set up a larger payload than will fit in one packet.
   const string payload(connection_.max_packet_length(), 'a');
-  EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)).Times(AnyNumber());
+  EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _, _)).Times(AnyNumber());
 
   // Now send some packets with no truncation.
   EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(2);
diff --git a/net/quic/quic_crypto_server_stream.cc b/net/quic/quic_crypto_server_stream.cc
index dac2087..1d62376 100644
--- a/net/quic/quic_crypto_server_stream.cc
+++ b/net/quic/quic_crypto_server_stream.cc
@@ -6,10 +6,10 @@
 
 #include "base/base64.h"
 #include "crypto/secure_hash.h"
+#include "net/quic/crypto/cached_network_parameters.h"
 #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/source_address_token.h"
 #include "net/quic/quic_config.h"
 #include "net/quic/quic_flags.h"
 #include "net/quic/quic_protocol.h"
diff --git a/net/quic/quic_dispatcher.cc b/net/quic/quic_dispatcher.cc
index aede7c2..d27b454 100644
--- a/net/quic/quic_dispatcher.cc
+++ b/net/quic/quic_dispatcher.cc
@@ -352,8 +352,7 @@
   QuicServerSession* session = new QuicServerSession(
       config_,
       CreateQuicConnection(connection_id, server_address, client_address),
-      this,
-      crypto_config_.HasProofSource());
+      this);
   session->InitializeSession(crypto_config_);
   return session;
 }
@@ -368,6 +367,7 @@
                             connection_writer_factory_,
                             /* owns_writer= */ true,
                             /* is_server= */ true,
+                            crypto_config_.HasProofSource(),
                             supported_versions_);
 }
 
diff --git a/net/quic/quic_flags.cc b/net/quic/quic_flags.cc
index 8d6dd86..47d58ce 100644
--- a/net/quic/quic_flags.cc
+++ b/net/quic/quic_flags.cc
@@ -36,10 +36,6 @@
 // limit.
 bool FLAGS_quic_allow_more_open_streams = false;
 
-// If true, then QUIC connections will set both idle and overall timeouts in a
-// single method.
-bool FLAGS_quic_unified_timeouts = true;
-
 // If true, QUIC will be more resilliant to junk packets with valid connection
 // IDs.
 bool FLAGS_quic_drop_junk_packets = true;
diff --git a/net/quic/quic_flags.h b/net/quic/quic_flags.h
index d49f47a..a75f79b 100644
--- a/net/quic/quic_flags.h
+++ b/net/quic/quic_flags.h
@@ -15,7 +15,6 @@
 NET_EXPORT_PRIVATE extern bool FLAGS_enable_quic_fec;
 NET_EXPORT_PRIVATE extern bool FLAGS_quic_use_bbr_congestion_control;
 NET_EXPORT_PRIVATE extern bool FLAGS_quic_allow_more_open_streams;
-NET_EXPORT_PRIVATE extern bool FLAGS_quic_unified_timeouts;
 NET_EXPORT_PRIVATE extern bool FLAGS_quic_drop_junk_packets;
 NET_EXPORT_PRIVATE extern bool FLAGS_quic_allow_bbr;
 NET_EXPORT_PRIVATE extern bool FLAGS_allow_truncated_connection_ids_for_quic;
diff --git a/net/quic/quic_framer.cc b/net/quic/quic_framer.cc
index e2487b4..d2a7694 100644
--- a/net/quic/quic_framer.cc
+++ b/net/quic/quic_framer.cc
@@ -978,30 +978,30 @@
 QuicFramer::AckFrameInfo QuicFramer::GetAckFrameInfo(
     const QuicAckFrame& frame) {
   AckFrameInfo ack_info;
-  if (!frame.missing_packets.empty()) {
-    DCHECK_GE(frame.largest_observed, *frame.missing_packets.rbegin());
-    size_t cur_range_length = 0;
-    SequenceNumberSet::const_iterator iter = frame.missing_packets.begin();
-    QuicPacketSequenceNumber last_missing = *iter;
-    ++iter;
-    for (; iter != frame.missing_packets.end(); ++iter) {
-      if (cur_range_length != numeric_limits<uint8>::max() &&
-          *iter == (last_missing + 1)) {
-        ++cur_range_length;
-      } else {
-        ack_info.nack_ranges[last_missing - cur_range_length] =
-            cur_range_length;
-        cur_range_length = 0;
-      }
-      ack_info.max_delta = max(ack_info.max_delta, *iter - last_missing);
-      last_missing = *iter;
-    }
-    // Include the last nack range.
-    ack_info.nack_ranges[last_missing - cur_range_length] = cur_range_length;
-    // Include the range to the largest observed.
-    ack_info.max_delta = max(ack_info.max_delta,
-                             frame.largest_observed - last_missing);
+  if (frame.missing_packets.empty()) {
+    return ack_info;
   }
+  DCHECK_GE(frame.largest_observed, *frame.missing_packets.rbegin());
+  size_t cur_range_length = 0;
+  SequenceNumberSet::const_iterator iter = frame.missing_packets.begin();
+  QuicPacketSequenceNumber last_missing = *iter;
+  ++iter;
+  for (; iter != frame.missing_packets.end(); ++iter) {
+    if (cur_range_length != numeric_limits<uint8>::max() &&
+        *iter == (last_missing + 1)) {
+      ++cur_range_length;
+    } else {
+      ack_info.nack_ranges[last_missing - cur_range_length] = cur_range_length;
+      cur_range_length = 0;
+    }
+    ack_info.max_delta = max(ack_info.max_delta, *iter - last_missing);
+    last_missing = *iter;
+  }
+  // Include the last nack range.
+  ack_info.nack_ranges[last_missing - cur_range_length] = cur_range_length;
+  // Include the range to the largest observed.
+  ack_info.max_delta =
+      max(ack_info.max_delta, frame.largest_observed - last_missing);
   return ack_info;
 }
 
diff --git a/net/quic/quic_http_stream_test.cc b/net/quic/quic_http_stream_test.cc
index db97aac..a172c24 100644
--- a/net/quic/quic_http_stream_test.cc
+++ b/net/quic/quic_http_stream_test.cc
@@ -65,8 +65,9 @@
                        address,
                        helper,
                        writer_factory,
-                       true  /* owns_writer */,
+                       true   /* owns_writer */,
                        false  /* is_server */,
+                       false  /* is_secure */,
                        versions) {
   }
 
@@ -215,7 +216,7 @@
         WillRepeatedly(Return(QuicTime::Delta::Zero()));
     EXPECT_CALL(*send_algorithm_, BandwidthEstimate()).WillRepeatedly(
         Return(QuicBandwidth::Zero()));
-    EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)).Times(AnyNumber());
+    EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _, _)).Times(AnyNumber());
     helper_.reset(new QuicConnectionHelper(runner_.get(), &clock_,
                                            &random_generator_));
     TestPacketWriterFactory writer_factory(socket);
@@ -232,7 +233,6 @@
                               &transport_security_state_,
                               make_scoped_ptr((QuicServerInfo*)nullptr),
                               DefaultQuicConfig(),
-                              /*is_secure=*/false,
                               base::MessageLoop::current()->
                                   message_loop_proxy().get(),
                               nullptr));
diff --git a/net/quic/quic_packet_creator.h b/net/quic/quic_packet_creator.h
index 287cde1..bada2c3 100644
--- a/net/quic/quic_packet_creator.h
+++ b/net/quic/quic_packet_creator.h
@@ -212,11 +212,11 @@
     next_sequence_number_length_ = length;
   }
 
-  size_t max_packet_length() const {
+  QuicByteCount max_packet_length() const {
     return max_packet_length_;
   }
 
-  void set_max_packet_length(size_t length) {
+  void set_max_packet_length(QuicByteCount length) {
     // |max_packet_length_| should not be changed mid-packet or mid-FEC group.
     DCHECK(fec_group_.get() == nullptr && queued_frames_.empty());
     max_packet_length_ = length;
@@ -272,7 +272,7 @@
   // packet.
   bool send_version_in_packet_;
   // Maximum length including headers and encryption (UDP payload length.)
-  size_t max_packet_length_;
+  QuicByteCount max_packet_length_;
   // 0 indicates FEC is disabled.
   size_t max_packets_per_fec_group_;
   // Length of connection_id to send over the wire.
diff --git a/net/quic/quic_packet_generator.cc b/net/quic/quic_packet_generator.cc
index 2481ddc..21ab10c 100644
--- a/net/quic/quic_packet_generator.cc
+++ b/net/quic/quic_packet_generator.cc
@@ -357,11 +357,11 @@
   return packet_creator_.sequence_number();
 }
 
-size_t QuicPacketGenerator::max_packet_length() const {
+QuicByteCount QuicPacketGenerator::max_packet_length() const {
   return packet_creator_.max_packet_length();
 }
 
-void QuicPacketGenerator::set_max_packet_length(size_t length) {
+void QuicPacketGenerator::set_max_packet_length(QuicByteCount length) {
   packet_creator_.set_max_packet_length(length);
 }
 
diff --git a/net/quic/quic_packet_generator.h b/net/quic/quic_packet_generator.h
index 3fec02a..2882aab 100644
--- a/net/quic/quic_packet_generator.h
+++ b/net/quic/quic_packet_generator.h
@@ -177,9 +177,9 @@
   // created.
   QuicPacketSequenceNumber sequence_number() const;
 
-  size_t max_packet_length() const;
+  QuicByteCount max_packet_length() const;
 
-  void set_max_packet_length(size_t length);
+  void set_max_packet_length(QuicByteCount length);
 
   void set_debug_delegate(DebugDelegate* debug_delegate) {
     debug_delegate_ = debug_delegate;
diff --git a/net/quic/quic_protocol.h b/net/quic/quic_protocol.h
index ad920d0..00064ff 100644
--- a/net/quic/quic_protocol.h
+++ b/net/quic/quic_protocol.h
@@ -60,8 +60,11 @@
 const QuicByteCount kDefaultTCPMSS = 1460;
 
 // Maximum size of the initial congestion window in packets.
-const QuicPacketCount kDefaultInitialWindow = 10;
 const QuicPacketCount kMaxInitialWindow = 100;
+// We match SPDY's use of 32 when secure (since we'd compete with SPDY).
+const QuicPacketCount kInitialCongestionWindowSecure = 32;
+// Be conservative, and just use double a typical TCP ICWND for HTTP.
+const QuicPacketCount kInitialCongestionWindowInsecure = 20;
 
 // Default size of initial flow control window, for both stream and session.
 const uint32 kDefaultFlowControlSendWindow = 16 * 1024;  // 16 KB
diff --git a/net/quic/quic_reliable_client_stream.cc b/net/quic/quic_reliable_client_stream.cc
index e186b03..68651cb 100644
--- a/net/quic/quic_reliable_client_stream.cc
+++ b/net/quic/quic_reliable_client_stream.cc
@@ -83,7 +83,7 @@
 
 void QuicReliableClientStream::SetDelegate(
     QuicReliableClientStream::Delegate* delegate) {
-  DCHECK((!delegate_ && delegate) || (delegate_ && !delegate));
+  DCHECK(!(delegate_ && delegate));
   delegate_ = delegate;
 }
 
diff --git a/net/quic/quic_sent_packet_manager.cc b/net/quic/quic_sent_packet_manager.cc
index 9e2d04f..7978fed 100644
--- a/net/quic/quic_sent_packet_manager.cc
+++ b/net/quic/quic_sent_packet_manager.cc
@@ -34,8 +34,8 @@
 static const int64 kMaxRetransmissionTimeMs = 60000;
 static const size_t kMaxRetransmissions = 10;
 
-// Only exponentially back off the handshake timer 5 times due to a timeout.
-static const size_t kMaxHandshakeRetransmissionBackoffs = 5;
+// Ensure the handshake timer isnt't faster than 10ms.
+// This limits the tenth retransmitted packet to 10s after the initial CHLO.
 static const int64 kMinHandshakeTimeoutMs = 10;
 
 // Sends up to two tail loss probes before firing an RTO,
@@ -49,6 +49,10 @@
 // Number of unpaced packets to send after quiescence.
 static const size_t kInitialUnpacedBurst = 10;
 
+// Fraction of the receive buffer that can be used for encrypted bytes.
+// Allows a 5% overhead for IP and UDP framing, as well as ack only packets.
+static const float kUsableRecieveBufferFraction = 0.95f;
+
 bool HasCryptoHandshake(const TransmissionInfo& transmission_info) {
   if (transmission_info.retransmittable_frames == nullptr) {
     return false;
@@ -66,17 +70,22 @@
     const QuicClock* clock,
     QuicConnectionStats* stats,
     CongestionControlType congestion_control_type,
-    LossDetectionType loss_type)
+    LossDetectionType loss_type,
+    bool is_secure)
     : unacked_packets_(),
       is_server_(is_server),
       clock_(clock),
       stats_(stats),
       debug_delegate_(nullptr),
       network_change_visitor_(nullptr),
-      send_algorithm_(SendAlgorithmInterface::Create(clock,
-                                                     &rtt_stats_,
-                                                     congestion_control_type,
-                                                     stats)),
+      initial_congestion_window_(is_secure ? kInitialCongestionWindowSecure
+                                           : kInitialCongestionWindowInsecure),
+      send_algorithm_(
+          SendAlgorithmInterface::Create(clock,
+                                         &rtt_stats_,
+                                         congestion_control_type,
+                                         stats,
+                                         initial_congestion_window_)),
       loss_algorithm_(LossDetectionInterface::Create(loss_type)),
       n_connection_simulation_(false),
       receive_buffer_bytes_(kDefaultSocketReceiveBuffer),
@@ -116,15 +125,17 @@
       rtt_stats_.set_recent_min_rtt_window(
           QuicTime::Delta::FromSeconds(FLAGS_quic_recent_min_rtt_window_s));
     }
-    send_algorithm_.reset(
-        SendAlgorithmInterface::Create(clock_, &rtt_stats_, kBBR, stats_));
+    send_algorithm_.reset(SendAlgorithmInterface::Create(
+        clock_, &rtt_stats_, kBBR, stats_, initial_congestion_window_));
   }
   if (config.HasReceivedConnectionOptions() &&
       ContainsQuicTag(config.ReceivedConnectionOptions(), kRENO)) {
-    send_algorithm_.reset(
-        SendAlgorithmInterface::Create(clock_, &rtt_stats_, kReno, stats_));
+    send_algorithm_.reset(SendAlgorithmInterface::Create(
+        clock_, &rtt_stats_, kReno, stats_, initial_congestion_window_));
   }
-  if (HasClientSentConnectionOption(config, kPACE)) {
+  if (HasClientSentConnectionOption(config, kPACE) ||
+      (FLAGS_quic_allow_bbr &&
+       HasClientSentConnectionOption(config, kTBBR))) {
     EnablePacing();
   }
   if (HasClientSentConnectionOption(config, k1CON)) {
@@ -145,7 +156,7 @@
         max(kMinSocketReceiveBuffer,
             static_cast<QuicByteCount>(config.ReceivedSocketReceiveBuffer()));
   }
-  send_algorithm_->SetFromConfig(config, is_server_);
+  send_algorithm_->SetFromConfig(config, is_server_, using_pacing_);
 
   if (network_change_visitor_ != nullptr) {
     network_change_visitor_->OnCongestionWindowChange();
@@ -595,10 +606,7 @@
 
 void QuicSentPacketManager::RetransmitCryptoPackets() {
   DCHECK_EQ(HANDSHAKE_MODE, GetRetransmissionMode());
-  // TODO(ianswett): Typical TCP implementations only retransmit 5 times.
-  consecutive_crypto_retransmission_count_ =
-      min(kMaxHandshakeRetransmissionBackoffs,
-          consecutive_crypto_retransmission_count_ + 1);
+  ++consecutive_crypto_retransmission_count_;
   bool packet_retransmitted = false;
   QuicPacketSequenceNumber sequence_number = unacked_packets_.GetLeastUnacked();
   for (QuicUnackedPacketMap::const_iterator it = unacked_packets_.begin();
@@ -757,7 +765,8 @@
   if (pending_timer_transmission_count_ > 0) {
     return QuicTime::Delta::Zero();
   }
-  if (unacked_packets_.bytes_in_flight() >= receive_buffer_bytes_) {
+  if (unacked_packets_.bytes_in_flight() >=
+      kUsableRecieveBufferFraction * receive_buffer_bytes_) {
     return QuicTime::Delta::Infinite();
   }
   return send_algorithm_->TimeUntilSend(
diff --git a/net/quic/quic_sent_packet_manager.h b/net/quic/quic_sent_packet_manager.h
index f82e34b..2a3ea64 100644
--- a/net/quic/quic_sent_packet_manager.h
+++ b/net/quic/quic_sent_packet_manager.h
@@ -93,7 +93,8 @@
                         const QuicClock* clock,
                         QuicConnectionStats* stats,
                         CongestionControlType congestion_control_type,
-                        LossDetectionType loss_type);
+                        LossDetectionType loss_type,
+                        bool is_secure);
   virtual ~QuicSentPacketManager();
 
   virtual void SetFromConfig(const QuicConfig& config);
@@ -351,6 +352,7 @@
   QuicConnectionStats* stats_;
   DebugDelegate* debug_delegate_;
   NetworkChangeVisitor* network_change_visitor_;
+  const QuicPacketCount initial_congestion_window_;
   RttStats rtt_stats_;
   scoped_ptr<SendAlgorithmInterface> send_algorithm_;
   scoped_ptr<LossDetectionInterface> loss_algorithm_;
diff --git a/net/quic/quic_sent_packet_manager_test.cc b/net/quic/quic_sent_packet_manager_test.cc
index d7a846a..d710120 100644
--- a/net/quic/quic_sent_packet_manager_test.cc
+++ b/net/quic/quic_sent_packet_manager_test.cc
@@ -45,7 +45,7 @@
 class QuicSentPacketManagerTest : public ::testing::TestWithParam<bool> {
  protected:
   QuicSentPacketManagerTest()
-      : manager_(true, &clock_, &stats_, kCubic, kNack),
+      : manager_(true, &clock_, &stats_, kCubic, kNack, false),
         send_algorithm_(new StrictMock<MockSendAlgorithm>),
         network_change_visitor_(new StrictMock<MockNetworkChangeVisitor>) {
     QuicSentPacketManagerPeer::SetSendAlgorithm(&manager_, send_algorithm_);
@@ -1080,12 +1080,12 @@
 
   // Check the min.
   RttStats* rtt_stats = QuicSentPacketManagerPeer::GetRttStats(&manager_);
-  rtt_stats->set_initial_rtt_us(1 * base::Time::kMicrosecondsPerMillisecond);
+  rtt_stats->set_initial_rtt_us(1 * kNumMicrosPerMilli);
   EXPECT_EQ(clock_.Now().Add(QuicTime::Delta::FromMilliseconds(10)),
             manager_.GetRetransmissionTime());
 
   // Test with a standard smoothed RTT.
-  rtt_stats->set_initial_rtt_us(100 * base::Time::kMicrosecondsPerMillisecond);
+  rtt_stats->set_initial_rtt_us(100 * kNumMicrosPerMilli);
 
   QuicTime::Delta srtt =
       QuicTime::Delta::FromMicroseconds(rtt_stats->initial_rtt_us());
@@ -1109,12 +1109,12 @@
 
   // Check the min.
   RttStats* rtt_stats = QuicSentPacketManagerPeer::GetRttStats(&manager_);
-  rtt_stats->set_initial_rtt_us(1 * base::Time::kMicrosecondsPerMillisecond);
+  rtt_stats->set_initial_rtt_us(1 * kNumMicrosPerMilli);
   EXPECT_EQ(clock_.Now().Add(QuicTime::Delta::FromMilliseconds(10)),
             manager_.GetRetransmissionTime());
 
   // Test with a standard smoothed RTT.
-  rtt_stats->set_initial_rtt_us(100 * base::Time::kMicrosecondsPerMillisecond);
+  rtt_stats->set_initial_rtt_us(100 * kNumMicrosPerMilli);
   QuicTime::Delta srtt =
       QuicTime::Delta::FromMicroseconds(rtt_stats->initial_rtt_us());
   QuicTime::Delta expected_tlp_delay = srtt.Multiply(2);
@@ -1277,7 +1277,7 @@
   QuicTagVector options;
   options.push_back(kTIME);
   QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
-  EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _, _));
   EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange());
   manager_.SetFromConfig(config);
 
@@ -1318,7 +1318,7 @@
   QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
   EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange());
   EXPECT_CALL(*send_algorithm_, SetNumEmulatedConnections(1));
-  EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _, _));
   manager_.SetFromConfig(config);
 
   QuicSentPacketManagerPeer::SetIsServer(&manager_, false);
@@ -1326,7 +1326,7 @@
   client_config.SetConnectionOptionsToSend(options);
   EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange());
   EXPECT_CALL(*send_algorithm_, SetNumEmulatedConnections(1));
-  EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _, _));
   manager_.SetFromConfig(client_config);
 }
 
@@ -1340,7 +1340,7 @@
   options.push_back(kNCON);
   QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
   EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange());
-  EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _, _));
   manager_.SetFromConfig(config);
 
   EXPECT_CALL(*send_algorithm_, SetNumEmulatedConnections(5));
@@ -1354,7 +1354,7 @@
   options.push_back(kNTLP);
   QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
   EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange());
-  EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _, _));
   manager_.SetFromConfig(config);
   EXPECT_EQ(0u, QuicSentPacketManagerPeer::GetMaxTailLossProbes(&manager_));
 }
@@ -1367,7 +1367,7 @@
   QuicSentPacketManagerPeer::SetIsServer(&manager_, false);
   client_config.SetConnectionOptionsToSend(options);
   EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange());
-  EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _, _));
   manager_.SetFromConfig(client_config);
   EXPECT_EQ(0u, QuicSentPacketManagerPeer::GetMaxTailLossProbes(&manager_));
 }
@@ -1380,7 +1380,7 @@
   options.push_back(kPACE);
   QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
   EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange());
-  EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _, /* using_pacing= */ true));
   manager_.SetFromConfig(config);
 
   EXPECT_TRUE(manager_.using_pacing());
@@ -1393,7 +1393,7 @@
   // Try to set a size below the minimum and ensure it gets set to the min.
   QuicConfig client_config;
   QuicConfigPeer::SetReceivedSocketReceiveBuffer(&client_config, 1024);
-  EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _, _));
   EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange());
   manager_.SetFromConfig(client_config);
 
@@ -1417,6 +1417,27 @@
             manager_.TimeUntilSend(clock_.Now(), HAS_RETRANSMITTABLE_DATA));
 }
 
+TEST_F(QuicSentPacketManagerTest, ReceiveWindowLimited) {
+  EXPECT_EQ(kDefaultSocketReceiveBuffer,
+            QuicSentPacketManagerPeer::GetReceiveWindow(&manager_));
+
+  // Ensure the smaller send window only allows 256 * 0.95 packets to be sent.
+  for (QuicPacketSequenceNumber i = 1; i <= 244; ++i) {
+    EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _, _)).WillOnce(Return(
+        QuicTime::Delta::Zero()));
+    EXPECT_EQ(QuicTime::Delta::Zero(),
+              manager_.TimeUntilSend(clock_.Now(), HAS_RETRANSMITTABLE_DATA));
+    EXPECT_CALL(*send_algorithm_, OnPacketSent(_, BytesInFlight(), i,
+                                               1024, HAS_RETRANSMITTABLE_DATA))
+        .WillOnce(Return(true));
+    SerializedPacket packet(CreatePacket(i, true));
+    manager_.OnPacketSent(&packet, 0, clock_.Now(), 1024,
+                          NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA);
+  }
+  EXPECT_EQ(QuicTime::Delta::Infinite(),
+            manager_.TimeUntilSend(clock_.Now(), HAS_RETRANSMITTABLE_DATA));
+}
+
 TEST_F(QuicSentPacketManagerTest, UseInitialRoundTripTimeToSend) {
   uint32 initial_rtt_us = 325000;
   EXPECT_NE(initial_rtt_us,
@@ -1424,7 +1445,7 @@
 
   QuicConfig config;
   config.SetInitialRoundTripTimeUsToSend(initial_rtt_us);
-  EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _, _));
   EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange());
   manager_.SetFromConfig(config);
 
diff --git a/net/quic/quic_server_session.cc b/net/quic/quic_server_session.cc
index 7fab509..1d48182 100644
--- a/net/quic/quic_server_session.cc
+++ b/net/quic/quic_server_session.cc
@@ -5,7 +5,7 @@
 #include "net/quic/quic_server_session.h"
 
 #include "base/logging.h"
-#include "net/quic/crypto/source_address_token.h"
+#include "net/quic/crypto/cached_network_parameters.h"
 #include "net/quic/quic_connection.h"
 #include "net/quic/quic_flags.h"
 #include "net/quic/quic_spdy_server_stream.h"
@@ -15,9 +15,8 @@
 
 QuicServerSession::QuicServerSession(const QuicConfig& config,
                                      QuicConnection* connection,
-                                     QuicServerSessionVisitor* visitor,
-                                     bool is_secure)
-    : QuicSession(connection, config, is_secure),
+                                     QuicServerSessionVisitor* visitor)
+    : QuicSession(connection, config),
       visitor_(visitor),
       bandwidth_estimate_sent_to_client_(QuicBandwidth::Zero()),
       last_scup_time_(QuicTime::Zero()),
diff --git a/net/quic/quic_server_session.h b/net/quic/quic_server_session.h
index a402005..43107a0 100644
--- a/net/quic/quic_server_session.h
+++ b/net/quic/quic_server_session.h
@@ -46,8 +46,7 @@
  public:
   QuicServerSession(const QuicConfig& config,
                     QuicConnection* connection,
-                    QuicServerSessionVisitor* visitor,
-                    bool is_secure);
+                    QuicServerSessionVisitor* visitor);
 
   // Override the base class to notify the owner of the connection close.
   void OnConnectionClosed(QuicErrorCode error, bool from_peer) override;
diff --git a/net/quic/quic_session.cc b/net/quic/quic_session.cc
index 34a668d..2318ab4 100644
--- a/net/quic/quic_session.cc
+++ b/net/quic/quic_session.cc
@@ -95,8 +95,7 @@
   QuicSession* session_;
 };
 
-QuicSession::QuicSession(QuicConnection* connection, const QuicConfig& config,
-                         bool is_secure)
+QuicSession::QuicSession(QuicConnection* connection, const QuicConfig& config)
     : connection_(connection),
       visitor_shim_(new VisitorShim(this)),
       config_(config),
@@ -106,8 +105,7 @@
       error_(QUIC_NO_ERROR),
       goaway_received_(false),
       goaway_sent_(false),
-      has_pending_handshake_(false),
-      is_secure_(is_secure) {
+      has_pending_handshake_(false) {
   if (connection_->version() == QUIC_VERSION_19) {
     flow_controller_.reset(new QuicFlowController(
         connection_.get(), 0, is_server(), kDefaultFlowControlSendWindow,
@@ -124,10 +122,6 @@
 void QuicSession::InitializeSession() {
   connection_->set_visitor(visitor_shim_.get());
   connection_->SetFromConfig(config_);
-  if (!FLAGS_quic_unified_timeouts && connection_->connected()) {
-    connection_->SetOverallConnectionTimeout(
-        config_.max_time_before_crypto_handshake());
-  }
   headers_stream_.reset(new QuicHeadersStream(this));
 }
 
@@ -569,9 +563,6 @@
       // Discard originally encrypted packets, since they can't be decrypted by
       // the peer.
       connection_->NeuterUnencryptedPackets();
-      if (!FLAGS_quic_unified_timeouts) {
-        connection_->SetOverallConnectionTimeout(QuicTime::Delta::Infinite());
-      }
       if (!FLAGS_quic_allow_more_open_streams) {
         max_open_streams_ = config_.MaxStreamsPerConnection();
       }
diff --git a/net/quic/quic_session.h b/net/quic/quic_session.h
index 6ca9ce0..43f4042 100644
--- a/net/quic/quic_session.h
+++ b/net/quic/quic_session.h
@@ -52,9 +52,7 @@
     HANDSHAKE_CONFIRMED,
   };
 
-  QuicSession(QuicConnection* connection,
-              const QuicConfig& config,
-              bool is_secure);
+  QuicSession(QuicConnection* connection, const QuicConfig& config);
   void InitializeSession();
 
   ~QuicSession() override;
@@ -212,8 +210,8 @@
   bool IsStreamFlowControlBlocked();
 
   // Returns true if this is a secure QUIC session.
-  bool is_secure() const {
-    return is_secure_;
+  bool IsSecure() const {
+    return connection()->is_secure();
   }
 
   size_t get_max_open_streams() const { return max_open_streams_; }
diff --git a/net/quic/quic_session_test.cc b/net/quic/quic_session_test.cc
index edbfbee..d14d875 100644
--- a/net/quic/quic_session_test.cc
+++ b/net/quic/quic_session_test.cc
@@ -125,9 +125,7 @@
 class TestSession : public QuicSession {
  public:
   explicit TestSession(QuicConnection* connection)
-      : QuicSession(connection,
-                    DefaultQuicConfig(),
-                    false),
+      : QuicSession(connection, DefaultQuicConfig()),
         crypto_stream_(this),
         writev_consumes_all_data_(false) {
     InitializeSession();
@@ -580,8 +578,7 @@
 }
 
 TEST_P(QuicSessionTest, IncreasedTimeoutAfterCryptoHandshake) {
-  EXPECT_EQ((FLAGS_quic_unified_timeouts ?
-             kInitialIdleTimeoutSecs : kDefaultIdleTimeoutSecs) + 3,
+  EXPECT_EQ(kInitialIdleTimeoutSecs + 3,
             QuicConnectionPeer::GetNetworkTimeout(connection_).ToSeconds());
   CryptoHandshakeMessage msg;
   session_.GetCryptoStream()->OnHandshakeMessage(msg);
diff --git a/net/quic/quic_stream_factory.cc b/net/quic/quic_stream_factory.cc
index 076797a..32adeda 100644
--- a/net/quic/quic_stream_factory.cc
+++ b/net/quic/quic_stream_factory.cc
@@ -60,16 +60,6 @@
 // The initial receive window size for both streams and sessions.
 const int32 kInitialReceiveWindowSize = 10 * 1024 * 1024;  // 10MB
 
-// The suggested initial congestion windows for a server to use.
-// TODO: This should be tested and optimized, and even better, suggest a window
-// that corresponds to historical bandwidth and min-RTT.
-// Larger initial congestion windows can, if we don't overshoot, reduce latency
-// by avoiding the RTT needed for slow start to double (and re-double) from a
-// default of 10.
-// We match SPDY's use of 32 when secure (since we'd compete with SPDY).
-const int32 kServerSecureInitialCongestionWindow = 32;
-// Be conservative, and just use double a typical TCP  ICWND for HTTP.
-const int32 kServerInecureInitialCongestionWindow = 20;
 // Set the maximum number of undecryptable packets the connection will store.
 const int32 kMaxUndecryptablePackets = 100;
 
@@ -922,15 +912,13 @@
                                                   packet_writer_factory,
                                                   true  /* owns_writer */,
                                                   false  /* is_server */,
+                                                  server_id.is_https(),
                                                   supported_versions_);
   connection->set_max_packet_length(max_packet_length_);
 
   InitializeCachedStateInCryptoConfig(server_id, server_info);
 
   QuicConfig config = config_;
-  config.SetInitialCongestionWindowToSend(
-      server_id.is_https() ? kServerSecureInitialCongestionWindow
-                           : kServerInecureInitialCongestionWindow);
   config.set_max_undecryptable_packets(kMaxUndecryptablePackets);
   config.SetInitialFlowControlWindowToSend(kInitialReceiveWindowSize);
   config.SetInitialStreamFlowControlWindowToSend(kInitialReceiveWindowSize);
@@ -954,7 +942,7 @@
 
   *session = new QuicClientSession(
       connection, socket.Pass(), this, transport_security_state_,
-      server_info.Pass(), config, server_id.is_https(),
+      server_info.Pass(), config,
       base::MessageLoop::current()->message_loop_proxy().get(),
       net_log.net_log());
   all_sessions_[*session] = server_id;  // owning pointer
diff --git a/net/quic/quic_time_wait_list_manager.cc b/net/quic/quic_time_wait_list_manager.cc
index d59cbc4..67d347f 100644
--- a/net/quic/quic_time_wait_list_manager.cc
+++ b/net/quic/quic_time_wait_list_manager.cc
@@ -27,9 +27,8 @@
 
 namespace {
 
-// Time period for which a given connection_id should live in the time-wait
-// state.
-int64 FLAGS_quic_time_wait_list_seconds = 5;
+// Time period for which the connection_id should live in time wait state.
+const int kTimeWaitSeconds = 5;
 
 }  // namespace
 
@@ -40,7 +39,8 @@
  public:
   explicit ConnectionIdCleanUpAlarm(
       QuicTimeWaitListManager* time_wait_list_manager)
-      : time_wait_list_manager_(time_wait_list_manager) {}
+      : time_wait_list_manager_(time_wait_list_manager) {
+  }
 
   QuicTime OnAlarm() override {
     time_wait_list_manager_->CleanUpOldConnectionIds();
@@ -67,7 +67,8 @@
                QuicEncryptedPacket* packet)
       : server_address_(server_address),
         client_address_(client_address),
-        packet_(packet) {}
+        packet_(packet) {
+  }
 
   const IPEndPoint& server_address() const { return server_address_; }
   const IPEndPoint& client_address() const { return client_address_; }
@@ -87,8 +88,7 @@
     QuicConnectionHelperInterface* helper,
     const QuicVersionVector& supported_versions)
     : helper_(helper),
-      kTimeWaitPeriod_(
-          QuicTime::Delta::FromSeconds(FLAGS_quic_time_wait_list_seconds)),
+      kTimeWaitPeriod_(QuicTime::Delta::FromSeconds(kTimeWaitSeconds)),
       connection_id_clean_up_alarm_(
           helper_->CreateAlarm(new ConnectionIdCleanUpAlarm(this))),
       writer_(writer),
@@ -276,7 +276,6 @@
       break;
     }
     // This connection_id has lived its age, retire it now.
-    DVLOG(1) << "Retiring " << it->first << " from the time-wait state.";
     delete it->second.close_packet;
     connection_id_map_.erase(it);
   }
diff --git a/net/quic/test_tools/quic_config_peer.cc b/net/quic/test_tools/quic_config_peer.cc
index 7c84001..d0f5bfd 100644
--- a/net/quic/test_tools/quic_config_peer.cc
+++ b/net/quic/test_tools/quic_config_peer.cc
@@ -10,12 +10,6 @@
 namespace test {
 
 // static
-void QuicConfigPeer::SetReceivedInitialWindow(QuicConfig* config,
-                                              size_t initial_window) {
-  config->initial_congestion_window_.SetReceivedValue(initial_window);
-}
-
-// static
 void QuicConfigPeer::SetReceivedSocketReceiveBuffer(
     QuicConfig* config,
     uint32 receive_buffer_bytes) {
diff --git a/net/quic/test_tools/quic_config_peer.h b/net/quic/test_tools/quic_config_peer.h
index 6c5e237..32e6bff 100644
--- a/net/quic/test_tools/quic_config_peer.h
+++ b/net/quic/test_tools/quic_config_peer.h
@@ -15,9 +15,6 @@
 
 class QuicConfigPeer {
  public:
-  static void SetReceivedInitialWindow(QuicConfig* config,
-                                       size_t initial_window);
-
   static void SetReceivedSocketReceiveBuffer(QuicConfig* config,
                                              uint32 receive_buffer_bytes);
 
diff --git a/net/quic/test_tools/quic_test_utils.cc b/net/quic/test_tools/quic_test_utils.cc
index ae3abfe..13e5eb1 100644
--- a/net/quic/test_tools/quic_test_utils.cc
+++ b/net/quic/test_tools/quic_test_utils.cc
@@ -221,21 +221,10 @@
   clock_.AdvanceTime(delta);
 }
 
-namespace {
-class NiceMockPacketWriterFactory
-    : public QuicConnection::PacketWriterFactory {
- public:
-  NiceMockPacketWriterFactory() {}
-  ~NiceMockPacketWriterFactory() override {}
-
-  QuicPacketWriter* Create(QuicConnection* /*connection*/) const override {
-    return new testing::NiceMock<MockPacketWriter>();
-  }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(NiceMockPacketWriterFactory);
-};
-}  // namespace
+QuicPacketWriter* NiceMockPacketWriterFactory::Create(
+    QuicConnection* /*connection*/) const {
+  return new testing::NiceMock<MockPacketWriter>();
+}
 
 MockConnection::MockConnection(bool is_server)
     : QuicConnection(kTestConnectionId,
@@ -243,7 +232,21 @@
                      new testing::NiceMock<MockHelper>(),
                      NiceMockPacketWriterFactory(),
                      /* owns_writer= */ true,
-                     is_server, QuicSupportedVersions()),
+                     is_server,
+                     /* is_secure= */ false,
+                     QuicSupportedVersions()),
+      helper_(helper()) {
+}
+
+MockConnection::MockConnection(bool is_server, bool is_secure)
+    : QuicConnection(kTestConnectionId,
+                     IPEndPoint(TestPeerIPAddress(), kTestPort),
+                     new testing::NiceMock<MockHelper>(),
+                     NiceMockPacketWriterFactory(),
+                     /* owns_writer= */ true,
+                     is_server,
+                     is_secure,
+                     QuicSupportedVersions()),
       helper_(helper()) {
 }
 
@@ -253,7 +256,9 @@
                      new testing::NiceMock<MockHelper>(),
                      NiceMockPacketWriterFactory(),
                      /* owns_writer= */ true,
-                     is_server, QuicSupportedVersions()),
+                     is_server,
+                     /* is_secure= */ false,
+                     QuicSupportedVersions()),
       helper_(helper()) {
 }
 
@@ -264,7 +269,9 @@
                      new testing::NiceMock<MockHelper>(),
                      NiceMockPacketWriterFactory(),
                      /* owns_writer= */ true,
-                     is_server, QuicSupportedVersions()),
+                     is_server,
+                     /* is_secure= */ false,
+                     QuicSupportedVersions()),
       helper_(helper()) {
 }
 
@@ -275,7 +282,9 @@
                      new testing::NiceMock<MockHelper>(),
                      NiceMockPacketWriterFactory(),
                      /* owns_writer= */ true,
-                     is_server, supported_versions),
+                     is_server,
+                     /* is_secure= */ false,
+                     supported_versions),
       helper_(helper()) {
 }
 
@@ -316,7 +325,7 @@
 }
 
 MockSession::MockSession(QuicConnection* connection)
-    : QuicSession(connection, DefaultQuicConfig(), /*is_secure=*/false) {
+    : QuicSession(connection, DefaultQuicConfig()) {
   InitializeSession();
   ON_CALL(*this, WritevData(_, _, _, _, _, _))
       .WillByDefault(testing::Return(QuicConsumedData(0, false)));
@@ -326,7 +335,7 @@
 }
 
 TestSession::TestSession(QuicConnection* connection, const QuicConfig& config)
-    : QuicSession(connection, config, /*is_secure=*/false),
+    : QuicSession(connection, config),
       crypto_stream_(nullptr) {
   InitializeSession();
 }
@@ -343,7 +352,7 @@
 
 TestClientSession::TestClientSession(QuicConnection* connection,
                                      const QuicConfig& config)
-    : QuicClientSessionBase(connection, config, /*is_secure=*/false),
+    : QuicClientSessionBase(connection, config),
       crypto_stream_(nullptr) {
   EXPECT_CALL(*this, OnProofValid(_)).Times(AnyNumber());
   InitializeSession();
diff --git a/net/quic/test_tools/quic_test_utils.h b/net/quic/test_tools/quic_test_utils.h
index ea5e5ef..fa987de 100644
--- a/net/quic/test_tools/quic_test_utils.h
+++ b/net/quic/test_tools/quic_test_utils.h
@@ -265,11 +265,25 @@
   DISALLOW_COPY_AND_ASSIGN(MockHelper);
 };
 
+class NiceMockPacketWriterFactory : public QuicConnection::PacketWriterFactory {
+ public:
+  NiceMockPacketWriterFactory() {}
+  ~NiceMockPacketWriterFactory() override {}
+
+  QuicPacketWriter* Create(QuicConnection* /*connection*/) const override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(NiceMockPacketWriterFactory);
+};
+
 class MockConnection : public QuicConnection {
  public:
   // Uses a MockHelper, ConnectionId of 42, and 127.0.0.1:123.
   explicit MockConnection(bool is_server);
 
+  // Uses a MockHelper, ConnectionId of 42, and 127.0.0.1:123.
+  MockConnection(bool is_server, bool is_secure);
+
   // Uses a MockHelper, ConnectionId of 42.
   MockConnection(IPEndPoint address, bool is_server);
 
@@ -437,7 +451,9 @@
   MockSendAlgorithm();
   virtual ~MockSendAlgorithm();
 
-  MOCK_METHOD2(SetFromConfig, void(const QuicConfig& config, bool is_server));
+  MOCK_METHOD3(SetFromConfig, void(const QuicConfig& config,
+                                   bool is_server,
+                                   bool using_pacing));
   MOCK_METHOD1(SetNumEmulatedConnections, void(int num_connections));
   MOCK_METHOD1(SetMaxPacketSize, void(QuicByteCount max_packet_size));
   MOCK_METHOD2(OnIncomingQuicCongestionFeedbackFrame,
diff --git a/net/socket/tcp_socket_libevent.cc b/net/socket/tcp_socket_libevent.cc
index cc23765..d7fa9fa 100644
--- a/net/socket/tcp_socket_libevent.cc
+++ b/net/socket/tcp_socket_libevent.cc
@@ -21,6 +21,7 @@
 #include "net/base/ip_endpoint.h"
 #include "net/base/net_errors.h"
 #include "net/base/net_util.h"
+#include "net/base/network_activity_monitor.h"
 #include "net/base/network_change_notifier.h"
 #include "net/socket/socket_libevent.h"
 #include "net/socket/socket_net_log_params.h"
@@ -601,6 +602,8 @@
   read_bytes.Add(rv);
   net_log_.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_RECEIVED, rv,
                                 buf->data());
+  NetworkActivityMonitor::GetInstance()->IncrementBytesReceived(rv);
+
   return rv;
 }
 
@@ -633,6 +636,7 @@
   write_bytes.Add(rv);
   net_log_.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_SENT, rv,
                                 buf->data());
+  NetworkActivityMonitor::GetInstance()->IncrementBytesSent(rv);
   return rv;
 }
 
diff --git a/net/socket/tcp_socket_win.cc b/net/socket/tcp_socket_win.cc
index fd3c8b7..0c3d26f 100644
--- a/net/socket/tcp_socket_win.cc
+++ b/net/socket/tcp_socket_win.cc
@@ -18,6 +18,7 @@
 #include "net/base/ip_endpoint.h"
 #include "net/base/net_errors.h"
 #include "net/base/net_util.h"
+#include "net/base/network_activity_monitor.h"
 #include "net/base/network_change_notifier.h"
 #include "net/base/winsock_init.h"
 #include "net/base/winsock_util.h"
@@ -545,6 +546,7 @@
       write_bytes.Add(rv);
       net_log_.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_SENT, rv,
                                     buf->data());
+      NetworkActivityMonitor::GetInstance()->IncrementBytesSent(rv);
       return rv;
     }
   } else {
@@ -913,6 +915,7 @@
       read_bytes.Add(rv);
     net_log_.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_RECEIVED, rv,
                                   buf->data());
+    NetworkActivityMonitor::GetInstance()->IncrementBytesReceived(rv);
     return rv;
   }
 
@@ -982,6 +985,7 @@
       write_bytes.Add(num_bytes);
       net_log_.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_SENT, num_bytes,
                                     core_->write_iobuffer_->data());
+      NetworkActivityMonitor::GetInstance()->IncrementBytesSent(num_bytes);
     }
   }
 
diff --git a/net/tools/quic/end_to_end_test.cc b/net/tools/quic/end_to_end_test.cc
index 1fb3e79..33f30fc 100644
--- a/net/tools/quic/end_to_end_test.cc
+++ b/net/tools/quic/end_to_end_test.cc
@@ -920,11 +920,10 @@
   EXPECT_EQ(2u, client_negotiated_config->MaxStreamsPerConnection());
 }
 
-TEST_P(EndToEndTest, LimitCongestionWindowAndRTT) {
-  // Client tries to request twice the server's max initial window, and the
-  // server limits it to the max.
-  client_config_.SetInitialCongestionWindowToSend(2 * kMaxInitialWindow);
-  client_config_.SetInitialRoundTripTimeUsToSend(20000);
+TEST_P(EndToEndTest, ClientSuggestsRTT) {
+  // Client suggests initial RTT, verify it is used.
+  const uint32 kInitialRTT = 20000;
+  client_config_.SetInitialRoundTripTimeUsToSend(kInitialRTT);
 
   ASSERT_TRUE(Initialize());
   client_->client()->WaitForCryptoHandshakeConfirmed();
@@ -940,33 +939,21 @@
   const QuicSentPacketManager& server_sent_packet_manager =
       *GetSentPacketManagerFromFirstServerSession();
 
-  // The client shouldn't set its initial window based on the negotiated value.
-  EXPECT_EQ(kDefaultInitialWindow,
-            client_sent_packet_manager.GetCongestionWindowInTcpMss());
-  EXPECT_EQ(kMaxInitialWindow,
-            server_sent_packet_manager.GetCongestionWindowInTcpMss());
+  // BBR automatically enables pacing.
+  EXPECT_EQ(GetParam().use_pacing ||
+            (FLAGS_quic_allow_bbr &&
+             GetParam().congestion_control_tag == kTBBR),
+            server_sent_packet_manager.using_pacing());
+  EXPECT_EQ(GetParam().use_pacing ||
+            (FLAGS_quic_allow_bbr &&
+             GetParam().congestion_control_tag == kTBBR),
+            client_sent_packet_manager.using_pacing());
 
-  EXPECT_EQ(GetParam().use_pacing, server_sent_packet_manager.using_pacing());
-  EXPECT_EQ(GetParam().use_pacing, client_sent_packet_manager.using_pacing());
-
-  // The client *should* set the intitial RTT, but it's increased to 10ms.
-  EXPECT_EQ(20000u, client_sent_packet_manager.GetRttStats()->initial_rtt_us());
-  EXPECT_EQ(20000u, server_sent_packet_manager.GetRttStats()->initial_rtt_us());
-
-  // Now use the negotiated limits with packet loss.
-  SetPacketLossPercentage(30);
-
-  // 10 KB body.
-  string body;
-  GenerateBody(&body, 1024 * 10);
-
-  HTTPMessage request(HttpConstants::HTTP_1_1,
-                      HttpConstants::POST, "/foo");
-  request.AddBody(body, true);
-
+  EXPECT_EQ(kInitialRTT,
+            client_sent_packet_manager.GetRttStats()->initial_rtt_us());
+  EXPECT_EQ(kInitialRTT,
+            server_sent_packet_manager.GetRttStats()->initial_rtt_us());
   server_thread_->Resume();
-
-  EXPECT_EQ(kFooResponseBody, client_->SendCustomSynchronousRequest(request));
 }
 
 TEST_P(EndToEndTest, MaxInitialRTT) {
@@ -1025,7 +1012,7 @@
   EXPECT_FALSE(
       client_sent_packet_manager.GetRttStats()->smoothed_rtt().IsInfinite());
   // Expect the default rtt of 100ms.
-  EXPECT_EQ(static_cast<int64>(100 * base::Time::kMicrosecondsPerMillisecond),
+  EXPECT_EQ(static_cast<int64>(100 * kNumMicrosPerMilli),
             server_sent_packet_manager.GetRttStats()->initial_rtt_us());
   // Ensure the bandwidth is valid.
   client_sent_packet_manager.BandwidthEstimate();
diff --git a/net/tools/quic/quic_client.cc b/net/tools/quic/quic_client.cc
index b28ec2b..74874d7 100644
--- a/net/tools/quic/quic_client.cc
+++ b/net/tools/quic/quic_client.cc
@@ -199,8 +199,8 @@
                          factory,
                          /* owns_writer= */ false,
                          /* is_server= */ false,
-                         supported_versions_),
-      server_id_.is_https()));
+                         server_id_.is_https(),
+                         supported_versions_)));
 
   // Reset |writer_| after |session_| so that the old writer outlives the old
   // session.
diff --git a/net/tools/quic/quic_client_session.cc b/net/tools/quic/quic_client_session.cc
index 87ca0ce..235eeb0 100644
--- a/net/tools/quic/quic_client_session.cc
+++ b/net/tools/quic/quic_client_session.cc
@@ -15,9 +15,8 @@
 namespace tools {
 
 QuicClientSession::QuicClientSession(const QuicConfig& config,
-                                     QuicConnection* connection,
-                                     bool is_secure)
-    : QuicClientSessionBase(connection, config, is_secure) {
+                                     QuicConnection* connection)
+    : QuicClientSessionBase(connection, config) {
 }
 
 QuicClientSession::~QuicClientSession() {
@@ -26,18 +25,16 @@
 void QuicClientSession::InitializeSession(
     const QuicServerId& server_id,
     QuicCryptoClientConfig* crypto_config) {
-  QuicClientSessionBase::InitializeSession();
   crypto_stream_.reset(
       new QuicCryptoClientStream(server_id, this, nullptr, crypto_config));
+  QuicClientSessionBase::InitializeSession();
 }
 
 void QuicClientSession::OnProofValid(
-    const QuicCryptoClientConfig::CachedState& /*cached*/) {
-}
+    const QuicCryptoClientConfig::CachedState& /*cached*/) {}
 
 void QuicClientSession::OnProofVerifyDetailsAvailable(
-    const ProofVerifyDetails& /*verify_details*/) {
-}
+    const ProofVerifyDetails& /*verify_details*/) {}
 
 QuicSpdyClientStream* QuicClientSession::CreateOutgoingDataStream() {
   if (!crypto_stream_->encryption_established()) {
diff --git a/net/tools/quic/quic_client_session.h b/net/tools/quic/quic_client_session.h
index d1cd38c..3c92efa 100644
--- a/net/tools/quic/quic_client_session.h
+++ b/net/tools/quic/quic_client_session.h
@@ -25,9 +25,7 @@
 
 class QuicClientSession : public QuicClientSessionBase {
  public:
-  QuicClientSession(const QuicConfig& config,
-                    QuicConnection* connection,
-                    bool is_secure);
+  QuicClientSession(const QuicConfig& config, QuicConnection* connection);
   ~QuicClientSession() override;
 
   void InitializeSession(const QuicServerId& server_id,
diff --git a/net/tools/quic/quic_client_session_test.cc b/net/tools/quic/quic_client_session_test.cc
index 61422e1..5b5c415 100644
--- a/net/tools/quic/quic_client_session_test.cc
+++ b/net/tools/quic/quic_client_session_test.cc
@@ -42,8 +42,7 @@
   ToolsQuicClientSessionTest()
       : connection_(
             new PacketSavingConnection(false, SupportedVersions(GetParam()))) {
-    session_.reset(new QuicClientSession(DefaultQuicConfig(), connection_,
-                                         /*is_secure=*/false));
+    session_.reset(new QuicClientSession(DefaultQuicConfig(), connection_));
     session_->InitializeSession(
         QuicServerId(kServerHostname, kPort, false, PRIVACY_MODE_DISABLED),
         &crypto_config_);
diff --git a/net/tools/quic/quic_dispatcher.cc b/net/tools/quic/quic_dispatcher.cc
index 16cee2b..4ea48e9 100644
--- a/net/tools/quic/quic_dispatcher.cc
+++ b/net/tools/quic/quic_dispatcher.cc
@@ -364,8 +364,7 @@
   QuicServerSession* session = new QuicServerSession(
       config_,
       CreateQuicConnection(connection_id, server_address, client_address),
-      this,
-      crypto_config_.HasProofSource());
+      this);
   session->InitializeSession(crypto_config_);
   return session;
 }
@@ -380,6 +379,7 @@
                             connection_writer_factory_,
                             /* owns_writer= */ true,
                             /* is_server= */ true,
+                            crypto_config_.HasProofSource(),
                             supported_versions_);
 }
 
diff --git a/net/tools/quic/quic_server_session.cc b/net/tools/quic/quic_server_session.cc
index 1dd5748..45c1379 100644
--- a/net/tools/quic/quic_server_session.cc
+++ b/net/tools/quic/quic_server_session.cc
@@ -5,7 +5,7 @@
 #include "net/tools/quic/quic_server_session.h"
 
 #include "base/logging.h"
-#include "net/quic/crypto/source_address_token.h"
+#include "net/quic/crypto/cached_network_parameters.h"
 #include "net/quic/quic_connection.h"
 #include "net/quic/quic_flags.h"
 #include "net/quic/reliable_quic_stream.h"
@@ -16,9 +16,8 @@
 
 QuicServerSession::QuicServerSession(const QuicConfig& config,
                                      QuicConnection* connection,
-                                     QuicServerSessionVisitor* visitor,
-                                     bool is_secure)
-    : QuicSession(connection, config, is_secure),
+                                     QuicServerSessionVisitor* visitor)
+    : QuicSession(connection, config),
       visitor_(visitor),
       bandwidth_estimate_sent_to_client_(QuicBandwidth::Zero()),
       last_scup_time_(QuicTime::Zero()),
diff --git a/net/tools/quic/quic_server_session.h b/net/tools/quic/quic_server_session.h
index cdc2bf3..603ad35 100644
--- a/net/tools/quic/quic_server_session.h
+++ b/net/tools/quic/quic_server_session.h
@@ -47,8 +47,7 @@
  public:
   QuicServerSession(const QuicConfig& config,
                     QuicConnection* connection,
-                    QuicServerSessionVisitor* visitor,
-                    bool is_secure);
+                    QuicServerSessionVisitor* visitor);
 
   // Override the base class to notify the owner of the connection close.
   void OnConnectionClosed(QuicErrorCode error, bool from_peer) override;
diff --git a/net/tools/quic/quic_server_session_test.cc b/net/tools/quic/quic_server_session_test.cc
index 202022f..6a17f53 100644
--- a/net/tools/quic/quic_server_session_test.cc
+++ b/net/tools/quic/quic_server_session_test.cc
@@ -4,9 +4,9 @@
 
 #include "net/tools/quic/quic_server_session.h"
 
+#include "net/quic/crypto/cached_network_parameters.h"
 #include "net/quic/crypto/quic_crypto_server_config.h"
 #include "net/quic/crypto/quic_random.h"
-#include "net/quic/crypto/source_address_token.h"
 #include "net/quic/quic_connection.h"
 #include "net/quic/quic_crypto_server_stream.h"
 #include "net/quic/quic_flags.h"
@@ -79,8 +79,7 @@
 
     connection_ =
         new StrictMock<MockConnection>(true, SupportedVersions(GetParam()));
-    session_.reset(new QuicServerSession(config_, connection_, &owner_,
-                                         /*is_secure=*/false));
+    session_.reset(new QuicServerSession(config_, connection_, &owner_));
     MockClock clock;
     handshake_message_.reset(crypto_config_.AddDefaultConfig(
         QuicRandom::GetInstance(), &clock,
diff --git a/net/tools/quic/quic_spdy_client_stream_test.cc b/net/tools/quic/quic_spdy_client_stream_test.cc
index d2106d9..090e2da 100644
--- a/net/tools/quic/quic_spdy_client_stream_test.cc
+++ b/net/tools/quic/quic_spdy_client_stream_test.cc
@@ -29,7 +29,7 @@
   QuicSpdyClientStreamTest()
       : connection_(new StrictMock<MockConnection>(
             false, SupportedVersions(GetParam()))),
-        session_(DefaultQuicConfig(), connection_, /*is_secure=*/false),
+        session_(DefaultQuicConfig(), connection_),
         body_("hello world") {
     session_.InitializeSession(
         QuicServerId("example.com", 80, false, PRIVACY_MODE_DISABLED),
diff --git a/net/tools/quic/quic_time_wait_list_manager.cc b/net/tools/quic/quic_time_wait_list_manager.cc
index 58f50fe..f54a465 100644
--- a/net/tools/quic/quic_time_wait_list_manager.cc
+++ b/net/tools/quic/quic_time_wait_list_manager.cc
@@ -28,9 +28,8 @@
 
 namespace {
 
-// Time period for which a given connection_id should live in the time-wait
-// state.
-int64 FLAGS_quic_time_wait_list_seconds = 5;
+// Time period for which the connection_id should live in time wait state.
+const int kTimeWaitSeconds = 5;
 
 }  // namespace
 
@@ -91,8 +90,7 @@
     EpollServer* epoll_server,
     const QuicVersionVector& supported_versions)
     : epoll_server_(epoll_server),
-      kTimeWaitPeriod_(
-          QuicTime::Delta::FromSeconds(FLAGS_quic_time_wait_list_seconds)),
+      kTimeWaitPeriod_(QuicTime::Delta::FromSeconds(kTimeWaitSeconds)),
       connection_id_clean_up_alarm_(new ConnectionIdCleanUpAlarm(this)),
       clock_(epoll_server_),
       writer_(writer),
@@ -122,7 +120,9 @@
     delete it->second.close_packet;
     connection_id_map_.erase(it);
   }
-  ConnectionIdData data(num_packets, version, clock_.ApproximateNow(),
+  ConnectionIdData data(num_packets,
+                        version,
+                        clock_.ApproximateNow(),
                         close_packet);
   connection_id_map_.insert(make_pair(connection_id, data));
 }
@@ -168,12 +168,12 @@
     return;
   }
   if (it->second.close_packet) {
-     QueuedPacket* queued_packet =
-         new QueuedPacket(server_address,
-                          client_address,
-                          it->second.close_packet->Clone());
-     // Takes ownership of the packet.
-     SendOrQueuePacket(queued_packet);
+    QueuedPacket* queued_packet =
+        new QueuedPacket(server_address,
+                         client_address,
+                         it->second.close_packet->Clone());
+    // Takes ownership of the packet.
+    SendOrQueuePacket(queued_packet);
   } else {
     SendPublicReset(server_address,
                     client_address,
@@ -282,7 +282,6 @@
       break;
     }
     // This connection_id has lived its age, retire it now.
-    DVLOG(1) << "Retiring " << it->first << " from the time-wait state.";
     delete it->second.close_packet;
     connection_id_map_.erase(it);
   }
diff --git a/net/tools/quic/test_tools/quic_test_utils.cc b/net/tools/quic/test_tools/quic_test_utils.cc
index 40b7e88..91cd003 100644
--- a/net/tools/quic/test_tools/quic_test_utils.cc
+++ b/net/tools/quic/test_tools/quic_test_utils.cc
@@ -18,21 +18,10 @@
 namespace tools {
 namespace test {
 
-namespace {
-class NiceMockPacketWriterFactory
-    : public QuicConnection::PacketWriterFactory {
- public:
-  NiceMockPacketWriterFactory() {}
-  ~NiceMockPacketWriterFactory() override {}
-
-  QuicPacketWriter* Create(QuicConnection* /*connection*/) const override {
-    return new testing::NiceMock<MockPacketWriter>();
-  }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(NiceMockPacketWriterFactory);
-};
-}  // namespace
+QuicPacketWriter* NiceMockPacketWriterFactory::Create(
+    QuicConnection* /*connection*/) const {
+  return new testing::NiceMock<MockPacketWriter>();
+}
 
 MockConnection::MockConnection(bool is_server)
     : QuicConnection(kTestConnectionId,
@@ -40,7 +29,21 @@
                      new testing::NiceMock<MockHelper>(),
                      NiceMockPacketWriterFactory(),
                      /* owns_writer= */ true,
-                     is_server, QuicSupportedVersions()),
+                     is_server,
+                     /* is_secure= */ false,
+                     QuicSupportedVersions()),
+      helper_(helper()) {
+}
+
+MockConnection::MockConnection(bool is_server, bool is_secure)
+    : QuicConnection(kTestConnectionId,
+                     IPEndPoint(net::test::Loopback4(), kTestPort),
+                     new testing::NiceMock<MockHelper>(),
+                     NiceMockPacketWriterFactory(),
+                     /* owns_writer= */ true,
+                     is_server,
+                     is_secure,
+                     QuicSupportedVersions()),
       helper_(helper()) {
 }
 
@@ -50,7 +53,9 @@
                      new testing::NiceMock<MockHelper>(),
                      NiceMockPacketWriterFactory(),
                      /* owns_writer= */ true,
-                     is_server, QuicSupportedVersions()),
+                     is_server,
+                     /* is_secure= */ false,
+                     QuicSupportedVersions()),
       helper_(helper()) {
 }
 
@@ -61,7 +66,9 @@
                      new testing::NiceMock<MockHelper>(),
                      NiceMockPacketWriterFactory(),
                      /* owns_writer= */ true,
-                     is_server, QuicSupportedVersions()),
+                     is_server,
+                     /* is_secure= */ false,
+                     QuicSupportedVersions()),
       helper_(helper()) {
 }
 
@@ -72,7 +79,9 @@
                      new testing::NiceMock<MockHelper>(),
                      NiceMockPacketWriterFactory(),
                      /* owns_writer= */ true,
-                     is_server, QuicSupportedVersions()),
+                     is_server,
+                     /* is_secure= */ false,
+                     supported_versions),
       helper_(helper()) {
 }
 
@@ -93,9 +102,8 @@
   return ack;
 }
 
-TestSession::TestSession(QuicConnection* connection,
-                         const QuicConfig& config)
-    : QuicSession(connection, config, /*is_secure=*/false),
+TestSession::TestSession(QuicConnection* connection, const QuicConfig& config)
+    : QuicSession(connection, config),
       crypto_stream_(nullptr) {
   InitializeSession();
 }
diff --git a/net/tools/quic/test_tools/quic_test_utils.h b/net/tools/quic/test_tools/quic_test_utils.h
index cbd7fbe..9db9fb5 100644
--- a/net/tools/quic/test_tools/quic_test_utils.h
+++ b/net/tools/quic/test_tools/quic_test_utils.h
@@ -39,11 +39,25 @@
 QuicAckFrame MakeAckFrameWithNackRanges(size_t num_nack_ranges,
                                         QuicPacketSequenceNumber least_unacked);
 
+class NiceMockPacketWriterFactory : public QuicConnection::PacketWriterFactory {
+ public:
+  NiceMockPacketWriterFactory() {}
+  ~NiceMockPacketWriterFactory() override {}
+
+  QuicPacketWriter* Create(QuicConnection* /*connection*/) const override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(NiceMockPacketWriterFactory);
+};
+
 class MockConnection : public QuicConnection {
  public:
   // Uses a MockHelper, ConnectionId of 42, and 127.0.0.1:123.
   explicit MockConnection(bool is_server);
 
+  // Uses a MockHelper, ConnectionId of 42, and 127.0.0.1:123.
+  MockConnection(bool is_server, bool is_secure);
+
   // Uses a MockHelper, ConnectionId of 42.
   MockConnection(IPEndPoint address, bool is_server);
 
@@ -83,10 +97,12 @@
   void ReallyProcessUdpPacket(const IPEndPoint& self_address,
                               const IPEndPoint& peer_address,
                               const QuicEncryptedPacket& packet) {
-    return QuicConnection::ProcessUdpPacket(self_address, peer_address, packet);
+    QuicConnection::ProcessUdpPacket(self_address, peer_address, packet);
   }
 
-  virtual bool OnProtocolVersionMismatch(QuicVersion version) { return false; }
+  virtual bool OnProtocolVersionMismatch(QuicVersion version) override {
+    return false;
+  }
 
  private:
   scoped_ptr<QuicConnectionHelperInterface> helper_;
diff --git a/net/udp/udp_socket_libevent.cc b/net/udp/udp_socket_libevent.cc
index 9b1a995..2dffff3 100644
--- a/net/udp/udp_socket_libevent.cc
+++ b/net/udp/udp_socket_libevent.cc
@@ -24,6 +24,7 @@
 #include "net/base/net_errors.h"
 #include "net/base/net_log.h"
 #include "net/base/net_util.h"
+#include "net/base/network_activity_monitor.h"
 #include "net/socket/socket_descriptor.h"
 #include "net/udp/udp_net_log_parameters.h"
 
@@ -414,6 +415,7 @@
 
   base::StatsCounter read_bytes("udp.read_bytes");
   read_bytes.Add(result);
+  NetworkActivityMonitor::GetInstance()->IncrementBytesReceived(result);
 }
 
 int UDPSocketLibevent::CreateSocket(int addr_family) {
@@ -458,6 +460,7 @@
 
   base::StatsCounter write_bytes("udp.write_bytes");
   write_bytes.Add(result);
+  NetworkActivityMonitor::GetInstance()->IncrementBytesSent(result);
 }
 
 int UDPSocketLibevent::InternalRecvFrom(IOBuffer* buf, int buf_len,
diff --git a/net/udp/udp_socket_win.cc b/net/udp/udp_socket_win.cc
index 4c307fd..11c731f 100644
--- a/net/udp/udp_socket_win.cc
+++ b/net/udp/udp_socket_win.cc
@@ -20,6 +20,7 @@
 #include "net/base/net_errors.h"
 #include "net/base/net_log.h"
 #include "net/base/net_util.h"
+#include "net/base/network_activity_monitor.h"
 #include "net/base/winsock_init.h"
 #include "net/base/winsock_util.h"
 #include "net/socket/socket_descriptor.h"
@@ -595,6 +596,7 @@
 
   base::StatsCounter read_bytes("udp.read_bytes");
   read_bytes.Add(result);
+  NetworkActivityMonitor::GetInstance()->IncrementBytesReceived(result);
 }
 
 void UDPSocketWin::DidCompleteWrite() {
@@ -626,6 +628,7 @@
 
   base::StatsCounter write_bytes("udp.write_bytes");
   write_bytes.Add(result);
+  NetworkActivityMonitor::GetInstance()->IncrementBytesSent(result);
 }
 
 int UDPSocketWin::InternalRecvFrom(IOBuffer* buf, int buf_len,
diff --git a/net/url_request/sdch_dictionary_fetcher.cc b/net/url_request/sdch_dictionary_fetcher.cc
index 5806193..5ac65ef 100644
--- a/net/url_request/sdch_dictionary_fetcher.cc
+++ b/net/url_request/sdch_dictionary_fetcher.cc
@@ -11,6 +11,7 @@
 #include "base/compiler_specific.h"
 #include "base/thread_task_runner_handle.h"
 #include "net/base/load_flags.h"
+#include "net/base/sdch_net_log_params.h"
 #include "net/url_request/url_request_context.h"
 #include "net/url_request/url_request_status.h"
 #include "net/url_request/url_request_throttler_manager.h"
@@ -45,16 +46,15 @@
   // Avoid pushing duplicate copy onto queue. We may fetch this url again later
   // and get a different dictionary, but there is no reason to have it in the
   // queue twice at one time.
-  if (!fetch_queue_.empty() && fetch_queue_.back() == dictionary_url) {
+  if ((!fetch_queue_.empty() && fetch_queue_.back() == dictionary_url) ||
+      attempted_load_.find(dictionary_url) != attempted_load_.end()) {
+    // TODO(rdsmith): log this error to the net log of the URLRequest
+    // initiating this fetch, once URLRequest will be passed here.
     SdchManager::SdchErrorRecovery(
-        SdchManager::DICTIONARY_ALREADY_SCHEDULED_TO_DOWNLOAD);
+        SDCH_DICTIONARY_PREVIOUSLY_SCHEDULED_TO_DOWNLOAD);
     return;
   }
-  if (attempted_load_.find(dictionary_url) != attempted_load_.end()) {
-    SdchManager::SdchErrorRecovery(
-        SdchManager::DICTIONARY_ALREADY_TRIED_TO_DOWNLOAD);
-    return;
-  }
+
   attempted_load_.insert(dictionary_url);
   fetch_queue_.push(dictionary_url);
 
@@ -166,6 +166,7 @@
 
   next_state_ = STATE_REQUEST_STARTED;
   current_request_->Start();
+  current_request_->net_log().AddEvent(NetLog::TYPE_SDCH_DICTIONARY_FETCH);
 
   return OK;
 }
@@ -207,7 +208,12 @@
       // an infinite loop.  It's not clear how to handle a read failure
       // without a promise to invoke the callback at some point in the future,
       // so the request is failed.
-      SdchManager::SdchErrorRecovery(SdchManager::DICTIONARY_FETCH_READ_FAILED);
+      SdchManager::SdchErrorRecovery(SDCH_DICTIONARY_FETCH_READ_FAILED);
+      current_request_->net_log().AddEvent(
+          NetLog::TYPE_SDCH_DICTIONARY_ERROR,
+          base::Bind(&NetLogSdchDictionaryFetchProblemCallback,
+                     SDCH_DICTIONARY_FETCH_READ_FAILED, current_request_->url(),
+                     true));
       DLOG(FATAL)
           << "URLRequest::Read() returned false without IO pending or error!";
       return ERR_FAILED;
@@ -228,8 +234,10 @@
   DCHECK(CalledOnValidThread());
 
   // If the dictionary was successfully fetched, add it to the manager.
-  if (rv == OK)
-    dictionary_fetched_callback_.Run(dictionary_, current_request_->url());
+  if (rv == OK) {
+    dictionary_fetched_callback_.Run(dictionary_, current_request_->url(),
+                                     current_request_->net_log());
+  }
 
   current_request_.reset();
   buffer_ = NULL;
diff --git a/net/url_request/sdch_dictionary_fetcher.h b/net/url_request/sdch_dictionary_fetcher.h
index 5b6f269..79d8778 100644
--- a/net/url_request/sdch_dictionary_fetcher.h
+++ b/net/url_request/sdch_dictionary_fetcher.h
@@ -36,7 +36,8 @@
                                          public base::NonThreadSafe {
  public:
   typedef base::Callback<void(const std::string& dictionary_text,
-                              const GURL& dictionary_url)>
+                              const GURL& dictionary_url,
+                              const BoundNetLog& net_log)>
       OnDictionaryFetchedCallback;
 
   // The consumer must guarantee that |*context| outlives this object.
diff --git a/net/url_request/sdch_dictionary_fetcher_unittest.cc b/net/url_request/sdch_dictionary_fetcher_unittest.cc
index 0febd7e..ae76cbc 100644
--- a/net/url_request/sdch_dictionary_fetcher_unittest.cc
+++ b/net/url_request/sdch_dictionary_fetcher_unittest.cc
@@ -99,7 +99,8 @@
   }
 
   void OnDictionaryFetched(const std::string& dictionary_text,
-                           const GURL& dictionary_url) {
+                           const GURL& dictionary_url,
+                           const BoundNetLog& net_log) {
     dictionary_additions.push_back(
         DictionaryAdditions(dictionary_text, dictionary_url));
   }
diff --git a/net/url_request/test_url_fetcher_factory.cc b/net/url_request/test_url_fetcher_factory.cc
index af76576..357dfeb 100644
--- a/net/url_request/test_url_fetcher_factory.cc
+++ b/net/url_request/test_url_fetcher_factory.cc
@@ -48,6 +48,7 @@
       fake_response_destination_(STRING),
       fake_was_fetched_via_proxy_(false),
       fake_max_retries_(0) {
+  CHECK(original_url_.is_valid());
 }
 
 TestURLFetcher::~TestURLFetcher() {
diff --git a/net/url_request/url_request_context_builder.cc b/net/url_request/url_request_context_builder.cc
index 04c190c..41420d5 100644
--- a/net/url_request/url_request_context_builder.cc
+++ b/net/url_request/url_request_context_builder.cc
@@ -214,7 +214,8 @@
       ftp_enabled_(false),
 #endif
       http_cache_enabled_(true),
-      throttling_enabled_(false) {
+      throttling_enabled_(false),
+      channel_id_enabled_(true) {
 }
 
 URLRequestContextBuilder::~URLRequestContextBuilder() {}
@@ -296,12 +297,14 @@
   storage->set_http_auth_handler_factory(http_auth_handler_registry_factory);
   storage->set_cookie_store(new CookieMonster(NULL, NULL));
 
-  // TODO(mmenke):  This always creates a file thread, even when it ends up
-  // not being used.  Consider lazily creating the thread.
-  storage->set_channel_id_service(
-      new ChannelIDService(
-          new DefaultChannelIDStore(NULL),
-          context->GetFileThread()->message_loop_proxy()));
+  if (channel_id_enabled_) {
+    // TODO(mmenke):  This always creates a file thread, even when it ends up
+    // not being used.  Consider lazily creating the thread.
+    storage->set_channel_id_service(
+        new ChannelIDService(
+            new DefaultChannelIDStore(NULL),
+            context->GetFileThread()->message_loop_proxy()));
+  }
 
   storage->set_transport_security_state(new net::TransportSecurityState());
   if (!transport_security_persister_path_.empty()) {
diff --git a/net/url_request/url_request_context_builder.h b/net/url_request/url_request_context_builder.h
index a7d9d7b..f26552a 100644
--- a/net/url_request/url_request_context_builder.h
+++ b/net/url_request/url_request_context_builder.h
@@ -174,6 +174,10 @@
     throttling_enabled_ = throttling_enabled;
   }
 
+  void set_channel_id_enabled(bool enable) {
+    channel_id_enabled_ = enable;
+  }
+
   URLRequestContext* Build();
 
  private:
@@ -200,6 +204,7 @@
 #endif
   bool http_cache_enabled_;
   bool throttling_enabled_;
+  bool channel_id_enabled_;
 
   HttpCacheParams http_cache_params_;
   HttpNetworkSessionParams http_network_session_params_;
diff --git a/net/url_request/url_request_http_job.cc b/net/url_request/url_request_http_job.cc
index 4261b92..33a5088 100644
--- a/net/url_request/url_request_http_job.cc
+++ b/net/url_request/url_request_http_job.cc
@@ -24,6 +24,7 @@
 #include "net/base/net_util.h"
 #include "net/base/network_delegate.h"
 #include "net/base/sdch_manager.h"
+#include "net/base/sdch_net_log_params.h"
 #include "net/cert/cert_status_flags.h"
 #include "net/cookies/cookie_store.h"
 #include "net/http/http_content_disposition.h"
@@ -70,6 +71,7 @@
   int GetResponseCode() const override;
   const URLRequestContext* GetURLRequestContext() const override;
   void RecordPacketStats(StatisticSelector statistic) const override;
+  const BoundNetLog& GetNetLog() const override;
 
   // Method to allow us to reset filter context for a response that should have
   // been SDCH encoded when there is an update due to an explicit HTTP header.
@@ -78,6 +80,10 @@
  private:
   URLRequestHttpJob* job_;
 
+  // URLRequestHttpJob may be detached from URLRequest, but we still need to
+  // return something.
+  BoundNetLog dummy_log_;
+
   DISALLOW_COPY_AND_ASSIGN(HttpFilterContext);
 };
 
@@ -147,6 +153,10 @@
   job_->RecordPacketStats(statistic);
 }
 
+const BoundNetLog& URLRequestHttpJob::HttpFilterContext::GetNetLog() const {
+  return job_->request() ? job_->request()->net_log() : dummy_log_;
+}
+
 // TODO(darin): make sure the port blocking code is not lost
 // static
 URLRequestJob* URLRequestHttpJob::Factory(URLRequest* request,
@@ -321,21 +331,42 @@
   ProcessPublicKeyPinsHeader();
 
   SdchManager* sdch_manager(request()->context()->sdch_manager());
-  if (sdch_manager && sdch_manager->IsInSupportedDomain(request_->url())) {
-    const std::string name = "Get-Dictionary";
-    std::string url_text;
-    void* iter = NULL;
-    // TODO(jar): We need to not fetch dictionaries the first time they are
-    // seen, but rather wait until we can justify their usefulness.
-    // For now, we will only fetch the first dictionary, which will at least
-    // require multiple suggestions before we get additional ones for this site.
-    // Eventually we should wait until a dictionary is requested several times
-    // before we even download it (so that we don't waste memory or bandwidth).
-    if (GetResponseHeaders()->EnumerateHeader(&iter, name, &url_text)) {
-      // Resolve suggested URL relative to request url.
-      GURL sdch_dictionary_url = request_->url().Resolve(url_text);
-      if (sdch_dictionary_url.is_valid()) {
-        sdch_manager->OnGetDictionary(request_->url(), sdch_dictionary_url);
+  if (sdch_manager) {
+    SdchProblemCode rv = sdch_manager->IsInSupportedDomain(request()->url());
+    if (rv != SDCH_OK) {
+      // If SDCH is just disabled, it is not a real error.
+      if (rv != SDCH_DISABLED && rv != SDCH_SECURE_SCHEME_NOT_SUPPORTED) {
+        SdchManager::SdchErrorRecovery(rv);
+        request()->net_log().AddEvent(
+            NetLog::TYPE_SDCH_DECODING_ERROR,
+            base::Bind(&NetLogSdchResourceProblemCallback, rv));
+      }
+    } else {
+      const std::string name = "Get-Dictionary";
+      std::string url_text;
+      void* iter = NULL;
+      // TODO(jar): We need to not fetch dictionaries the first time they are
+      // seen, but rather wait until we can justify their usefulness.
+      // For now, we will only fetch the first dictionary, which will at least
+      // require multiple suggestions before we get additional ones for this
+      // site. Eventually we should wait until a dictionary is requested
+      // several times
+      // before we even download it (so that we don't waste memory or
+      // bandwidth).
+      if (GetResponseHeaders()->EnumerateHeader(&iter, name, &url_text)) {
+        // Resolve suggested URL relative to request url.
+        GURL sdch_dictionary_url = request_->url().Resolve(url_text);
+        if (sdch_dictionary_url.is_valid()) {
+          rv = sdch_manager->OnGetDictionary(request_->url(),
+                                             sdch_dictionary_url);
+          if (rv != SDCH_OK) {
+            SdchManager::SdchErrorRecovery(rv);
+            request_->net_log().AddEvent(
+                NetLog::TYPE_SDCH_DICTIONARY_ERROR,
+                base::Bind(&NetLogSdchDictionaryFetchProblemCallback, rv,
+                           sdch_dictionary_url, false));
+          }
+        }
       }
     }
   }
@@ -483,13 +514,24 @@
   // simple_data_source.
   if (!request_info_.extra_headers.HasHeader(
       HttpRequestHeaders::kAcceptEncoding)) {
-    bool advertise_sdch = sdch_manager &&
-        // We don't support SDCH responses to POST as there is a possibility
-        // of having SDCH encoded responses returned (e.g. by the cache)
-        // which we cannot decode, and in those situations, we will need
-        // to retransmit the request without SDCH, which is illegal for a POST.
-        request()->method() != "POST" &&
-        sdch_manager->IsInSupportedDomain(request_->url());
+    // We don't support SDCH responses to POST as there is a possibility
+    // of having SDCH encoded responses returned (e.g. by the cache)
+    // which we cannot decode, and in those situations, we will need
+    // to retransmit the request without SDCH, which is illegal for a POST.
+    bool advertise_sdch = sdch_manager != NULL && request()->method() != "POST";
+    if (advertise_sdch) {
+      SdchProblemCode rv = sdch_manager->IsInSupportedDomain(request()->url());
+      if (rv != SDCH_OK) {
+        advertise_sdch = false;
+        // If SDCH is just disabled, it is not a real error.
+        if (rv != SDCH_DISABLED && rv != SDCH_SECURE_SCHEME_NOT_SUPPORTED) {
+          SdchManager::SdchErrorRecovery(rv);
+          request()->net_log().AddEvent(
+              NetLog::TYPE_SDCH_DECODING_ERROR,
+              base::Bind(&NetLogSdchResourceProblemCallback, rv));
+        }
+      }
+    }
     std::string avail_dictionaries;
     if (advertise_sdch) {
       sdch_manager->GetAvailDictionaryList(request_->url(),
diff --git a/sandbox/linux/syscall_broker/broker_process.cc b/sandbox/linux/syscall_broker/broker_process.cc
index ebd7d05..9b92c49 100644
--- a/sandbox/linux/syscall_broker/broker_process.cc
+++ b/sandbox/linux/syscall_broker/broker_process.cc
@@ -98,6 +98,7 @@
     _exit(1);
   }
   NOTREACHED();
+  return false;
 }
 
 void BrokerProcess::CloseChannel() {
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json
index d763318..a2a9b23 100644
--- a/testing/buildbot/chromium.chromiumos.json
+++ b/testing/buildbot/chromium.chromiumos.json
@@ -45,7 +45,6 @@
         }
       },
       "jingle_unittests",
-      "content_unittests",
       "device_unittests",
       "media_unittests",
       {
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index c9869f7..bee8677 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -46,7 +46,6 @@
       "mojo_public_environment_unittests",
       "mojo_public_system_unittests",
       "mojo_public_utility_unittests",
-      "mojo_surfaces_lib_unittests",
       "mojo_system_unittests",
       "nacl_loader_unittests"
     ],
@@ -112,7 +111,6 @@
       "mojo_public_environment_unittests",
       "mojo_public_system_unittests",
       "mojo_public_utility_unittests",
-      "mojo_surfaces_lib_unittests",
       "mojo_system_unittests",
       "nacl_loader_unittests"
     ],
@@ -178,7 +176,6 @@
       "mojo_public_environment_unittests",
       "mojo_public_system_unittests",
       "mojo_public_utility_unittests",
-      "mojo_surfaces_lib_unittests",
       "mojo_system_unittests",
       "nacl_loader_unittests"
     ],
@@ -244,7 +241,6 @@
       "mojo_public_environment_unittests",
       "mojo_public_system_unittests",
       "mojo_public_utility_unittests",
-      "mojo_surfaces_lib_unittests",
       "mojo_system_unittests",
       "nacl_loader_unittests"
     ],
diff --git a/testing/buildbot/tryserver.chromium.perf.json b/testing/buildbot/tryserver.chromium.perf.json
new file mode 100644
index 0000000..2c63c08
--- /dev/null
+++ b/testing/buildbot/tryserver.chromium.perf.json
@@ -0,0 +1,2 @@
+{
+}
diff --git a/testing/scripts/common.py b/testing/scripts/common.py
index 1afbe6b..f3617c7 100644
--- a/testing/scripts/common.py
+++ b/testing/scripts/common.py
@@ -68,6 +68,7 @@
       '--builder-name', cmd_args.properties['buildername'],
       '--slave-name', cmd_args.properties['slavename'],
       '--build-number', str(cmd_args.properties['buildnumber']),
+      '--build-properties', json.dumps(cmd_args.properties),
   ] + runtest_args)
 
 
diff --git a/ui/gl/generate_bindings.py b/ui/gl/generate_bindings.py
index 0156806..da668ec 100755
--- a/ui/gl/generate_bindings.py
+++ b/ui/gl/generate_bindings.py
@@ -595,9 +595,15 @@
   'names': ['glMapBufferOES', 'glMapBuffer'],
   'arguments': 'GLenum target, GLenum access', },
 { 'return_type': 'void*',
-  'names': ['glMapBufferRange'],
+  'known_as': 'glMapBufferRange',
+  'versions': [{ 'name': 'glMapBufferRange',
+                 'gl_versions': ['gl3', 'gl4', 'es3'] },
+               { 'name': 'glMapBufferRange',
+                 'extensions': ['GL_ARB_map_buffer_range'] },
+               { 'name': 'glMapBufferRangeEXT',
+                 'extensions': ['GL_EXT_map_buffer_range'] }],
   'arguments':
-      'GLenum target, GLintptr offset, GLsizeiptr length, GLenum access', },
+      'GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access', },
 { 'return_type': 'void',
   'known_as': 'glMatrixLoadfEXT',
   'versions': [{ 'name': 'glMatrixLoadfEXT',
diff --git a/ui/gl/gl_implementation_win.cc b/ui/gl/gl_implementation_win.cc
index b4dd38c..fff9018 100644
--- a/ui/gl/gl_implementation_win.cc
+++ b/ui/gl/gl_implementation_win.cc
@@ -33,7 +33,7 @@
 
 namespace {
 
-const wchar_t kD3DCompiler[] = L"D3DCompiler_46.dll";
+const wchar_t kD3DCompiler[] = L"D3DCompiler_47.dll";
 
 void GL_BINDING_CALL MarshalClearDepthToClearDepthf(GLclampd depth) {
   glClearDepthf(static_cast<GLclampf>(depth));