diff --git a/DEPS b/DEPS
index 9d9f18c..a93f161 100644
--- a/DEPS
+++ b/DEPS
@@ -40,7 +40,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '1a763632d21636504d78910f7dea0aa708c6365f',
+  'skia_revision': 'a523d2d1554441a79319eb46960d7b5c2dc85d9d',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -258,9 +258,6 @@
   'src/third_party/libphonenumber/dist':
     Var('chromium_git') + '/external/libphonenumber.git' + '@' + 'a4da30df63a097d67e3c429ead6790ad91d36cf4',
 
-  'src/third_party/webpagereplay':
-    Var('chromium_git') + '/external/github.com/chromium/web-page-replay.git' + '@' + '3cd3a3f6f06a1b87b14b9162c7eb16d23d141241',
-
   'src/third_party/pywebsocket/src':
     Var('chromium_git') + '/external/github.com/google/pywebsocket.git' + '@' + '2d7b73c3acbd0f41dcab487ae5c97c6feae06ce2',
 
diff --git a/ash/accessibility_delegate.h b/ash/accessibility_delegate.h
index 0be79b5..59d1753 100644
--- a/ash/accessibility_delegate.h
+++ b/ash/accessibility_delegate.h
@@ -33,15 +33,9 @@
   // Invoked to enable the screen magnifier.
   virtual void SetMagnifierEnabled(bool enabled) = 0;
 
-  // Invoked to change the type of the screen magnifier.
-  virtual void SetMagnifierType(MagnifierType type) = 0;
-
   // Returns true if the screen magnifier is enabled.
   virtual bool IsMagnifierEnabled() const = 0;
 
-  // Returns the current screen magnifier mode.
-  virtual MagnifierType GetMagnifierType() const = 0;
-
   // Invoked to enable Large Cursor.
   virtual void SetLargeCursorEnabled(bool enabled) = 0;
 
diff --git a/ash/accessibility_types.h b/ash/accessibility_types.h
index 56f7551..23fc6f8f 100644
--- a/ash/accessibility_types.h
+++ b/ash/accessibility_types.h
@@ -24,14 +24,12 @@
 
 // Note: Do not change these values; UMA and prefs depend on them.
 enum MagnifierType {
+  MAGNIFIER_DISABLED = 0,  // Used by enterprise policy.
   MAGNIFIER_FULL = 1,
-  MAGNIFIER_PARTIAL = 2,
+  // Never shipped. Deprioritized in 2013. http://crbug.com/170850
+  // MAGNIFIER_PARTIAL = 2,
 };
 
-const int kMaxMagnifierType = 2;
-
-const MagnifierType kDefaultMagnifierType = MAGNIFIER_FULL;
-
 // Factor of magnification scale. For example, when this value is 1.189, scale
 // value will be changed x1.000, x1.189, x1.414, x1.681, x2.000, ...
 // Note: this value is 2.0 ^ (1 / 4).
diff --git a/ash/default_accessibility_delegate.cc b/ash/default_accessibility_delegate.cc
index e2fd90a..a3b95399 100644
--- a/ash/default_accessibility_delegate.cc
+++ b/ash/default_accessibility_delegate.cc
@@ -28,18 +28,10 @@
   screen_magnifier_enabled_ = enabled;
 }
 
-void DefaultAccessibilityDelegate::SetMagnifierType(MagnifierType type) {
-  screen_magnifier_type_ = type;
-}
-
 bool DefaultAccessibilityDelegate::IsMagnifierEnabled() const {
   return screen_magnifier_enabled_;
 }
 
-MagnifierType DefaultAccessibilityDelegate::GetMagnifierType() const {
-  return screen_magnifier_type_;
-}
-
 void DefaultAccessibilityDelegate::SetLargeCursorEnabled(bool enabled) {
   large_cursor_enabled_ = enabled;
 }
diff --git a/ash/default_accessibility_delegate.h b/ash/default_accessibility_delegate.h
index 749abf3..3621e46 100644
--- a/ash/default_accessibility_delegate.h
+++ b/ash/default_accessibility_delegate.h
@@ -21,9 +21,7 @@
   void ToggleHighContrast() override;
   bool IsHighContrastEnabled() const override;
   void SetMagnifierEnabled(bool enabled) override;
-  void SetMagnifierType(MagnifierType type) override;
   bool IsMagnifierEnabled() const override;
-  MagnifierType GetMagnifierType() const override;
   void SetLargeCursorEnabled(bool enabled) override;
   bool IsLargeCursorEnabled() const override;
   void SetAutoclickEnabled(bool enabled) override;
@@ -66,7 +64,6 @@
   bool spoken_feedback_enabled_ = false;
   bool high_contrast_enabled_ = false;
   bool screen_magnifier_enabled_ = false;
-  MagnifierType screen_magnifier_type_ = kDefaultMagnifierType;
   bool large_cursor_enabled_ = false;
   bool autoclick_enabled_ = false;
   bool virtual_keyboard_enabled_ = false;
@@ -79,6 +76,7 @@
   bool select_to_speak_enabled_ = false;
   bool switch_access_enabled_ = false;
   AccessibilityAlert accessibility_alert_ = A11Y_ALERT_NONE;
+
   DISALLOW_COPY_AND_ASSIGN(DefaultAccessibilityDelegate);
 };
 
diff --git a/ash/public/cpp/ash_pref_names.cc b/ash/public/cpp/ash_pref_names.cc
index 5364a2c..8b3b6bb9 100644
--- a/ash/public/cpp/ash_pref_names.cc
+++ b/ash/public/cpp/ash_pref_names.cc
@@ -32,6 +32,7 @@
 // An integer pref which determines what type of screen magnifier is enabled.
 // Note that: 'screen_magnifier_type' had been used as string pref. Hence,
 // we are using another name pref here.
+// NOTE: We only shipped one type (full). http://crbug.com/170850
 const char kAccessibilityScreenMagnifierType[] =
     "settings.a11y.screen_magnifier_type2";
 // A double pref which determines a zooming scale of the screen magnifier.
diff --git a/base/bind.h b/base/bind.h
index 32a1c851e..944b7d8 100644
--- a/base/bind.h
+++ b/base/bind.h
@@ -35,20 +35,47 @@
 template <typename Signature>
 struct IsOnceCallback<OnceCallback<Signature>> : std::true_type {};
 
-// Asserts |Param| is constructible from |Unwrapped|. |Arg| is here just to
-// show it in the compile error message as a hint to fix the error.
-template <size_t i, typename Arg, typename Unwrapped, typename Param>
+// Helper to assert that parameter |i| of type |Arg| can be bound, which means:
+// - |Arg| can be retained internally as |Storage|.
+// - |Arg| can be forwarded as |Unwrapped| to |Param|.
+template <size_t i,
+          typename Arg,
+          typename Storage,
+          typename Unwrapped,
+          typename Param>
 struct AssertConstructible {
-  static_assert(std::is_constructible<Param, Unwrapped>::value,
-                "|Param| needs to be constructible from |Unwrapped| type. "
-                "The failing argument is passed as the |i|th parameter, whose "
-                "type is |Arg|, and delivered as |Unwrapped| into |Param|.");
+ private:
+  static constexpr bool param_is_forwardable =
+      std::is_constructible<Param, Unwrapped>::value;
+  // Unlike the check for binding into storage below, the check for
+  // forwardability drops the const qualifier for repeating callbacks. This is
+  // to try to catch instances where std::move()--which forwards as a const
+  // reference with repeating callbacks--is used instead of base::Passed().
+  static_assert(
+      param_is_forwardable ||
+          !std::is_constructible<Param, std::decay_t<Unwrapped>&&>::value,
+      "Bound argument |i| is move-only but will be forwarded by copy. "
+      "Ensure |Arg| is bound using base::Passed(), not std::move().");
+  static_assert(
+      param_is_forwardable,
+      "Bound argument |i| of type |Arg| cannot be forwarded as "
+      "|Unwrapped| to the bound functor, which declares it as |Param|.");
+
+  static constexpr bool arg_is_storable =
+      std::is_constructible<Storage, Arg>::value;
+  static_assert(arg_is_storable ||
+                    !std::is_constructible<Storage, std::decay_t<Arg>&&>::value,
+                "Bound argument |i| is move-only but will be bound by copy. "
+                "Ensure |Arg| is mutable and bound using std::move().");
+  static_assert(arg_is_storable,
+                "Bound argument |i| of type |Arg| cannot be converted and "
+                "bound as |Storage|.");
 };
 
 // Takes three same-length TypeLists, and applies AssertConstructible for each
 // triples.
 template <typename Index,
-          typename ArgsList,
+          typename Args,
           typename UnwrappedTypeList,
           typename ParamsList>
 struct AssertBindArgsValidity;
@@ -61,7 +88,7 @@
                               TypeList<Args...>,
                               TypeList<Unwrapped...>,
                               TypeList<Params...>>
-    : AssertConstructible<Ns, Args, Unwrapped, Params>... {
+    : AssertConstructible<Ns, Args, std::decay_t<Args>, Unwrapped, Params>... {
   static constexpr bool ok = true;
 };
 
diff --git a/base/bind_unittest.nc b/base/bind_unittest.nc
index 92b461f..cbaf6c48 100644
--- a/base/bind_unittest.nc
+++ b/base/bind_unittest.nc
@@ -70,7 +70,10 @@
 void VoidPolymorphic1(T t) {
 }
 
-#if defined(NCTEST_METHOD_ON_CONST_OBJECT)  // [r"fatal error: static_assert failed \"\|Param\| needs to be constructible from \|Unwrapped\| type\."]
+void TakesMoveOnly(std::unique_ptr<int>) {
+}
+
+#if defined(NCTEST_METHOD_ON_CONST_OBJECT)  // [r"fatal error: static_assert failed \"Bound argument \|i\| of type \|Arg\| cannot be forwarded as \|Unwrapped\| to the bound functor, which declares it as \|Param\|\.\""]
 
 // Method bound to const-object.
 //
@@ -107,7 +110,7 @@
   no_ref_const_cb.Run();
 }
 
-#elif defined(NCTEST_CONST_POINTER)  // [r"fatal error: static_assert failed \"\|Param\| needs to be constructible from \|Unwrapped\| type\."]
+#elif defined(NCTEST_CONST_POINTER)  // [r"fatal error: static_assert failed \"Bound argument \|i\| of type \|Arg\| cannot be forwarded as \|Unwrapped\| to the bound functor, which declares it as \|Param\|\.\""]
 
 // Const argument used with non-const pointer parameter of same type.
 //
@@ -119,7 +122,7 @@
   pointer_same_cb.Run();
 }
 
-#elif defined(NCTEST_CONST_POINTER_SUBTYPE)  // [r"fatal error: static_assert failed \"\|Param\| needs to be constructible from \|Unwrapped\| type\."]
+#elif defined(NCTEST_CONST_POINTER_SUBTYPE)  // [r"fatal error: static_assert failed \"Bound argument \|i\| of type \|Arg\| cannot be forwarded as \|Unwrapped\| to the bound functor, which declares it as \|Param\|\.\""]
 
 // Const argument used with non-const pointer parameter of super type.
 //
@@ -148,7 +151,7 @@
   ref_arg_cb.Run(p);
 }
 
-#elif defined(NCTEST_DISALLOW_BIND_TO_NON_CONST_REF_PARAM)  // [r"fatal error: static_assert failed \"\|Param\| needs to be constructible from \|Unwrapped\| type\."]
+#elif defined(NCTEST_DISALLOW_BIND_TO_NON_CONST_REF_PARAM)  // [r"fatal error: static_assert failed \"Bound argument \|i\| of type \|Arg\| cannot be forwarded as \|Unwrapped\| to the bound functor, which declares it as \|Param\|\.\""]
 
 // Binding functions with reference parameters, unsupported.
 //
@@ -277,6 +280,28 @@
   BindOnce(std::move(cb), 42);
 }
 
+#elif defined(NCTEST_BINDONCE_MOVEONLY_TYPE_BY_VALUE)  // [r"fatal error: static_assert failed \"Bound argument \|i\| is move-only but will be bound by copy\. Ensure \|Arg\| is mutable and bound using std::move\(\)\.\""]
+
+void WontCompile() {
+  std::unique_ptr<int> x;
+  BindOnce(&TakesMoveOnly, x);
+}
+
+#elif defined(NCTEST_BIND_MOVEONLY_TYPE_BY_VALUE)  // [r"Bound argument \|i\| is move-only but will be forwarded by copy\. Ensure \|Arg\| is bound using base::Passed\(\), not std::move\(\)."]
+
+void WontCompile() {
+  std::unique_ptr<int> x;
+  Bind(&TakesMoveOnly, x);
+}
+
+#elif defined(NCTEST_BIND_MOVEONLY_TYPE_WITH_STDMOVE)  // [r"Bound argument \|i\| is move-only but will be forwarded by copy\. Ensure \|Arg\| is bound using base::Passed\(\), not std::move\(\)."]
+
+void WontCompile() {
+  std::unique_ptr<int> x;
+  Bind(&TakesMoveOnly, std::move(x));
+}
+
+
 #endif
 
 }  // namespace base
diff --git a/base/containers/circular_deque.h b/base/containers/circular_deque.h
index 9d2d06ec8..3eec347 100644
--- a/base/containers/circular_deque.h
+++ b/base/containers/circular_deque.h
@@ -33,12 +33,6 @@
 //  - Container-wide comparisons are not implemented. If you want to compare
 //    two containers, use an algorithm so the expensive iteration is explicit.
 //
-//  - Insert and erase in the middle is not supported. This complicates the
-//    implementation and is not necessary for our current goals. We can
-//    consider adding this in the future if necessary. But consider that
-//    the implementation will be relatively inefficient (linear time). If
-//    a use wants arbitrary queue mutations, consider a std::list.
-//
 // If you want a similar container with only a queue API, use base::queue in
 // base/containers/queue.h.
 //
@@ -97,6 +91,16 @@
 //   void resize(size_t);
 //   void resize(size_t count, const T& value);
 //
+// Positional insert and erase:
+//   void insert(const_iterator pos, size_type count, const T& value);
+//   void insert(const_iterator pos,
+//               InputIterator first, InputIterator last);
+//   iterator insert(const_iterator pos, const T& value);
+//   iterator insert(const_iterator pos, T&& value);
+//   iterator emplace(const_iterator pos, Args&&... args);
+//   iterator erase(const_iterator pos);
+//   iterator erase(const_iterator first, const_iterator last);
+//
 // End insert and erase:
 //   void push_front(const T&);
 //   void push_front(T&&);
@@ -132,10 +136,9 @@
   using reference = const T&;
   using iterator_category = std::random_access_iterator_tag;
 
-  circular_deque_const_iterator(const circular_deque<T>* parent, size_t index)
-      : parent_deque_(parent), index_(index) {
+  circular_deque_const_iterator() : parent_deque_(nullptr), index_(0) {
 #if DCHECK_IS_ON()
-    created_generation_ = parent->generation_;
+    created_generation_ = 0;
 #endif  // DCHECK_IS_ON()
   }
 
@@ -231,8 +234,17 @@
   }
 
  protected:
+  friend class circular_deque<T>;
+
+  circular_deque_const_iterator(const circular_deque<T>* parent, size_t index)
+      : parent_deque_(parent), index_(index) {
+#if DCHECK_IS_ON()
+    created_generation_ = parent->generation_;
+#endif  // DCHECK_IS_ON()
+  }
+
   // Returns the offset from the beginning index of the buffer to the current
-  // iten.
+  // item.
   size_t OffsetFromBegin() const {
     if (index_ >= parent_deque_->begin_)
       return index_ - parent_deque_->begin_;  // On the same side as begin.
@@ -257,7 +269,12 @@
   }
   void Add(difference_type delta) {
     CheckUnstableUsage();
-    parent_deque_->CheckValidIndex(index_);
+#if DCHECK_IS_ON()
+    if (delta <= 0)
+      parent_deque_->CheckValidIndexOrEnd(index_);
+    else
+      parent_deque_->CheckValidIndex(index_);
+#endif
     difference_type new_offset = OffsetFromBegin() + delta;
     DCHECK(new_offset >= 0 &&
            new_offset <= static_cast<difference_type>(parent_deque_->size()));
@@ -267,17 +284,20 @@
 
 #if DCHECK_IS_ON()
   void CheckUnstableUsage() const {
+    DCHECK(parent_deque_);
     // Since circular_deque doesn't guarantee stability, any attempt to
     // dereference this iterator after a mutation (i.e. the generation doesn't
     // match the original) in the container is illegal.
-    DCHECK(parent_deque_);
     DCHECK_EQ(created_generation_, parent_deque_->generation_)
         << "circular_deque iterator dereferenced after mutation.";
   }
   void CheckComparable(const circular_deque_const_iterator& other) const {
     DCHECK_EQ(parent_deque_, other.parent_deque_);
-    CheckUnstableUsage();
-    other.CheckUnstableUsage();
+    // Since circular_deque doesn't guarantee stability, two iterators that
+    // are compared must have been generated without mutating the container.
+    // If this fires, the container was mutated between generating the two
+    // iterators being compared.
+    DCHECK_EQ(created_generation_, other.created_generation_);
   }
 #else
   inline void CheckUnstableUsage() const {}
@@ -300,6 +320,8 @@
   using base = circular_deque_const_iterator<T>;
 
  public:
+  friend class circular_deque<T>;
+
   using difference_type = std::ptrdiff_t;
   using value_type = T;
   using pointer = T*;
@@ -307,7 +329,7 @@
   using iterator_category = std::random_access_iterator_tag;
 
   // Expose the base class' constructor.
-  using base::circular_deque_const_iterator;
+  circular_deque_iterator() : circular_deque_const_iterator<T>() {}
 
   // Dereferencing.
   T& operator*() const { return const_cast<T&>(base::operator*()); }
@@ -354,6 +376,10 @@
     base::Decrement();
     return ret;
   }
+
+ private:
+  circular_deque_iterator(const circular_deque<T>* parent, size_t index)
+      : circular_deque_const_iterator<T>(parent, index) {}
 };
 
 }  // namespace internal
@@ -516,14 +542,16 @@
   const_iterator end() const { return const_iterator(this, end_); }
   const_iterator cend() const { return const_iterator(this, end_); }
 
-  reverse_iterator rbegin() { return reverse_iterator(begin()); }
+  reverse_iterator rbegin() { return reverse_iterator(end()); }
   const_reverse_iterator rbegin() const {
-    return const_reverse_iterator(begin());
+    return const_reverse_iterator(end());
   }
   const_reverse_iterator crbegin() const { return rbegin(); }
 
-  reverse_iterator rend() { return reverse_iterator(end()); }
-  const_reverse_iterator rend() const { return const_reverse_iterator(end()); }
+  reverse_iterator rend() { return reverse_iterator(begin()); }
+  const_reverse_iterator rend() const {
+    return const_reverse_iterator(begin());
+  }
   const_reverse_iterator crend() const { return rend(); }
 
   // ---------------------------------------------------------------------------
@@ -626,17 +654,155 @@
   // ---------------------------------------------------------------------------
   // Insert and erase.
   //
-  // These bulk insert operations are not provided as described in the file
-  // level comment above:
+  // Insertion and deletion in the middle is O(n) and invalidates all existing
+  // iterators.
   //
-  //   void insert(const_iterator pos, size_type count, const T& value);
-  //   void insert(const_iterator pos, InputIterator first, InputIterator last);
-  //   iterator insert(const_iterator pos, const T& value);
-  //   iterator insert(const_iterator pos, T&& value);
-  //   iterator emplace(const_iterator pos, Args&&... args);
-  //
-  //   iterator erase(const_iterator pos);
-  //   iterator erase(const_iterator first, const_iterator last);
+  // The implementation of insert isn't optimized as much as it could be. If
+  // the insertion requires that the buffer be grown, it will first be grown
+  // and everything moved, and then the items will be inserted, potentially
+  // moving some items twice. This simplifies the implemntation substantially
+  // and means less generated templatized code. Since this is an uncommon
+  // operation for deques, and already relatively slow, it doesn't seem worth
+  // the benefit to optimize this.
+
+  void insert(const_iterator pos, size_type count, const T& value) {
+    ValidateIterator(pos);
+
+    // Optimize insert at the beginning.
+    if (pos == begin()) {
+      ExpandCapacityIfNecessary(count);
+      for (size_t i = 0; i < count; i++)
+        push_front(value);
+      return;
+    }
+
+    iterator insert_cur(this, pos.index_);
+    iterator insert_end;
+    MakeRoomFor(count, &insert_cur, &insert_end);
+    while (insert_cur < insert_end) {
+      new (&buffer_[insert_cur.index_]) T(value);
+      ++insert_cur;
+    }
+
+    IncrementGeneration();
+  }
+
+  // This enable_if keeps this call from getting confused with the (pos, count,
+  // value) version when value is an integer.
+  template <class InputIterator>
+  typename std::enable_if<::base::internal::is_iterator<InputIterator>::value,
+                          void>::type
+  insert(const_iterator pos, InputIterator first, InputIterator last) {
+    ValidateIterator(pos);
+
+    size_t inserted_items = std::distance(first, last);
+    if (inserted_items == 0)
+      return;  // Can divide by 0 when doing modulo below, so return early.
+
+    // Make a hole to copy the items into.
+    iterator insert_cur;
+    iterator insert_end;
+    if (pos == begin()) {
+      // Optimize insert at the beginning, nothing needs to be shifted and the
+      // hole is the |inserted_items| block immediately before |begin_|.
+      ExpandCapacityIfNecessary(inserted_items);
+      insert_end = begin();
+      begin_ =
+          (begin_ + buffer_.capacity() - inserted_items) % buffer_.capacity();
+      insert_cur = begin();
+    } else {
+      insert_cur = iterator(this, pos.index_);
+      MakeRoomFor(inserted_items, &insert_cur, &insert_end);
+    }
+
+    // Copy the items.
+    while (insert_cur < insert_end) {
+      new (&buffer_[insert_cur.index_]) T(*first);
+      ++insert_cur;
+      ++first;
+    }
+
+    IncrementGeneration();
+  }
+
+  // These all return an iterator to the inserted item. Existing iterators will
+  // be invalidated.
+  iterator insert(const_iterator pos, const T& value) {
+    return emplace(pos, value);
+  }
+  iterator insert(const_iterator pos, T&& value) {
+    return emplace(pos, std::move(value));
+  }
+  template <class... Args>
+  iterator emplace(const_iterator pos, Args&&... args) {
+    ValidateIterator(pos);
+
+    // Optimize insert at beginning which doesn't require shifting.
+    if (pos == cbegin()) {
+      emplace_front(std::forward<Args>(args)...);
+      return begin();
+    }
+
+    // Do this before we make the new iterators we return.
+    IncrementGeneration();
+
+    iterator insert_begin(this, pos.index_);
+    iterator insert_end;
+    MakeRoomFor(1, &insert_begin, &insert_end);
+    new (&buffer_[insert_begin.index_]) T(std::forward<Args>(args)...);
+
+    return insert_begin;
+  }
+
+  // Calling erase() won't automatically resize the buffer smaller like resize
+  // or the pop functions. Erase is slow and relatively uncommon, and for
+  // normal deque usage a pop will normally be done on a regular basis that
+  // will prevent excessive buffer usage over long periods of time. It's not
+  // worth having the extra code for every template instantiation of erase()
+  // to resize capacity downward to a new buffer.
+  iterator erase(const_iterator pos) { return erase(pos, pos + 1); }
+  iterator erase(const_iterator first, const_iterator last) {
+    ValidateIterator(first);
+    ValidateIterator(last);
+
+    // First, call the destructor on the deleted items.
+    if (first.index_ < last.index_) {
+      // Contiguous range.
+      buffer_.DestructRange(&buffer_[first.index_], &buffer_[last.index_]);
+    } else {
+      // Deleted range wraps around.
+      buffer_.DestructRange(&buffer_[first.index_],
+                            &buffer_[buffer_.capacity()]);
+      buffer_.DestructRange(&buffer_[0], &buffer_[last.index_]);
+    }
+
+    IncrementGeneration();
+
+    if (last.index_ == begin_) {
+      // This deletion is from the beginning. Nothing needs to be copied, only
+      // begin_ needs to be updated.
+      begin_ = last.index_;
+      return iterator(this, last.index_);
+    }
+
+    // In an erase operation, the shifted items all move logically to the left,
+    // so move them from left-to-right.
+    iterator move_src(this, last.index_);
+    iterator move_src_end = end();
+    iterator move_dest(this, first.index_);
+    for (; move_src < move_src_end; move_src++, move_dest++) {
+      buffer_.MoveRange(&buffer_[move_src.index_],
+                        &buffer_[move_src.index_ + 1],
+                        &buffer_[move_dest.index_]);
+    }
+
+    end_ = move_dest.index_;
+
+    // Since we did not reallocate and only changed things after the erase
+    // element(s), the input iterator's index points to the thing following the
+    // deletion.
+    return iterator(this, first.index_);
+  }
 
   // ---------------------------------------------------------------------------
   // Begin/end operations.
@@ -816,6 +982,41 @@
     }
   }
 
+  // Makes room for |count| items starting at |*insert_begin|. Since iterators
+  // are not stable across buffer resizes, |*insert_begin| will be updated to
+  // point to the beginning of the newly opened position in the new array (it's
+  // in/out), and the end of the newly opened position (it's out-only).
+  void MakeRoomFor(size_t count, iterator* insert_begin, iterator* insert_end) {
+    if (count == 0) {
+      *insert_end = *insert_begin;
+      return;
+    }
+
+    // The offset from the beginning will be stable across reallocations.
+    size_t begin_offset = insert_begin->OffsetFromBegin();
+    ExpandCapacityIfNecessary(count);
+
+    insert_begin->index_ = (begin_ + begin_offset) % buffer_.capacity();
+    *insert_end =
+        iterator(this, (insert_begin->index_ + count) % buffer_.capacity());
+
+    // Update the new end and prepare the iterators for copying.
+    iterator src = end();
+    end_ = (end_ + count) % buffer_.capacity();
+    iterator dest = end();
+
+    // Move the elements. This will always involve shifting logically to the
+    // right, so move in a right-to-left order.
+    while (true) {
+      if (src == *insert_begin)
+        break;
+      --src;
+      --dest;
+      buffer_.MoveRange(&buffer_[src.index_], &buffer_[src.index_ + 1],
+                        &buffer_[dest.index_]);
+    }
+  }
+
 #if DCHECK_IS_ON()
   // Asserts the given index is dereferencable. The index is an index into the
   // buffer, not an index used by operator[] or at() which will be offsets from
@@ -833,12 +1034,18 @@
       CheckValidIndex(i);
   }
 
+  void ValidateIterator(const const_iterator& i) const {
+    DCHECK(i.parent_deque_ == this);
+    i.CheckUnstableUsage();
+  }
+
   // See generation_ below.
   void IncrementGeneration() { generation_++; }
 #else
   // No-op versions of these functions for release builds.
   void CheckValidIndex(size_t) const {}
   void CheckValidIndexOrEnd(size_t) const {}
+  void ValidateIterator(const const_iterator& i) const {}
   void IncrementGeneration() {}
 #endif
 
diff --git a/base/containers/circular_deque_unittest.cc b/base/containers/circular_deque_unittest.cc
index d520df2..932d943 100644
--- a/base/containers/circular_deque_unittest.cc
+++ b/base/containers/circular_deque_unittest.cc
@@ -479,6 +479,25 @@
   }
 }
 
+TEST(CircularDeque, ReverseIterator) {
+  circular_deque<int> q;
+  q.push_back(4);
+  q.push_back(3);
+  q.push_back(2);
+  q.push_back(1);
+
+  circular_deque<int>::reverse_iterator iter = q.rbegin();
+  EXPECT_EQ(1, *iter);
+  iter++;
+  EXPECT_EQ(2, *iter);
+  ++iter;
+  EXPECT_EQ(3, *iter);
+  iter++;
+  EXPECT_EQ(4, *iter);
+  ++iter;
+  EXPECT_EQ(q.rend(), iter);
+}
+
 TEST(CircularDeque, CapacityReserveShrink) {
   circular_deque<int> q;
 
@@ -627,6 +646,157 @@
   EXPECT_EQ(3, counter);
 }
 
+TEST(CircularDeque, InsertEraseSingle) {
+  circular_deque<int> q;
+  q.push_back(1);
+  q.push_back(2);
+
+  // Insert at the beginning.
+  auto result = q.insert(q.begin(), 0);
+  EXPECT_EQ(q.begin(), result);
+  EXPECT_EQ(3u, q.size());
+  EXPECT_EQ(0, q[0]);
+  EXPECT_EQ(1, q[1]);
+  EXPECT_EQ(2, q[2]);
+
+  // Erase at the beginning.
+  result = q.erase(q.begin());
+  EXPECT_EQ(q.begin(), result);
+  EXPECT_EQ(2u, q.size());
+  EXPECT_EQ(1, q[0]);
+  EXPECT_EQ(2, q[1]);
+
+  // Insert at the end.
+  result = q.insert(q.end(), 3);
+  EXPECT_EQ(q.end() - 1, result);
+  EXPECT_EQ(1, q[0]);
+  EXPECT_EQ(2, q[1]);
+  EXPECT_EQ(3, q[2]);
+
+  // Erase at the end.
+  result = q.erase(q.end() - 1);
+  EXPECT_EQ(q.end(), result);
+  EXPECT_EQ(1, q[0]);
+  EXPECT_EQ(2, q[1]);
+
+  // Insert in the middle.
+  result = q.insert(q.begin() + 1, 10);
+  EXPECT_EQ(q.begin() + 1, result);
+  EXPECT_EQ(1, q[0]);
+  EXPECT_EQ(10, q[1]);
+  EXPECT_EQ(2, q[2]);
+
+  // Erase in the middle.
+  result = q.erase(q.begin() + 1);
+  EXPECT_EQ(q.begin() + 1, result);
+  EXPECT_EQ(1, q[0]);
+  EXPECT_EQ(2, q[1]);
+}
+
+TEST(CircularDeque, InsertFill) {
+  circular_deque<int> q;
+
+  // Fill when empty.
+  q.insert(q.begin(), 2, 1);
+
+  // 0's at the beginning.
+  q.insert(q.begin(), 2, 0);
+
+  // 50's in the middle (now at offset 3).
+  q.insert(q.begin() + 3, 2, 50);
+
+  // 200's at the end.
+  q.insert(q.end(), 2, 200);
+
+  ASSERT_EQ(8u, q.size());
+  EXPECT_EQ(0, q[0]);
+  EXPECT_EQ(0, q[1]);
+  EXPECT_EQ(1, q[2]);
+  EXPECT_EQ(50, q[3]);
+  EXPECT_EQ(50, q[4]);
+  EXPECT_EQ(1, q[5]);
+  EXPECT_EQ(200, q[6]);
+  EXPECT_EQ(200, q[7]);
+}
+
+TEST(CircularDeque, InsertEraseRange) {
+  circular_deque<int> q;
+
+  // Loop index used below to shift the used items in the buffer.
+  for (int i = 0; i < 10; i++) {
+    circular_deque<int> source;
+
+    // Fill empty range.
+    q.insert(q.begin(), source.begin(), source.end());
+
+    // Have some stuff to insert.
+    source.push_back(1);
+    source.push_back(2);
+
+    q.insert(q.begin(), source.begin(), source.end());
+
+    // Shift the used items in the buffer by i which will place the two used
+    // elements in different places in the buffer each time through this loop.
+    for (int shift_i = 0; shift_i < i; shift_i++) {
+      q.push_back(0);
+      q.pop_front();
+    }
+
+    // Set the two items to notable values so we can check for them later.
+    ASSERT_EQ(2u, q.size());
+    q[0] = 100;
+    q[1] = 101;
+
+    // Insert at the beginning, middle (now at offset 3), and end.
+    q.insert(q.begin(), source.begin(), source.end());
+    q.insert(q.begin() + 3, source.begin(), source.end());
+    q.insert(q.end(), source.begin(), source.end());
+
+    ASSERT_EQ(8u, q.size());
+    EXPECT_EQ(1, q[0]);
+    EXPECT_EQ(2, q[1]);
+    EXPECT_EQ(100, q[2]);  // First inserted one.
+    EXPECT_EQ(1, q[3]);
+    EXPECT_EQ(2, q[4]);
+    EXPECT_EQ(101, q[5]);  // First inserted second one.
+    EXPECT_EQ(1, q[6]);
+    EXPECT_EQ(2, q[7]);
+
+    // Now erase the inserted ranges.
+    auto result = q.erase(q.begin(), q.begin() + 2);
+    EXPECT_EQ(q.begin(), result);
+    result = q.erase(q.begin() + 1, q.begin() + 3);
+    EXPECT_EQ(q.begin() + 1, result);
+    result = q.erase(q.end() - 2, q.end());
+    EXPECT_EQ(q.end(), result);
+
+    ASSERT_EQ(2u, q.size());
+    EXPECT_EQ(100, q[0]);
+    EXPECT_EQ(101, q[1]);
+
+    // Erase everything.
+    result = q.erase(q.begin(), q.end());
+    EXPECT_EQ(q.end(), result);
+    EXPECT_TRUE(q.empty());
+  }
+}
+
+TEST(CircularDeque, EmplaceMoveOnly) {
+  int values[] = {1, 3};
+  circular_deque<MoveOnlyInt> q(std::begin(values), std::end(values));
+
+  q.emplace(q.begin(), MoveOnlyInt(0));
+  q.emplace(q.begin() + 2, MoveOnlyInt(2));
+  q.emplace(q.end(), MoveOnlyInt(4));
+
+  ASSERT_EQ(5u, q.size());
+  EXPECT_EQ(0, q[0].data());
+  EXPECT_EQ(1, q[1].data());
+  EXPECT_EQ(2, q[2].data());
+  EXPECT_EQ(3, q[3].data());
+  EXPECT_EQ(4, q[4].data());
+}
+
 /*
 This test should assert in a debug build. It tries to dereference an iterator
 after mutating the container. Uncomment to double-check that this works.
diff --git a/base/metrics/histogram.cc b/base/metrics/histogram.cc
index f3683f0..fdc4c1a2 100644
--- a/base/metrics/histogram.cc
+++ b/base/metrics/histogram.cc
@@ -546,7 +546,7 @@
 }
 
 bool Histogram::ValidateHistogramContents(bool crash_if_invalid,
-                                          int corrupted_count) const {
+                                          int identifier) const {
   enum Fields : int {
     kUnloggedBucketRangesField,
     kUnloggedSamplesField,
@@ -569,7 +569,9 @@
     bad_fields |= 1 << kLoggedBucketRangesField;
   else if (logged_samples_->id() == 0)
     bad_fields |= 1 << kIdField;
-  else if (HashMetricName(histogram_name()) != logged_samples_->id())
+  else if (histogram_name().length() > 20 && histogram_name().at(20) == '\0')
+    bad_fields |= 1 << kHistogramNameField;
+  else if (histogram_name().length() > 40 && histogram_name().at(40) == '\0')
     bad_fields |= 1 << kHistogramNameField;
   if (flags() == 0)
     bad_fields |= 1 << kFlagsField;
@@ -581,14 +583,13 @@
     return is_valid;
 
   // Abort if a problem is found (except "flags", which could legally be zero).
-  const std::string debug_string =
-      base::StringPrintf("%s/%" PRIu32 "/%d", histogram_name().c_str(),
-                         bad_fields, corrupted_count);
+  const std::string debug_string = base::StringPrintf(
+      "%s/%" PRIu32 "#%d", histogram_name().c_str(), bad_fields, identifier);
 #if !defined(OS_NACL)
   // Temporary for https://crbug.com/736675.
   base::debug::ScopedCrashKey crash_key("bad_histogram", debug_string);
 #endif
-  CHECK(false) << debug_string;
+  // CHECK(false) << debug_string;
   debug::Alias(&bad_fields);
   return false;
 }
diff --git a/base/metrics/histogram.h b/base/metrics/histogram.h
index 9515d0c..6bac0814 100644
--- a/base/metrics/histogram.h
+++ b/base/metrics/histogram.h
@@ -214,7 +214,7 @@
   // if available.
   // TODO(bcwhite): Remove this after crbug/736675.
   bool ValidateHistogramContents(bool crash_if_invalid,
-                                 int corrupted_count) const override;
+                                 int identifier) const override;
 
  protected:
   // This class, defined entirely within the .cc file, contains all the
diff --git a/base/metrics/statistics_recorder.cc b/base/metrics/statistics_recorder.cc
index 13179ed..634f7b4c 100644
--- a/base/metrics/statistics_recorder.cc
+++ b/base/metrics/statistics_recorder.cc
@@ -299,22 +299,13 @@
 }
 
 // static
-void StatisticsRecorder::ValidateAllHistograms() {
+void StatisticsRecorder::ValidateAllHistograms(int identifier) {
   ImportGlobalPersistentHistograms();
 
   auto known = GetKnownHistograms(/*include_persistent=*/true);
 
-  HistogramBase* last_invalid_histogram = nullptr;
-  int invalid_count = 0;
-  for (HistogramBase* h : known) {
-    const bool is_valid = h->ValidateHistogramContents(false, 0);
-    if (!is_valid) {
-      ++invalid_count;
-      last_invalid_histogram = h;
-    }
-  }
-  if (last_invalid_histogram)
-    last_invalid_histogram->ValidateHistogramContents(true, invalid_count);
+  for (HistogramBase* h : known)
+    h->ValidateHistogramContents(true, identifier);
 }
 
 // static
diff --git a/base/metrics/statistics_recorder.h b/base/metrics/statistics_recorder.h
index 0a24b504..b1063d71 100644
--- a/base/metrics/statistics_recorder.h
+++ b/base/metrics/statistics_recorder.h
@@ -137,7 +137,7 @@
                             HistogramSnapshotManager* snapshot_manager);
 
   // TODO(asvitkine): Remove this after crbug/736675.
-  static void ValidateAllHistograms();
+  static void ValidateAllHistograms(int identifier = 0);
 
   // GetSnapshot copies some of the pointers to registered histograms into the
   // caller supplied vector (Histograms). Only histograms which have |query| as
diff --git a/base/profiler/native_stack_sampler_mac.cc b/base/profiler/native_stack_sampler_mac.cc
index e7e099f..302fe5c 100644
--- a/base/profiler/native_stack_sampler_mac.cc
+++ b/base/profiler/native_stack_sampler_mac.cc
@@ -44,6 +44,93 @@
   size_t index;
 };
 
+// Module identifiers ---------------------------------------------------------
+
+// Returns the unique build ID for a module loaded at |module_addr|. Returns the
+// empty string if the function fails to get the build ID.
+//
+// Build IDs are created by the concatenation of the module's GUID (Windows) /
+// UUID (Mac) and an "age" field that indicates how many times that GUID/UUID
+// has been reused. In Windows binaries, the "age" field is present in the
+// module header, but on the Mac, UUIDs are never reused and so the "age" value
+// appended to the UUID is always 0.
+std::string GetUniqueId(const void* module_addr) {
+  const mach_header_64* mach_header =
+      reinterpret_cast<const mach_header_64*>(module_addr);
+  DCHECK_EQ(MH_MAGIC_64, mach_header->magic);
+
+  size_t offset = sizeof(mach_header_64);
+  size_t offset_limit = sizeof(mach_header_64) + mach_header->sizeofcmds;
+  for (uint32_t i = 0; (i < mach_header->ncmds) &&
+                       (offset + sizeof(load_command) < offset_limit);
+       ++i) {
+    const load_command* current_cmd = reinterpret_cast<const load_command*>(
+        reinterpret_cast<const uint8_t*>(mach_header) + offset);
+
+    if (offset + current_cmd->cmdsize > offset_limit) {
+      // This command runs off the end of the command list. This is malformed.
+      return std::string();
+    }
+
+    if (current_cmd->cmd == LC_UUID) {
+      if (current_cmd->cmdsize < sizeof(uuid_command)) {
+        // This "UUID command" is too small. This is malformed.
+        return std::string();
+      }
+
+      const uuid_command* uuid_cmd =
+          reinterpret_cast<const uuid_command*>(current_cmd);
+      static_assert(sizeof(uuid_cmd->uuid) == sizeof(uuid_t),
+                    "UUID field of UUID command should be 16 bytes.");
+      // The ID is comprised of the UUID concatenated with the Mac's "age" value
+      // which is always 0.
+      return HexEncode(&uuid_cmd->uuid, sizeof(uuid_cmd->uuid)) + "0";
+    }
+    offset += current_cmd->cmdsize;
+  }
+  return std::string();
+}
+
+// Gets the index for the Module containing |instruction_pointer| in
+// |modules|, adding it if it's not already present. Returns
+// StackSamplingProfiler::Frame::kUnknownModuleIndex if no Module can be
+// determined for |module|.
+size_t GetModuleIndex(const uintptr_t instruction_pointer,
+                      std::vector<StackSamplingProfiler::Module>* modules,
+                      std::vector<ModuleIndex>* profile_module_index) {
+  // Check if |instruction_pointer| is in the address range of a module we've
+  // already seen.
+  auto module_index =
+      std::find_if(profile_module_index->begin(), profile_module_index->end(),
+                   [instruction_pointer](const ModuleIndex& index) {
+                     return instruction_pointer >= index.base_address &&
+                            instruction_pointer < index.end_address;
+                   });
+  if (module_index != profile_module_index->end()) {
+    return module_index->index;
+  }
+  Dl_info inf;
+  if (!dladdr(reinterpret_cast<const void*>(instruction_pointer), &inf))
+    return StackSamplingProfiler::Frame::kUnknownModuleIndex;
+
+  StackSamplingProfiler::Module module(
+      reinterpret_cast<uintptr_t>(inf.dli_fbase), GetUniqueId(inf.dli_fbase),
+      base::FilePath(inf.dli_fname));
+  modules->push_back(module);
+
+  const mach_header_64* mach_header =
+      reinterpret_cast<const mach_header_64*>(inf.dli_fbase);
+  DCHECK_EQ(MH_MAGIC_64, mach_header->magic);
+
+  unsigned long module_size;
+  getsegmentdata(mach_header, SEG_TEXT, &module_size);
+  uintptr_t base_module_address = reinterpret_cast<uintptr_t>(mach_header);
+  size_t index = modules->size() - 1;
+  profile_module_index->emplace_back(base_module_address,
+                                     base_module_address + module_size, index);
+  return index;
+}
+
 // Stack walking --------------------------------------------------------------
 
 // Fills |state| with |target_thread|'s context.
@@ -141,10 +228,13 @@
 // lambda for each frame. Returns false if an error occurred, otherwise returns
 // true.
 template <typename StackFrameCallback>
-bool WalkStackFromContext(unw_context_t* unwind_context,
-                          uintptr_t stack_top,
-                          size_t* frame_count,
-                          const StackFrameCallback& callback) {
+bool WalkStackFromContext(
+    unw_context_t* unwind_context,
+    uintptr_t stack_top,
+    size_t* frame_count,
+    std::vector<StackSamplingProfiler::Module>* current_modules,
+    std::vector<ModuleIndex>* profile_module_index,
+    const StackFrameCallback& callback) {
   unw_cursor_t unwind_cursor;
   unw_init_local(&unwind_cursor, unwind_context);
 
@@ -154,7 +244,25 @@
     ++(*frame_count);
     unw_get_reg(&unwind_cursor, UNW_REG_IP, &ip);
 
-    callback(static_cast<uintptr_t>(ip));
+    // Ensure IP is in a module.
+    //
+    // Frameless unwinding (non-DWARF) works by fetching the function's
+    // stack size from the unwind encoding or stack, and adding it to the
+    // stack pointer to determine the function's return address.
+    //
+    // If we're in a function prologue or epilogue, the actual stack size
+    // may be smaller than it will be during the normal course of execution.
+    // When libunwind adds the expected stack size, it will look for the
+    // return address in the wrong place. This check should ensure that we
+    // bail before trying to deref a bad IP obtained this way in the previous
+    // frame.
+    size_t module_index =
+        GetModuleIndex(ip, current_modules, profile_module_index);
+    if (module_index == StackSamplingProfiler::Frame::kUnknownModuleIndex) {
+      return false;
+    }
+
+    callback(static_cast<uintptr_t>(ip), module_index);
 
     // If this stack frame has a frame pointer, stepping the cursor will involve
     // indexing memory access off of that pointer. In that case, sanity-check
@@ -213,6 +321,8 @@
 template <typename StackFrameCallback>
 void WalkStack(const x86_thread_state64_t& thread_state,
                uintptr_t stack_top,
+               std::vector<StackSamplingProfiler::Module>* current_modules,
+               std::vector<ModuleIndex>* profile_module_index,
                const StackFrameCallback& callback) {
   size_t frame_count = 0;
   // This uses libunwind to walk the stack. libunwind is designed to be used for
@@ -228,7 +338,8 @@
   unw_context_t unwind_context;
   memcpy(&unwind_context, &thread_state, sizeof(uintptr_t) * 17);
   bool result =
-      WalkStackFromContext(&unwind_context, stack_top, &frame_count, callback);
+      WalkStackFromContext(&unwind_context, stack_top, &frame_count,
+                           current_modules, profile_module_index, callback);
 
   if (!result)
     return;
@@ -250,98 +361,12 @@
       strcmp(info.dli_fname, LibSystemKernelName()) == 0) {
       rip = *reinterpret_cast<uint64_t*>(rsp);
       rsp += 8;
-      WalkStackFromContext(&unwind_context, stack_top, &frame_count, callback);
+      WalkStackFromContext(&unwind_context, stack_top, &frame_count,
+                           current_modules, profile_module_index, callback);
     }
   }
 }
 
-// Module identifiers ---------------------------------------------------------
-
-// Returns the unique build ID for a module loaded at |module_addr|. Returns the
-// empty string if the function fails to get the build ID.
-//
-// Build IDs are created by the concatenation of the module's GUID (Windows) /
-// UUID (Mac) and an "age" field that indicates how many times that GUID/UUID
-// has been reused. In Windows binaries, the "age" field is present in the
-// module header, but on the Mac, UUIDs are never reused and so the "age" value
-// appended to the UUID is always 0.
-std::string GetUniqueId(const void* module_addr) {
-  const mach_header_64* mach_header =
-      reinterpret_cast<const mach_header_64*>(module_addr);
-  DCHECK_EQ(MH_MAGIC_64, mach_header->magic);
-
-  size_t offset = sizeof(mach_header_64);
-  size_t offset_limit = sizeof(mach_header_64) + mach_header->sizeofcmds;
-  for (uint32_t i = 0; (i < mach_header->ncmds) &&
-                       (offset + sizeof(load_command) < offset_limit);
-       ++i) {
-    const load_command* current_cmd = reinterpret_cast<const load_command*>(
-        reinterpret_cast<const uint8_t*>(mach_header) + offset);
-
-    if (offset + current_cmd->cmdsize > offset_limit) {
-      // This command runs off the end of the command list. This is malformed.
-      return std::string();
-    }
-
-    if (current_cmd->cmd == LC_UUID) {
-      if (current_cmd->cmdsize < sizeof(uuid_command)) {
-        // This "UUID command" is too small. This is malformed.
-        return std::string();
-      }
-
-      const uuid_command* uuid_cmd =
-          reinterpret_cast<const uuid_command*>(current_cmd);
-      static_assert(sizeof(uuid_cmd->uuid) == sizeof(uuid_t),
-                    "UUID field of UUID command should be 16 bytes.");
-      // The ID is comprised of the UUID concatenated with the Mac's "age" value
-      // which is always 0.
-      return HexEncode(&uuid_cmd->uuid, sizeof(uuid_cmd->uuid)) + "0";
-    }
-    offset += current_cmd->cmdsize;
-  }
-  return std::string();
-}
-
-// Gets the index for the Module containing |instruction_pointer| in
-// |modules|, adding it if it's not already present. Returns
-// StackSamplingProfiler::Frame::kUnknownModuleIndex if no Module can be
-// determined for |module|.
-size_t GetModuleIndex(const uintptr_t instruction_pointer,
-                      std::vector<StackSamplingProfiler::Module>* modules,
-                      std::vector<ModuleIndex>* profile_module_index) {
-  // Check if |instruction_pointer| is in the address range of a module we've
-  // already seen.
-  auto module_index =
-      std::find_if(profile_module_index->begin(), profile_module_index->end(),
-                   [instruction_pointer](const ModuleIndex& index) {
-                     return instruction_pointer >= index.base_address &&
-                            instruction_pointer < index.end_address;
-                   });
-  if (module_index != profile_module_index->end()) {
-    return module_index->index;
-  }
-  Dl_info inf;
-  if (!dladdr(reinterpret_cast<const void*>(instruction_pointer), &inf))
-    return StackSamplingProfiler::Frame::kUnknownModuleIndex;
-
-  StackSamplingProfiler::Module module(
-      reinterpret_cast<uintptr_t>(inf.dli_fbase), GetUniqueId(inf.dli_fbase),
-      base::FilePath(inf.dli_fname));
-  modules->push_back(module);
-
-  const mach_header_64* mach_header =
-      reinterpret_cast<const mach_header_64*>(inf.dli_fbase);
-  DCHECK_EQ(MH_MAGIC_64, mach_header->magic);
-
-  unsigned long module_size;
-  getsegmentdata(mach_header, SEG_TEXT, &module_size);
-  uintptr_t base_module_address = reinterpret_cast<uintptr_t>(mach_header);
-  size_t index = modules->size() - 1;
-  profile_module_index->emplace_back(base_module_address,
-                                     base_module_address + module_size, index);
-  return index;
-}
-
 // ScopedSuspendThread --------------------------------------------------------
 
 // Suspends a thread for the lifetime of the object.
@@ -501,13 +526,12 @@
 
   auto* current_modules = current_modules_;
   auto* profile_module_index = &profile_module_index_;
-  WalkStack(
-      thread_state, new_stack_top,
-      [sample, current_modules, profile_module_index](uintptr_t frame_ip) {
-        sample->frames.push_back(StackSamplingProfiler::Frame(
-            frame_ip,
-            GetModuleIndex(frame_ip, current_modules, profile_module_index)));
-      });
+  WalkStack(thread_state, new_stack_top, current_modules, profile_module_index,
+            [sample, current_modules, profile_module_index](
+                uintptr_t frame_ip, size_t module_index) {
+              sample->frames.push_back(
+                  StackSamplingProfiler::Frame(frame_ip, module_index));
+            });
 }
 
 }  // namespace
diff --git a/build/android/findbugs_filter/findbugs_exclude.xml b/build/android/findbugs_filter/findbugs_exclude.xml
index 5bb747c3..0bbab67 100644
--- a/build/android/findbugs_filter/findbugs_exclude.xml
+++ b/build/android/findbugs_filter/findbugs_exclude.xml
@@ -26,6 +26,11 @@
   https://developer.android.com/reference/java/security/AccessController.html
   -->
   <Bug pattern="DP_CREATE_CLASSLOADER_INSIDE_DO_PRIVILEGED" />
+  <!--
+  Ignore unchecked casts.
+  See https://groups.google.com/a/chromium.org/forum/#!topic/java/xfXmNLI4SqM for details.
+  -->
+  <Bug pattern="BC_UNCONFIRMED_CAST" />
 
   <!-- Ignore unused public Rule and RuleChain in instrumentation tests -->
   <Match>
diff --git a/cc/blink/web_layer_impl.cc b/cc/blink/web_layer_impl.cc
index 5fa1e7b..b4ced27d 100644
--- a/cc/blink/web_layer_impl.cc
+++ b/cc/blink/web_layer_impl.cc
@@ -245,6 +245,10 @@
   return layer_->scrollable();
 }
 
+blink::WebSize WebLayerImpl::ScrollContainerBoundsForTesting() const {
+  return layer_->scroll_container_bounds();
+}
+
 void WebLayerImpl::SetUserScrollable(bool horizontal, bool vertical) {
   layer_->SetUserScrollable(horizontal, vertical);
 }
diff --git a/cc/blink/web_layer_impl.h b/cc/blink/web_layer_impl.h
index 40300b1..dc419b9 100644
--- a/cc/blink/web_layer_impl.h
+++ b/cc/blink/web_layer_impl.h
@@ -92,6 +92,7 @@
   void SetBackgroundFilters(const cc::FilterOperations& filters) override;
   bool HasTickingAnimationForTesting() override;
   void SetScrollable(const blink::WebSize&) override;
+  blink::WebSize ScrollContainerBoundsForTesting() const override;
   void SetScrollPosition(blink::WebFloatPoint position) override;
   blink::WebFloatPoint ScrollPosition() const override;
   bool Scrollable() const override;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
index 9888f2c..d1730aa9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -662,16 +662,12 @@
 
     @Override
     public ChromeTabCreator getTabCreator(boolean incognito) {
-        TabCreator tabCreator = super.getTabCreator(incognito);
-        assert tabCreator instanceof ChromeTabCreator;
-        return (ChromeTabCreator) tabCreator;
+        return (ChromeTabCreator) super.getTabCreator(incognito);
     }
 
     @Override
     public ChromeTabCreator getCurrentTabCreator() {
-        TabCreator tabCreator = super.getCurrentTabCreator();
-        assert tabCreator instanceof ChromeTabCreator;
-        return (ChromeTabCreator) tabCreator;
+        return (ChromeTabCreator) super.getCurrentTabCreator();
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkItemsAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkItemsAdapter.java
index 790898df..8d657c04 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkItemsAdapter.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkItemsAdapter.java
@@ -14,7 +14,6 @@
 import android.view.ViewGroup;
 
 import org.chromium.base.VisibleForTesting;
-import org.chromium.base.annotations.SuppressFBWarnings;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.bookmarks.BookmarkBridge.BookmarkItem;
 import org.chromium.chrome.browser.bookmarks.BookmarkBridge.BookmarkModelObserver;
@@ -224,7 +223,6 @@
         }
     }
 
-    @SuppressFBWarnings("BC_UNCONFIRMED_CAST")
     @Override
     public void onBindViewHolder(ViewHolder holder, int position) {
         switch (holder.getItemViewType()) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/SeparateTaskManagedCustomTabActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/SeparateTaskManagedCustomTabActivity.java
index dcbedce4..f24b43c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/SeparateTaskManagedCustomTabActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/SeparateTaskManagedCustomTabActivity.java
@@ -50,7 +50,6 @@
     @Override
     public ChromeTabCreator getTabCreator(boolean incognito) {
         TabCreator tabCreator = super.getTabCreator(incognito);
-        assert tabCreator instanceof ChromeTabCreator;
         return (ChromeTabCreator) tabCreator;
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadHistoryItemWrapper.java b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadHistoryItemWrapper.java
index 9dc36fc..c00f5f5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadHistoryItemWrapper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadHistoryItemWrapper.java
@@ -229,7 +229,6 @@
 
         @Override
         public boolean replaceItem(Object item) {
-            assert item instanceof DownloadItem;
             DownloadItem downloadItem = (DownloadItem) item;
             assert TextUtils.equals(mItem.getId(), downloadItem.getId());
 
@@ -430,7 +429,6 @@
 
         @Override
         public boolean replaceItem(Object item) {
-            assert item instanceof OfflinePageDownloadItem;
             OfflinePageDownloadItem newItem = (OfflinePageDownloadItem) item;
             assert TextUtils.equals(newItem.getGuid(), mItem.getGuid());
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunActivity.java
index 45c17e93..291e8296 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunActivity.java
@@ -33,7 +33,6 @@
 import org.chromium.chrome.browser.util.IntentUtils;
 import org.chromium.ui.base.LocalizationUtils;
 
-import java.lang.ref.WeakReference;
 import java.lang.reflect.Constructor;
 import java.util.ArrayList;
 import java.util.HashSet;
@@ -405,7 +404,7 @@
 
     @Override
     public void abortFirstRunExperience() {
-        finishAllTheActivities(getLocalClassName());
+        finish();
 
         sendPendingIntentIfNecessary(false);
         if (sObserver != null) sObserver.onAbortFirstRunExperience();
@@ -453,13 +452,13 @@
         if (sObserver != null) sObserver.onUpdateCachedEngineName();
 
         if (!sendPendingIntentIfNecessary(true)) {
-            finishAllTheActivities(getLocalClassName());
+            finish();
         } else {
             ApplicationStatus.registerStateListenerForActivity(new ActivityStateListener() {
                 @Override
                 public void onActivityStateChange(Activity activity, int newState) {
                     if (newState == ActivityState.STOPPED || newState == ActivityState.DESTROYED) {
-                        finishAllTheActivities(getLocalClassName());
+                        finish();
                         ApplicationStatus.unregisterActivityStateListener(this);
                     }
                 }
@@ -510,20 +509,6 @@
     }
 
     /**
-    * Finish all the instances of the given Activity.
-    * @param targetActivity The class name of the target Activity.
-    */
-    protected static void finishAllTheActivities(String targetActivity) {
-        List<WeakReference<Activity>> activities = ApplicationStatus.getRunningActivities();
-        for (WeakReference<Activity> weakActivity : activities) {
-            Activity activity = weakActivity.get();
-            if (activity != null && activity.getLocalClassName().equals(targetActivity)) {
-                activity.finish();
-            }
-        }
-    }
-
-    /**
      * Sends the PendingIntent included with the CHROME_LAUNCH_INTENT extra if it exists.
      * @param complete Whether first run completed successfully.
      * @return Whether a pending intent was sent.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/LightweightFirstRunActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/LightweightFirstRunActivity.java
index 7ee86de2..9bd1508 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/LightweightFirstRunActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/LightweightFirstRunActivity.java
@@ -90,7 +90,7 @@
     @Override
     public void completeFirstRunExperience() {
         FirstRunStatus.setLightweightFirstRunFlowComplete(true);
-        finishAllTheActivities(getLocalClassName());
+        finish();
 
         sendPendingIntentIfNecessary(true);
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/OWNERS b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/OWNERS
new file mode 100644
index 0000000..94b86d4
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/OWNERS
@@ -0,0 +1 @@
+yusufo@chromium.org
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/remote/RemoteMediaPlayerController.java b/chrome/android/java/src/org/chromium/chrome/browser/media/remote/RemoteMediaPlayerController.java
index d26befd0..3fb5d57 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/media/remote/RemoteMediaPlayerController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/media/remote/RemoteMediaPlayerController.java
@@ -145,7 +145,6 @@
                     Log.d(TAG, "Adding remote media route controller %s", className.trim());
                     Class<?> mediaRouteControllerClass = Class.forName(className.trim());
                     Object mediaRouteController = mediaRouteControllerClass.newInstance();
-                    assert mediaRouteController instanceof MediaRouteController;
                     mMediaRouteControllers.add((MediaRouteController) mediaRouteController);
                 }
             }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/metrics/WebApkUma.java b/chrome/android/java/src/org/chromium/chrome/browser/metrics/WebApkUma.java
index 2f0a4d9a..64d8ac38 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/metrics/WebApkUma.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/metrics/WebApkUma.java
@@ -156,30 +156,30 @@
      */
     @SuppressWarnings("deprecation")
     public static void logAvailableSpaceAboveLowSpaceLimitInUMA(boolean installSucceeded) {
-        StatFs partitionStats = new StatFs(Environment.getDataDirectory().getAbsolutePath());
-        long partitionAvailableBytes;
-        long partitionTotalBytes;
-
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
-            partitionAvailableBytes = partitionStats.getAvailableBytes();
-            partitionTotalBytes = partitionStats.getTotalBytes();
-        } else {
-            long blockSize = partitionStats.getBlockSize(); // deprecated in API level 18.
-            partitionAvailableBytes = blockSize
-                    * (long) partitionStats.getAvailableBlocks(); // deprecated in API level 18.
-            partitionTotalBytes = blockSize * (long) partitionStats.getBlockCount();
-        }
-
         // ContentResolver APIs are usually heavy, do it in AsyncTask.
         new AsyncTask<Void, Void, Long>() {
+            long mPartitionAvailableBytes;
             @Override
             protected Long doInBackground(Void... params) {
+                StatFs partitionStats =
+                        new StatFs(Environment.getDataDirectory().getAbsolutePath());
+                long partitionTotalBytes;
+                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
+                    mPartitionAvailableBytes = partitionStats.getAvailableBytes();
+                    partitionTotalBytes = partitionStats.getTotalBytes();
+                } else {
+                    // these APIs were deprecated in API level 18.
+                    long blockSize = partitionStats.getBlockSize();
+                    mPartitionAvailableBytes = blockSize
+                            * (long) partitionStats.getAvailableBlocks();
+                    partitionTotalBytes = blockSize * (long) partitionStats.getBlockCount();
+                }
                 return getLowSpaceLimitBytes(partitionTotalBytes);
             }
 
             @Override
             protected void onPostExecute(Long minimumFreeBytes) {
-                long availableBytesForInstallation = partitionAvailableBytes - minimumFreeBytes;
+                long availableBytesForInstallation = mPartitionAvailableBytes - minimumFreeBytes;
                 int availableSpaceMb = (int) (availableBytesForInstallation / 1024L / 1024L);
                 // Bound the number to [-1000, 500] and round down to the nearest multiple of 10MB
                 // to avoid exploding the histogram.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/CustomNotificationBuilder.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/CustomNotificationBuilder.java
index 4cea201..ca6279a9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/CustomNotificationBuilder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/CustomNotificationBuilder.java
@@ -4,6 +4,8 @@
 
 package org.chromium.chrome.browser.notifications;
 
+import static org.chromium.chrome.browser.util.ViewUtils.dpToPx;
+
 import android.app.Notification;
 import android.content.Context;
 import android.content.res.Resources;
@@ -16,7 +18,6 @@
 import android.os.SystemClock;
 import android.text.format.DateFormat;
 import android.util.DisplayMetrics;
-import android.util.TypedValue;
 import android.view.View;
 import android.widget.RemoteViews;
 
@@ -211,13 +212,13 @@
                     iconWidth = options.outWidth;
                 }
                 iconWidth = dpToPx(
-                        Math.min(pxToDp(iconWidth, metrics), MAX_ACTION_ICON_WIDTH_DP), metrics);
+                        metrics, Math.min(pxToDp(iconWidth, metrics), MAX_ACTION_ICON_WIDTH_DP));
 
                 // Set the padding of the button so the text does not overlap with the icon. Flip
                 // between left and right manually as RemoteViews does not expose a method that sets
                 // padding in a writing-direction independent way.
                 int buttonPadding =
-                        dpToPx(BUTTON_PADDING_START_DP + BUTTON_ICON_PADDING_DP, metrics)
+                        dpToPx(metrics, BUTTON_PADDING_START_DP + BUTTON_ICON_PADDING_DP)
                         + iconWidth;
                 int buttonPaddingLeft = LocalizationUtils.isLayoutRtl() ? 0 : buttonPadding;
                 int buttonPaddingRight = LocalizationUtils.isLayoutRtl() ? buttonPadding : 0;
@@ -233,8 +234,7 @@
     private void configureSettingsButton(RemoteViews bigView) {
         if (mSettingsAction == null) {
             bigView.setViewVisibility(R.id.origin_settings_icon, View.GONE);
-            int rightPadding =
-                    dpToPx(BUTTON_ICON_PADDING_DP, mContext.getResources().getDisplayMetrics());
+            int rightPadding = dpToPx(mContext, BUTTON_ICON_PADDING_DP);
             int leftPadding =
                     Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP ? rightPadding : 0;
             bigView.setViewPadding(R.id.origin, leftPadding, 0, rightPadding, 0);
@@ -252,7 +252,7 @@
     private void addWorkProfileBadge(RemoteViews view) {
         Resources resources = mContext.getResources();
         DisplayMetrics metrics = resources.getDisplayMetrics();
-        int size = dpToPx(WORK_PROFILE_BADGE_SIZE_DP, metrics);
+        int size = dpToPx(metrics, WORK_PROFILE_BADGE_SIZE_DP);
         int[] colors = new int[size * size];
 
         // Create an immutable bitmap, so that it can not be reused for painting a badge into it.
@@ -295,7 +295,7 @@
      * notification. Never scales the padding below zero.
      *
      * @param fontScale The current system font scaling factor.
-     * @param displayMetrics The display metrics for the current context.
+     * @param metrics The display metrics for the current context.
      * @return The amount of padding to be used, in pixels.
      */
     @VisibleForTesting
@@ -305,14 +305,7 @@
             fontScale = Math.min(fontScale, FONT_SCALE_LARGE);
             paddingScale = (FONT_SCALE_LARGE - fontScale) / (FONT_SCALE_LARGE - 1.0f);
         }
-        return dpToPx(paddingScale * MAX_SCALABLE_PADDING_DP, metrics);
-    }
-
-    /**
-     * Converts a dp value to a px value.
-     */
-    private static int dpToPx(float value, DisplayMetrics metrics) {
-        return Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, value, metrics));
+        return dpToPx(metrics, paddingScale * MAX_SCALABLE_PADDING_DP);
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/IncognitoNewTabPageViewMD.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/IncognitoNewTabPageViewMD.java
index 2e99eb32..6f9c668d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/IncognitoNewTabPageViewMD.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/IncognitoNewTabPageViewMD.java
@@ -4,6 +4,8 @@
 
 package org.chromium.chrome.browser.ntp;
 
+import static org.chromium.chrome.browser.util.ViewUtils.dpToPx;
+
 import android.content.Context;
 import android.graphics.Canvas;
 import android.graphics.Paint;
@@ -97,10 +99,6 @@
         return (int) Math.ceil(px / mMetrics.density);
     }
 
-    private int dpToPx(int dp) {
-        return (int) Math.ceil(dp * mMetrics.density);
-    }
-
     private int spToPx(int sp) {
         return (int) Math.ceil(sp * mMetrics.scaledDensity);
     }
@@ -229,12 +227,13 @@
             mSubtitle.setLayoutParams(
                     new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
                             LinearLayout.LayoutParams.WRAP_CONTENT));
-            mSubtitle.setMaxWidth(dpToPx(CONTENT_WIDTH_DP));
+            mSubtitle.setMaxWidth(dpToPx(mContext, CONTENT_WIDTH_DP));
 
             // The bulletpoints container takes the same width as subtitle. Since the width can
             // not be directly measured at this stage, we must calculate it manually.
             mBulletpointsContainer.setLayoutParams(new LinearLayout.LayoutParams(
-                    dpToPx(Math.min(CONTENT_WIDTH_DP, mWidthDp - 2 * paddingHorizontalDp)),
+                    dpToPx(mContext,
+                            Math.min(CONTENT_WIDTH_DP, mWidthDp - 2 * paddingHorizontalDp)),
                     LinearLayout.LayoutParams.WRAP_CONTENT));
         } else {
             // Large padding.
@@ -252,8 +251,9 @@
 
             // The subtitle width is equal to the two sets of bulletpoints if they are arranged
             // horizontally. If not, use the default CONTENT_WIDTH_DP.
-            int contentWidthPx = bulletpointsArrangedHorizontally ? dpToPx(totalBulletpointsWidthDp)
-                                                                  : dpToPx(CONTENT_WIDTH_DP);
+            int contentWidthPx = bulletpointsArrangedHorizontally
+                    ? dpToPx(mContext, totalBulletpointsWidthDp)
+                    : dpToPx(mContext, CONTENT_WIDTH_DP);
             mSubtitle.setLayoutParams(new LinearLayout.LayoutParams(
                     contentWidthPx, LinearLayout.LayoutParams.WRAP_CONTENT));
             mBulletpointsContainer.setLayoutParams(new LinearLayout.LayoutParams(
@@ -268,8 +268,9 @@
         }
 
         // Set up paddings and margins.
-        mContainer.setPadding(dpToPx(paddingHorizontalDp), dpToPx(paddingVerticalDp),
-                dpToPx(paddingHorizontalDp), dpToPx(paddingVerticalDp));
+        mContainer.setPadding(dpToPx(mContext, paddingHorizontalDp),
+                dpToPx(mContext, paddingVerticalDp), dpToPx(mContext, paddingHorizontalDp),
+                dpToPx(mContext, paddingVerticalDp));
 
         int spacingPx =
                 (int) Math.ceil(mParagraphs[0].getTextSize() * (mHeightDp <= 600 ? 1 : 1.5));
@@ -278,7 +279,7 @@
             // If bulletpoints are arranged horizontally, there should be space between them.
             int rightMarginPx = (bulletpointsArrangedHorizontally
                                         && paragraph == mBulletpointsContainer.getChildAt(0))
-                    ? dpToPx(BULLETPOINTS_HORIZONTAL_SPACING_DP)
+                    ? dpToPx(mContext, BULLETPOINTS_HORIZONTAL_SPACING_DP)
                     : 0;
 
             ((LinearLayout.LayoutParams) paragraph.getLayoutParams())
@@ -303,8 +304,8 @@
         }
 
         ImageView icon = (ImageView) findViewById(R.id.new_tab_incognito_icon);
-        icon.getLayoutParams().width = dpToPx(sizeDp);
-        icon.getLayoutParams().height = dpToPx(sizeDp);
+        icon.getLayoutParams().width = dpToPx(mContext, sizeDp);
+        icon.getLayoutParams().height = dpToPx(mContext, sizeDp);
     }
 
     /** Adjust the "Learn More" link. */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java
index 0fb1e9e..fa5a1fb 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java
@@ -4,6 +4,8 @@
 
 package org.chromium.chrome.browser.ntp;
 
+import static org.chromium.chrome.browser.util.ViewUtils.dpToPx;
+
 import android.annotation.SuppressLint;
 import android.content.Context;
 import android.graphics.Canvas;
@@ -17,7 +19,6 @@
 import android.text.Editable;
 import android.text.TextWatcher;
 import android.util.AttributeSet;
-import android.util.TypedValue;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
@@ -269,7 +270,7 @@
                 ChromeFeatureList.NTP_CONDENSED_LAYOUT, PARAM_CONDENSED_LAYOUT_LOGO_HEIGHT, 0);
         if (experimentalLogoHeightDp > 0) {
             ViewGroup.LayoutParams logoParams = mSearchProviderLogoView.getLayoutParams();
-            logoParams.height = dpToPx(experimentalLogoHeightDp);
+            logoParams.height = dpToPx(getContext(), experimentalLogoHeightDp);
             mSearchProviderLogoView.setLayoutParams(logoParams);
         }
         mLogoDelegate = new LogoDelegateImpl(
@@ -982,11 +983,4 @@
         }
     }
 
-    /**
-     * Converts a dp value to a px value.
-     */
-    private int dpToPx(int value) {
-        return Math.round(TypedValue.applyDimension(
-                TypedValue.COMPLEX_UNIT_DIP, value, getResources().getDisplayMetrics()));
-    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/RecentTabsRowAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/RecentTabsRowAdapter.java
index 224ba76..ec98c8e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/RecentTabsRowAdapter.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/RecentTabsRowAdapter.java
@@ -150,7 +150,6 @@
          * @return The view corresponding to the group.
          */
         public View getGroupView(boolean isExpanded, View convertView, ViewGroup parent) {
-            assert convertView == null || convertView instanceof RecentTabsGroupView;
             RecentTabsGroupView groupView = (RecentTabsGroupView) convertView;
             if (groupView == null) {
                 groupView = (RecentTabsGroupView) LayoutInflater.from(mActivity).inflate(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/ActionItem.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/ActionItem.java
index 27c3f11..37d665a3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/ActionItem.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/ActionItem.java
@@ -47,7 +47,6 @@
 
     @Override
     protected void onBindViewHolder(NewTabPageViewHolder holder) {
-        assert holder instanceof ViewHolder;
         mSuggestionsRanker.rankActionItem(this, mParentSection);
         ((ViewHolder) holder).onBindViewHolder(this);
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/AllDismissedItem.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/AllDismissedItem.java
index 83ae6ec..104ddc88 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/AllDismissedItem.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/AllDismissedItem.java
@@ -30,7 +30,6 @@
 
     @Override
     public void onBindViewHolder(NewTabPageViewHolder holder) {
-        assert holder instanceof ViewHolder;
         ((ViewHolder) holder).onBindViewHolder();
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java
index db9a469..8f16c39 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java
@@ -202,7 +202,6 @@
         }
 
         for (Object payload : payloads) {
-            assert payload instanceof PartialBindCallback;
             ((PartialBindCallback) payload).onResult(holder);
         }
     }
@@ -313,9 +312,6 @@
         // Getting the reference as we are doing here is going to be broken if that changes.
         assert mRecyclerView == null;
 
-        // FindBugs chokes on the cast below when not checked, raising BC_UNCONFIRMED_CAST
-        assert recyclerView instanceof SuggestionsRecyclerView;
-
         mRecyclerView = (SuggestionsRecyclerView) recyclerView;
 
         if (SuggestionsConfig.scrollToLoad()) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/ProgressItem.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/ProgressItem.java
index b1b39f0c..198e1d1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/ProgressItem.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/ProgressItem.java
@@ -20,7 +20,6 @@
 
     @Override
     protected void onBindViewHolder(NewTabPageViewHolder holder) {
-        assert holder instanceof ProgressViewHolder;
         ((ProgressViewHolder) holder).onBindViewHolder(this);
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SignInPromo.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SignInPromo.java
index 979a7c8b..d7ef055 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SignInPromo.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SignInPromo.java
@@ -13,7 +13,6 @@
 import org.chromium.base.Callback;
 import org.chromium.base.ContextUtils;
 import org.chromium.base.VisibleForTesting;
-import org.chromium.base.annotations.SuppressFBWarnings;
 import org.chromium.base.metrics.RecordUserAction;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeFeatureList;
@@ -155,7 +154,6 @@
         return new GenericPromoViewHolder(parent, contextMenuManager, config);
     }
 
-    @SuppressFBWarnings("BC_UNCONFIRMED_CAST")
     @Override
     protected void onBindViewHolder(NewTabPageViewHolder holder) {
         assert !mWasDismissed;
@@ -404,7 +402,6 @@
      */
     private static class UpdatePersonalizedSigninPromoCallback
             extends NewTabPageViewHolder.PartialBindCallback {
-        @SuppressFBWarnings("BC_UNCONFIRMED_CAST")
         @Override
         public void onResult(NewTabPageViewHolder result) {
             ((PersonalizedPromoViewHolder) result).updatePersonalizedSigninPromo();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/StatusItem.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/StatusItem.java
index f359a848..963b5cf 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/StatusItem.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/StatusItem.java
@@ -60,7 +60,6 @@
 
     @Override
     protected void onBindViewHolder(NewTabPageViewHolder holder) {
-        assert holder instanceof StatusCardViewHolder;
         ((StatusCardViewHolder) holder).onBindViewHolder(this);
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSection.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSection.java
index 9d70105..40b226b0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSection.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSection.java
@@ -148,7 +148,6 @@
         @Override
         public void onBindViewHolder(NewTabPageViewHolder holder, int position) {
             checkIndex(position);
-            assert holder instanceof SnippetArticleViewHolder;
             SnippetArticle suggestion = getSuggestionAt(position);
             mSuggestionsRanker.rankSuggestion(suggestion);
             ((SnippetArticleViewHolder) holder).onBindViewHolder(suggestion, mCategoryInfo);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SectionHeader.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SectionHeader.java
index 4cad997b..2ce6bb8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SectionHeader.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SectionHeader.java
@@ -33,7 +33,6 @@
 
     @Override
     protected void onBindViewHolder(NewTabPageViewHolder holder) {
-        assert holder instanceof SectionHeaderViewHolder;
         ((SectionHeaderViewHolder) holder).onBindViewHolder(this);
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetArticleViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetArticleViewHolder.java
index 1e2cd035..b5f4abf 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetArticleViewHolder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetArticleViewHolder.java
@@ -225,7 +225,6 @@
     public static class RefreshOfflineBadgeVisibilityCallback extends PartialBindCallback {
         @Override
         public void onResult(NewTabPageViewHolder holder) {
-            assert holder instanceof SnippetArticleViewHolder;
             ((SnippetArticleViewHolder) holder).refreshOfflineBadgeVisibility();
         }
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
index 05dc343..38cf48d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
@@ -1126,7 +1126,6 @@
     public int onSectionOptionSelected(@PaymentRequestUI.DataType int optionType,
             PaymentOption option, Callback<PaymentInformation> callback) {
         if (optionType == PaymentRequestUI.TYPE_SHIPPING_ADDRESSES) {
-            assert option instanceof AutofillAddress;
             // Log the change of shipping address.
             mJourneyLogger.incrementSelectionChanges(Section.SHIPPING_ADDRESS);
             AutofillAddress address = (AutofillAddress) option;
@@ -1145,11 +1144,9 @@
             mPaymentInformationCallback = callback;
             return PaymentRequestUI.SELECTION_RESULT_ASYNCHRONOUS_VALIDATION;
         } else if (optionType == PaymentRequestUI.TYPE_CONTACT_DETAILS) {
-            assert option instanceof AutofillContact;
             // Log the change of contact info.
             mJourneyLogger.incrementSelectionChanges(Section.CONTACT_INFO);
             AutofillContact contact = (AutofillContact) option;
-
             if (contact.isComplete()) {
                 mContactSection.setSelectedItem(option);
             } else {
@@ -1157,9 +1154,9 @@
                 return PaymentRequestUI.SELECTION_RESULT_EDITOR_LAUNCH;
             }
         } else if (optionType == PaymentRequestUI.TYPE_PAYMENT_METHODS) {
-            assert option instanceof PaymentInstrument;
-            if (option instanceof AutofillPaymentInstrument) {
-                AutofillPaymentInstrument card = (AutofillPaymentInstrument) option;
+            PaymentInstrument paymentInstrument = (PaymentInstrument) option;
+            if (paymentInstrument instanceof AutofillPaymentInstrument) {
+                AutofillPaymentInstrument card = (AutofillPaymentInstrument) paymentInstrument;
 
                 if (!card.isComplete()) {
                     editCard(card);
@@ -1169,7 +1166,7 @@
             // Log the change of payment method.
             mJourneyLogger.incrementSelectionChanges(Section.PAYMENT_METHOD);
 
-            updateOrderSummary((PaymentInstrument) option);
+            updateOrderSummary(paymentInstrument);
             mPaymentMethodsSection.setSelectedItem(option);
         }
 
@@ -1181,20 +1178,17 @@
     public int onSectionEditOption(@PaymentRequestUI.DataType int optionType, PaymentOption option,
             Callback<PaymentInformation> callback) {
         if (optionType == PaymentRequestUI.TYPE_SHIPPING_ADDRESSES) {
-            assert option instanceof AutofillAddress;
             editAddress((AutofillAddress) option);
             mPaymentInformationCallback = callback;
             return PaymentRequestUI.SELECTION_RESULT_ASYNCHRONOUS_VALIDATION;
         }
 
         if (optionType == PaymentRequestUI.TYPE_CONTACT_DETAILS) {
-            assert option instanceof AutofillContact;
             editContact((AutofillContact) option);
             return PaymentRequestUI.SELECTION_RESULT_EDITOR_LAUNCH;
         }
 
         if (optionType == PaymentRequestUI.TYPE_PAYMENT_METHODS) {
-            assert option instanceof AutofillPaymentInstrument;
             editCard((AutofillPaymentInstrument) option);
             return PaymentRequestUI.SELECTION_RESULT_EDITOR_LAUNCH;
         }
@@ -1356,7 +1350,6 @@
     @Override
     public boolean onPayClicked(PaymentOption selectedShippingAddress,
             PaymentOption selectedShippingOption, PaymentOption selectedPaymentMethod) {
-        assert selectedPaymentMethod instanceof PaymentInstrument;
         PaymentInstrument instrument = (PaymentInstrument) selectedPaymentMethod;
         mPaymentAppRunning = true;
 
@@ -1778,7 +1771,6 @@
 
         if (mShippingAddressesSection.getSelectedItem() == null) return;
 
-        assert mShippingAddressesSection.getSelectedItem() instanceof AutofillAddress;
         AutofillAddress selectedAddress =
                 (AutofillAddress) mShippingAddressesSection.getSelectedItem();
 
@@ -1851,7 +1843,6 @@
         if (mPaymentMethodsSection != null) {
             for (int i = 0; i < mPaymentMethodsSection.getSize(); i++) {
                 PaymentOption option = mPaymentMethodsSection.getItem(i);
-                assert option instanceof PaymentInstrument;
                 ((PaymentInstrument) option).dismissInstrument();
             }
             mPaymentMethodsSection = null;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentResponseHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentResponseHelper.java
index 220a6a8..9ac3ae1b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentResponseHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentResponseHelper.java
@@ -52,7 +52,6 @@
         if (selectedContact != null) {
             // Contacts are created in PaymentRequestImpl.init(). These should all be instances of
             // AutofillContact.
-            assert selectedContact instanceof AutofillContact;
             mPaymentResponse.payerName = ((AutofillContact) selectedContact).getPayerName();
             mPaymentResponse.payerPhone = ((AutofillContact) selectedContact).getPayerPhone();
             mPaymentResponse.payerEmail = ((AutofillContact) selectedContact).getPayerEmail();
@@ -73,7 +72,6 @@
         if (selectedShippingAddress != null) {
             // Shipping addresses are created in PaymentRequestImpl.init(). These should all be
             // instances of AutofillAddress.
-            assert selectedShippingAddress instanceof AutofillAddress;
             mSelectedShippingAddress = (AutofillAddress) selectedShippingAddress;
 
             // Addresses to be sent to the merchant should always be complete.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/ServiceWorkerPaymentAppBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/ServiceWorkerPaymentAppBridge.java
index c6ec3f9..a2af253 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/ServiceWorkerPaymentAppBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/ServiceWorkerPaymentAppBridge.java
@@ -119,7 +119,6 @@
     private static void onPaymentAppCreated(long registrationId, String scope, String label,
             @Nullable String sublabel, @Nullable Bitmap icon, String[] methodNameArray,
             String[] preferredRelatedApplications, WebContents webContents, Object callback) {
-        assert callback instanceof PaymentAppFactory.PaymentAppCreatedCallback;
         Context context = ChromeActivity.fromWebContents(webContents);
         if (context == null) return;
         URI scopeUri = UriUtils.parseUriFromString(scope);
@@ -136,14 +135,12 @@
 
     @CalledByNative
     private static void onAllPaymentAppsCreated(Object callback) {
-        assert callback instanceof PaymentAppFactory.PaymentAppCreatedCallback;
         ((PaymentAppFactory.PaymentAppCreatedCallback) callback).onAllPaymentAppsCreated();
     }
 
     @CalledByNative
     private static void onPaymentAppInvoked(
             Object callback, String methodName, String stringifiedDetails) {
-        assert callback instanceof PaymentInstrument.InstrumentDetailsCallback;
         if (TextUtils.isEmpty(methodName)) {
             ((PaymentInstrument.InstrumentDetailsCallback) callback).onInstrumentDetailsError();
         } else {
@@ -154,7 +151,6 @@
 
     @CalledByNative
     private static void onPaymentAppAborted(Object callback, boolean result) {
-        assert callback instanceof PaymentInstrument.AbortCallback;
         ((PaymentInstrument.AbortCallback) callback).onInstrumentAbortResult(result);
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/EditorDialog.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/EditorDialog.java
index 1b0f937..e26729c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/EditorDialog.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/EditorDialog.java
@@ -165,7 +165,6 @@
 
     /** Launches the Autofill help page on top of the current Context. */
     public static void launchAutofillHelpPage(Context context) {
-        assert context instanceof Activity;
         HelpAndFeedback.getInstance(context).show((Activity) context,
                 context.getString(R.string.help_context_autofill), Profile.getLastUsedProfile(),
                 null);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/EditorIconsField.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/EditorIconsField.java
index a353769..def641f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/EditorIconsField.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/EditorIconsField.java
@@ -13,7 +13,6 @@
 import android.widget.ImageView;
 import android.widget.TextView;
 
-import org.chromium.base.annotations.SuppressFBWarnings;
 import org.chromium.chrome.R;
 
 import java.util.List;
@@ -84,7 +83,6 @@
             return position;
         }
 
-        @SuppressFBWarnings("BC_UNCONFIRMED_CAST")
         @Override
         public View getView(int position, View convertView, ViewGroup parent) {
             ImageView iconView = (ImageView) convertView;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SiteExplorePageIndicatorView.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SiteExplorePageIndicatorView.java
index 69e799c9..c5d4297 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SiteExplorePageIndicatorView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SiteExplorePageIndicatorView.java
@@ -9,14 +9,12 @@
 import android.support.annotation.Nullable;
 import android.support.v4.view.ViewPager;
 import android.util.AttributeSet;
-import android.util.DisplayMetrics;
-import android.util.TypedValue;
 import android.view.View;
-import android.view.ViewParent;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 
 import org.chromium.chrome.R;
+import org.chromium.chrome.browser.util.ViewUtils;
 
 /**
  * Page indicator view for a {@link ViewPager}. It has to be inserted as a child of the
@@ -63,11 +61,7 @@
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
 
-        final ViewParent parent = getParent();
-        assert parent instanceof ViewPager :
-                "PageIndicatorView must be a direct child of a ViewPager.";
-
-        mViewPager = (ViewPager) parent;
+        mViewPager = (ViewPager) getParent();
 
         mViewPager.addOnPageChangeListener(this);
         mViewPager.getAdapter().registerDataSetObserver(mDataSetObserver);
@@ -92,7 +86,7 @@
 
         removeAllViews();
 
-        int indicatorSideMarginPx = dpToPx(SPACE_BETWEEN_INDICATORS_DP / 2);
+        int indicatorSideMarginPx = ViewUtils.dpToPx(getContext(), SPACE_BETWEEN_INDICATORS_DP / 2);
         for (int i = 0; i < numberOfPages; i++) {
             ImageView singlePageIndicatorView = new ImageView(getContext());
 
@@ -113,9 +107,4 @@
         }
     }
 
-    private int dpToPx(int dp) {
-        DisplayMetrics metrics = getResources().getDisplayMetrics();
-        return Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, metrics));
-    }
-
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SiteSection.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SiteSection.java
index 12df1eda27..9f4c761 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SiteSection.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SiteSection.java
@@ -79,8 +79,6 @@
 
     @Override
     protected void onBindViewHolder(NewTabPageViewHolder holder) {
-        assert holder instanceof SiteSectionViewHolder;
-
         SiteSectionViewHolder siteSectionView = (SiteSectionViewHolder) holder;
         siteSectionView.bindDataSource(mTileGroup, mTileRenderer);
         siteSectionView.refreshData();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SiteSectionViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SiteSectionViewHolder.java
index da9fa919b..c5076af 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SiteSectionViewHolder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SiteSectionViewHolder.java
@@ -65,7 +65,6 @@
     public static class UpdateTilesCallback extends PartialBindCallback {
         @Override
         public void onResult(NewTabPageViewHolder holder) {
-            assert holder instanceof SiteSectionViewHolder;
             ((SiteSectionViewHolder) holder).refreshData();
         }
     }
@@ -82,7 +81,6 @@
 
         @Override
         public void onResult(NewTabPageViewHolder holder) {
-            assert holder instanceof SiteSectionViewHolder;
             ((SiteSectionViewHolder) holder).updateIconView(mTile);
         }
     }
@@ -99,7 +97,6 @@
 
         @Override
         public void onResult(NewTabPageViewHolder holder) {
-            assert holder instanceof SiteSectionViewHolder;
             ((SiteSectionViewHolder) holder).updateOfflineBadge(mTile);
         }
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsCarousel.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsCarousel.java
index e1a5b35..cd60cc6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsCarousel.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsCarousel.java
@@ -42,8 +42,6 @@
 
     @Override
     protected void onBindViewHolder(NewTabPageViewHolder holder) {
-        assert holder.itemView instanceof RecyclerView;
-
         ((RecyclerView) holder.itemView).setAdapter(mAdapter);
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsRecyclerView.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsRecyclerView.java
index 68382f7a..06a3301 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsRecyclerView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsRecyclerView.java
@@ -385,8 +385,6 @@
 
         @Override
         public int getMovementFlags(RecyclerView recyclerView, ViewHolder viewHolder) {
-            assert viewHolder instanceof NewTabPageViewHolder;
-
             int swipeFlags = 0;
             if (((NewTabPageViewHolder) viewHolder).isDismissable()) {
                 swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
@@ -431,7 +429,6 @@
     private static class ResetForDismissCallback extends NewTabPageViewHolder.PartialBindCallback {
         @Override
         public void onResult(NewTabPageViewHolder holder) {
-            assert holder instanceof CardViewHolder;
             ((CardViewHolder) holder).getRecyclerView().updateViewStateForDismiss(0, holder);
         }
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/util/ViewUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/util/ViewUtils.java
index afd81ad..486c675 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/util/ViewUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/util/ViewUtils.java
@@ -4,9 +4,12 @@
 
 package org.chromium.chrome.browser.util;
 
+import android.content.Context;
 import android.graphics.Canvas;
 import android.graphics.Region;
 import android.support.annotation.DrawableRes;
+import android.util.DisplayMetrics;
+import android.util.TypedValue;
 import android.view.View;
 import android.view.ViewGroup;
 
@@ -124,4 +127,26 @@
         view.setBackgroundResource(resource);
         view.setPadding(left, top, right, bottom);
     }
+
+    /**
+     *  Converts density-independent pixels (dp) to pixels on the screen (px).
+     *
+     *  @param dp Density-independent pixels are based on the physical density of the screen.
+     *  @return   The physical pixels on the screen which correspond to this many
+     *            density-independent pixels for this screen.
+     */
+    public static int dpToPx(Context context, float dp) {
+        return dpToPx(context.getResources().getDisplayMetrics(), dp);
+    }
+
+    /**
+     *  Converts density-independent pixels (dp) to pixels on the screen (px).
+     *
+     *  @param dp Density-independent pixels are based on the physical density of the screen.
+     *  @return   The physical pixels on the screen which correspond to this many
+     *            density-independent pixels for this screen.
+     */
+    public static int dpToPx(DisplayMetrics metrics, float dp) {
+        return Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, metrics));
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java
index ea984a0..78f29483 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java
@@ -1262,15 +1262,15 @@
 
     /* package */ void exitCct() {
         if (mShowingDaydreamDoff) return;
-        assert mActivity instanceof CustomTabActivity;
+        CustomTabActivity customTabActivity = (CustomTabActivity) mActivity;
         if (mAutopresentWebVr || (mInVrAtChromeLaunch != null && mInVrAtChromeLaunch)) {
-            ((CustomTabActivity) mActivity).finishAndClose(false);
+            customTabActivity.finishAndClose(false);
             return;
         }
         if (showDoff(true /* optional */)) {
             mExitingCct = true;
         } else {
-            ((CustomTabActivity) mActivity).finishAndClose(false);
+            customTabActivity.finishAndClose(false);
         }
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/ImageViewTinter.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/ImageViewTinter.java
index 17518f0d..1a2d5ec 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/ImageViewTinter.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/ImageViewTinter.java
@@ -50,7 +50,6 @@
      * @param defStyle Style that is pulled in from an XML layout.
      */
     public ImageViewTinter(ImageViewTinterOwner view, @Nullable AttributeSet attrs, int defStyle) {
-        assert view instanceof ImageView;
         mImageView = (ImageView) view;
 
         // Parse out the attributes from the XML.
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
index 277588a..c4b9b2a 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
@@ -61,6 +61,7 @@
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.library_loader.LibraryLoader;
 import org.chromium.base.library_loader.LibraryProcessType;
+import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.test.util.CallbackHelper;
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.DisabledTest;
@@ -112,6 +113,8 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.Callable;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicReference;
@@ -128,6 +131,7 @@
     @Rule
     public CustomTabActivityTestRule mCustomTabActivityTestRule = new CustomTabActivityTestRule();
 
+    private static final int TIMEOUT_PAGE_LOAD_SECONDS = 10;
     private static final int MAX_MENU_CUSTOM_ITEMS = 5;
     private static final int NUM_CHROME_MENU_ITEMS = 5;
     private static final String TEST_PAGE = "/chrome/test/data/android/google.html";
@@ -1124,13 +1128,19 @@
      */
     @Test
     @SmallTest
-    @RetryOnFailure
     public void testCallbacksAreSent() {
-        final ArrayList<Integer> navigationEvents = new ArrayList<>();
+        final Semaphore navigationStartSemaphore = new Semaphore(0);
+        final Semaphore navigationFinishedSemaphore = new Semaphore(0);
         CustomTabsSession session = bindWithCallback(new CustomTabsCallback() {
             @Override
             public void onNavigationEvent(int navigationEvent, Bundle extras) {
-                navigationEvents.add(navigationEvent);
+                Assert.assertNotEquals(CustomTabsCallback.NAVIGATION_FAILED, navigationEvent);
+                Assert.assertNotEquals(CustomTabsCallback.NAVIGATION_ABORTED, navigationEvent);
+                if (navigationEvent == CustomTabsCallback.NAVIGATION_STARTED) {
+                    navigationStartSemaphore.release();
+                } else if (navigationEvent == CustomTabsCallback.NAVIGATION_FINISHED) {
+                    navigationFinishedSemaphore.release();
+                }
             }
         });
         Intent intent = new CustomTabsIntent.Builder(session).build().intent;
@@ -1142,23 +1152,13 @@
 
         try {
             mCustomTabActivityTestRule.startCustomTabActivityWithIntent(intent);
-            CriteriaHelper.pollInstrumentationThread(new Criteria() {
-                @Override
-                public boolean isSatisfied() {
-                    return navigationEvents.contains(CustomTabsCallback.NAVIGATION_STARTED);
-                }
-            });
-            CriteriaHelper.pollInstrumentationThread(new Criteria() {
-                @Override
-                public boolean isSatisfied() {
-                    return navigationEvents.contains(CustomTabsCallback.NAVIGATION_FINISHED);
-                }
-            });
+            Assert.assertTrue(navigationStartSemaphore.tryAcquire(
+                    TIMEOUT_PAGE_LOAD_SECONDS, TimeUnit.SECONDS));
+            Assert.assertTrue(navigationFinishedSemaphore.tryAcquire(
+                    TIMEOUT_PAGE_LOAD_SECONDS, TimeUnit.SECONDS));
         } catch (InterruptedException e) {
             Assert.fail();
         }
-        Assert.assertFalse(navigationEvents.contains(CustomTabsCallback.NAVIGATION_FAILED));
-        Assert.assertFalse(navigationEvents.contains(CustomTabsCallback.NAVIGATION_ABORTED));
     }
 
     /**
@@ -1226,6 +1226,45 @@
     }
 
     /**
+     * Tests that one navigation in a custom tab records the histograms reflecting time from
+     * intent to first navigation commit.
+     */
+    @Test
+    @SmallTest
+    public void testNavigationCommitUmaRecorded() {
+        String zoomedOutHistogramName = "CustomTabs.IntentToFirstCommitNavigationTime3.ZoomedOut";
+        String zoomedInHistogramName = "CustomTabs.IntentToFirstCommitNavigationTime3.ZoomedIn";
+        Assert.assertEquals(
+                0, RecordHistogram.getHistogramTotalCountForTesting(zoomedOutHistogramName));
+        Assert.assertEquals(
+                0, RecordHistogram.getHistogramTotalCountForTesting(zoomedInHistogramName));
+        final Semaphore semaphore = new Semaphore(0);
+        CustomTabsSession session = bindWithCallback(new CustomTabsCallback() {
+            @Override
+            public void onNavigationEvent(int navigationEvent, Bundle extras) {
+                if (navigationEvent == CustomTabsCallback.NAVIGATION_FINISHED) semaphore.release();
+            }
+        });
+        Intent intent = new CustomTabsIntent.Builder(session).build().intent;
+        intent.setData(Uri.parse(mTestPage));
+        intent.setComponent(
+                new ComponentName(InstrumentationRegistry.getInstrumentation().getTargetContext(),
+                        ChromeLauncherActivity.class));
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+        try {
+            mCustomTabActivityTestRule.startCustomTabActivityWithIntent(intent);
+            Assert.assertTrue(semaphore.tryAcquire(TIMEOUT_PAGE_LOAD_SECONDS, TimeUnit.SECONDS));
+        } catch (InterruptedException e) {
+            Assert.fail();
+        }
+        Assert.assertEquals(
+                1, RecordHistogram.getHistogramTotalCountForTesting(zoomedOutHistogramName));
+        Assert.assertEquals(
+                1, RecordHistogram.getHistogramTotalCountForTesting(zoomedInHistogramName));
+    }
+
+    /**
      * Tests that TITLE_ONLY state works as expected with a title getting set onload.
      */
     @Test
diff --git a/chrome/browser/android/chrome_feature_list.cc b/chrome/browser/android/chrome_feature_list.cc
index 3f9de63..e3be4a9 100644
--- a/chrome/browser/android/chrome_feature_list.cc
+++ b/chrome/browser/android/chrome_feature_list.cc
@@ -213,7 +213,7 @@
     "DownloadHomeShowStorageInfo", base::FEATURE_DISABLED_BY_DEFAULT};
 
 const base::Feature kFullscreenActivity{"FullscreenActivity",
-                                        base::FEATURE_ENABLED_BY_DEFAULT};
+                                        base::FEATURE_DISABLED_BY_DEFAULT};
 
 // Makes "Add to Home screen" in the app menu generate an APK for the shortcut
 // URL which opens Chrome in fullscreen.
diff --git a/chrome/browser/chromeos/accessibility/accessibility_manager.cc b/chrome/browser/chromeos/accessibility/accessibility_manager.cc
index fb65bd0..6b0e23f 100644
--- a/chrome/browser/chromeos/accessibility/accessibility_manager.cc
+++ b/chrome/browser/chromeos/accessibility/accessibility_manager.cc
@@ -158,17 +158,6 @@
     ash::AccessibilityNotificationVisibility notify)
     : notification_type(notification_type),
       enabled(enabled),
-      magnifier_type(ash::kDefaultMagnifierType),
-      notify(notify) {}
-
-AccessibilityStatusEventDetails::AccessibilityStatusEventDetails(
-    AccessibilityNotificationType notification_type,
-    bool enabled,
-    ash::MagnifierType magnifier_type,
-    ash::AccessibilityNotificationVisibility notify)
-    : notification_type(notification_type),
-      enabled(enabled),
-      magnifier_type(magnifier_type),
       notify(notify) {}
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -1383,12 +1372,8 @@
                         IsVirtualKeyboardEnabled());
   UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosStickyKeys", IsStickyKeysEnabled());
   if (MagnificationManager::Get()) {
-    uint32_t type = MagnificationManager::Get()->IsMagnifierEnabled()
-                        ? MagnificationManager::Get()->GetMagnifierType()
-                        : 0;
-    // '0' means magnifier is disabled.
-    UMA_HISTOGRAM_ENUMERATION("Accessibility.CrosScreenMagnifier", type,
-                              ash::kMaxMagnifierType + 1);
+    UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosScreenMagnifier",
+                          MagnificationManager::Get()->IsMagnifierEnabled());
   }
   if (profile_) {
     const PrefService* const prefs = profile_->GetPrefs();
diff --git a/chrome/browser/chromeos/accessibility/accessibility_manager.h b/chrome/browser/chromeos/accessibility/accessibility_manager.h
index 5ce3d4d8..e390440 100644
--- a/chrome/browser/chromeos/accessibility/accessibility_manager.h
+++ b/chrome/browser/chromeos/accessibility/accessibility_manager.h
@@ -62,15 +62,8 @@
       bool enabled,
       ash::AccessibilityNotificationVisibility notify);
 
-  AccessibilityStatusEventDetails(
-      AccessibilityNotificationType notification_type,
-      bool enabled,
-      ash::MagnifierType magnifier_type,
-      ash::AccessibilityNotificationVisibility notify);
-
   AccessibilityNotificationType notification_type;
   bool enabled;
-  ash::MagnifierType magnifier_type;
   ash::AccessibilityNotificationVisibility notify;
 };
 
diff --git a/chrome/browser/chromeos/accessibility/magnification_manager.cc b/chrome/browser/chromeos/accessibility/magnification_manager.cc
index 613159a3..4ad04c5 100644
--- a/chrome/browser/chromeos/accessibility/magnification_manager.cc
+++ b/chrome/browser/chromeos/accessibility/magnification_manager.cc
@@ -44,11 +44,8 @@
       : profile_(NULL),
         magnifier_enabled_pref_handler_(
             ash::prefs::kAccessibilityScreenMagnifierEnabled),
-        magnifier_type_pref_handler_(
-            ash::prefs::kAccessibilityScreenMagnifierType),
         magnifier_scale_pref_handler_(
             ash::prefs::kAccessibilityScreenMagnifierScale),
-        type_(ash::kDefaultMagnifierType),
         enabled_(false),
         keep_focus_centered_(false),
         observing_focus_change_in_page_(false) {
@@ -70,8 +67,6 @@
   // MagnificationManager implimentation:
   bool IsMagnifierEnabled() const override { return enabled_; }
 
-  ash::MagnifierType GetMagnifierType() const override { return type_; }
-
   void SetMagnifierEnabled(bool enabled) override {
     if (!profile_)
       return;
@@ -82,15 +77,6 @@
     prefs->CommitPendingWrite();
   }
 
-  void SetMagnifierType(ash::MagnifierType type) override {
-    if (!profile_)
-      return;
-
-    PrefService* prefs = profile_->GetPrefs();
-    prefs->SetInteger(ash::prefs::kAccessibilityScreenMagnifierType, type);
-    prefs->CommitPendingWrite();
-  }
-
   void SaveScreenMagnifierScale(double scale) override {
     if (!profile_)
       return;
@@ -128,17 +114,12 @@
           base::Bind(&MagnificationManagerImpl::UpdateMagnifierFromPrefs,
                      base::Unretained(this)));
       pref_change_registrar_->Add(
-          ash::prefs::kAccessibilityScreenMagnifierType,
-          base::Bind(&MagnificationManagerImpl::UpdateMagnifierFromPrefs,
-                     base::Unretained(this)));
-      pref_change_registrar_->Add(
           ash::prefs::kAccessibilityScreenMagnifierCenterFocus,
           base::Bind(&MagnificationManagerImpl::UpdateMagnifierFromPrefs,
                      base::Unretained(this)));
     }
 
     magnifier_enabled_pref_handler_.HandleProfileChanged(profile_, profile);
-    magnifier_type_pref_handler_.HandleProfileChanged(profile_, profile);
     magnifier_scale_pref_handler_.HandleProfileChanged(profile_, profile);
 
     profile_ = profile;
@@ -156,20 +137,8 @@
 
     enabled_ = enabled;
 
-    if (type_ == ash::MAGNIFIER_FULL) {
-      ash::Shell::Get()->magnification_controller()->SetEnabled(enabled_);
-      MonitorFocusInPageChange();
-    } else {
-      ash::Shell::Get()->partial_magnification_controller()->SetEnabled(
-          enabled_);
-    }
-  }
-
-  virtual void SetMagnifierTypeInternal(ash::MagnifierType type) {
-    if (type_ == type)
-      return;
-
-    type_ = ash::MAGNIFIER_FULL;  // (leave out for full magnifier)
+    ash::Shell::Get()->magnification_controller()->SetEnabled(enabled_);
+    MonitorFocusInPageChange();
   }
 
   virtual void SetMagniferKeepFocusCenteredInternal(bool keep_focus_centered) {
@@ -178,10 +147,8 @@
 
     keep_focus_centered_ = keep_focus_centered;
 
-    if (type_ == ash::MAGNIFIER_FULL) {
       ash::Shell::Get()->magnification_controller()->SetKeepFocusCentered(
           keep_focus_centered_);
-    }
   }
 
   void UpdateMagnifierFromPrefs() {
@@ -190,34 +157,19 @@
 
     const bool enabled = profile_->GetPrefs()->GetBoolean(
         ash::prefs::kAccessibilityScreenMagnifierEnabled);
-    const int type_integer = profile_->GetPrefs()->GetInteger(
-        ash::prefs::kAccessibilityScreenMagnifierType);
     const bool keep_focus_centered = profile_->GetPrefs()->GetBoolean(
         ash::prefs::kAccessibilityScreenMagnifierCenterFocus);
 
-    ash::MagnifierType type = ash::kDefaultMagnifierType;
-    if (type_integer > 0 && type_integer <= ash::kMaxMagnifierType) {
-      type = static_cast<ash::MagnifierType>(type_integer);
-    } else if (type_integer == 0) {
-      // Type 0 is used to disable the screen magnifier through policy. As the
-      // magnifier type is irrelevant in this case, it is OK to just fall back
-      // to the default.
-    } else {
-      NOTREACHED();
-    }
-
     if (!enabled) {
       SetMagnifierEnabledInternal(enabled);
-      SetMagnifierTypeInternal(type);
       SetMagniferKeepFocusCenteredInternal(keep_focus_centered);
     } else {
       SetMagniferKeepFocusCenteredInternal(keep_focus_centered);
-      SetMagnifierTypeInternal(type);
       SetMagnifierEnabledInternal(enabled);
     }
 
     AccessibilityStatusEventDetails details(
-        ACCESSIBILITY_TOGGLE_SCREEN_MAGNIFIER, enabled_, type_,
+        ACCESSIBILITY_TOGGLE_SCREEN_MAGNIFIER, enabled_,
         ash::A11Y_NOTIFICATION_NONE);
 
     if (AccessibilityManager::Get()) {
@@ -283,10 +235,8 @@
   Profile* profile_;
 
   AccessibilityManager::PrefHandler magnifier_enabled_pref_handler_;
-  AccessibilityManager::PrefHandler magnifier_type_pref_handler_;
   AccessibilityManager::PrefHandler magnifier_scale_pref_handler_;
 
-  ash::MagnifierType type_;
   bool enabled_;
   bool keep_focus_centered_;
   bool observing_focus_change_in_page_;
diff --git a/chrome/browser/chromeos/accessibility/magnification_manager.h b/chrome/browser/chromeos/accessibility/magnification_manager.h
index bec48e1..ede8a4f1 100644
--- a/chrome/browser/chromeos/accessibility/magnification_manager.h
+++ b/chrome/browser/chromeos/accessibility/magnification_manager.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_CHROMEOS_ACCESSIBILITY_MAGNIFICATION_MANAGER_H_
 #define CHROME_BROWSER_CHROMEOS_ACCESSIBILITY_MAGNIFICATION_MANAGER_H_
 
-#include "ash/accessibility_types.h"
 #include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
 
 class Profile;
@@ -20,12 +19,9 @@
 //     desktop.
 //   - Watch change of the pref. When the pref changes, the setting of the
 //     magnifier will interlock with it.
-
 class MagnificationManager {
  public:
-  // Creates an instance of MagnificationManager. This should be called once,
-  // Returns the existing instance. If there is no instance, creates one.
-  // because only one instance should exist at the same time.
+  // Creates an instance of MagnificationManager. This should be called once.
   static void Initialize();
 
   // Deletes the existing instance of MagnificationManager.
@@ -37,15 +33,9 @@
   // Returns if the screen magnifier is enabled.
   virtual bool IsMagnifierEnabled() const = 0;
 
-  // Returns the current type of the screen magnifier.
-  virtual ash::MagnifierType GetMagnifierType() const = 0;
-
   // Enables the screen magnifier.
   virtual void SetMagnifierEnabled(bool enabled) = 0;
 
-  // Changes the type of the screen magnifier.
-  virtual void SetMagnifierType(ash::MagnifierType type) = 0;
-
   // Saves the magnifier scale to the pref.
   virtual void SaveScreenMagnifierScale(double scale) = 0;
 
diff --git a/chrome/browser/chromeos/accessibility/magnification_manager_browsertest.cc b/chrome/browser/chromeos/accessibility/magnification_manager_browsertest.cc
index 482c7b8..3dcfee8 100644
--- a/chrome/browser/chromeos/accessibility/magnification_manager_browsertest.cc
+++ b/chrome/browser/chromeos/accessibility/magnification_manager_browsertest.cc
@@ -39,10 +39,6 @@
   MagnificationManager::Get()->SetMagnifierEnabled(enabled);
 }
 
-void SetMagnifierType(ash::MagnifierType type) {
-  MagnificationManager::Get()->SetMagnifierType(type);
-}
-
 void SetFullScreenMagnifierScale(double scale) {
   ash::Shell::Get()->magnification_controller()->SetScale(scale, false);
 }
@@ -59,10 +55,6 @@
   return MagnificationManager::Get()->GetSavedScreenMagnifierScale();
 }
 
-ash::MagnifierType GetMagnifierType() {
-  return MagnificationManager::Get()->GetMagnifierType();
-}
-
 bool IsMagnifierEnabled() {
   return MagnificationManager::Get()->IsMagnifierEnabled();
 }
@@ -122,10 +114,7 @@
 
 class MockMagnificationObserver {
  public:
-  MockMagnificationObserver() : observed_(false),
-                                observed_enabled_(false),
-                                magnifier_type_(-1)
-  {
+  MockMagnificationObserver() {
     AccessibilityManager* accessibility_manager = AccessibilityManager::Get();
     CHECK(accessibility_manager);
     accessibility_subscription_ = accessibility_manager->RegisterCallback(
@@ -137,7 +126,6 @@
 
   bool observed() const { return observed_; }
   bool observed_enabled() const { return observed_enabled_; }
-  int magnifier_type() const { return magnifier_type_; }
 
   void reset() { observed_ = false; }
 
@@ -145,15 +133,13 @@
   void OnAccessibilityStatusChanged(
       const AccessibilityStatusEventDetails& details) {
     if (details.notification_type == ACCESSIBILITY_TOGGLE_SCREEN_MAGNIFIER) {
-      magnifier_type_ = details.magnifier_type;
       observed_enabled_ = details.enabled;
       observed_ = true;
     }
   }
 
-  bool observed_;
-  bool observed_enabled_;
-  int magnifier_type_;
+  bool observed_ = false;
+  bool observed_enabled_ = false;
 
   std::unique_ptr<AccessibilityStatusSubscription> accessibility_subscription_;
 
@@ -215,7 +201,6 @@
   SetMagnifierEnabled(true);
   // Confirms that magnifier is enabled.
   EXPECT_TRUE(IsMagnifierEnabled());
-  EXPECT_EQ(ash::MAGNIFIER_FULL, GetMagnifierType());
   EXPECT_TRUE(GetScreenMagnifierEnabledFromPref());
 }
 
@@ -233,10 +218,8 @@
 
   // Enables magnifier on login screen.
   SetMagnifierEnabled(true);
-  SetMagnifierType(ash::MAGNIFIER_FULL);
   SetFullScreenMagnifierScale(2.5);
   EXPECT_TRUE(IsMagnifierEnabled());
-  EXPECT_EQ(ash::MAGNIFIER_FULL, GetMagnifierType());
   EXPECT_EQ(2.5, GetFullScreenMagnifierScale());
 
   // Logs in (but the session is not started yet).
@@ -245,7 +228,6 @@
 
   // Confirms that magnifier is keeping enabled.
   EXPECT_TRUE(IsMagnifierEnabled());
-  EXPECT_EQ(ash::MAGNIFIER_FULL, GetMagnifierType());
 
   StartUserSession(test_account_id_);
 
@@ -281,7 +263,6 @@
   // Confirms that the magnifier is enabled and configured according to the
   // explicitly set prefs just after session start.
   EXPECT_TRUE(IsMagnifierEnabled());
-  EXPECT_EQ(ash::MAGNIFIER_FULL, GetMagnifierType());
   EXPECT_EQ(2.5, GetFullScreenMagnifierScale());
   EXPECT_TRUE(GetScreenMagnifierEnabledFromPref());
 }
@@ -298,11 +279,9 @@
 
 IN_PROC_BROWSER_TEST_F(MagnificationManagerTest, LoginFullToFull) {
   // Enables magnifier on login screen.
-  SetMagnifierType(ash::MAGNIFIER_FULL);
   SetMagnifierEnabled(true);
   SetFullScreenMagnifierScale(3.0);
   EXPECT_TRUE(IsMagnifierEnabled());
-  EXPECT_EQ(ash::MAGNIFIER_FULL, GetMagnifierType());
   EXPECT_EQ(3.0, GetFullScreenMagnifierScale());
 
   // Logs in (but the session is not started yet).
@@ -311,14 +290,12 @@
 
   // Confirms that magnifier is keeping enabled.
   EXPECT_TRUE(IsMagnifierEnabled());
-  EXPECT_EQ(ash::MAGNIFIER_FULL, GetMagnifierType());
 
   StartUserSession(test_account_id_);
 
   // Confirms that the magnifier is enabled and configured according to the
   // explicitly set prefs just after session start.
   EXPECT_TRUE(IsMagnifierEnabled());
-  EXPECT_EQ(ash::MAGNIFIER_FULL, GetMagnifierType());
   EXPECT_EQ(2.5, GetFullScreenMagnifierScale());
   EXPECT_TRUE(GetScreenMagnifierEnabledFromPref());
 }
@@ -330,10 +307,8 @@
 
 IN_PROC_BROWSER_TEST_F(MagnificationManagerTest, LoginFullToUnset) {
   // Enables full screen magnifier.
-  SetMagnifierType(ash::MAGNIFIER_FULL);
   SetMagnifierEnabled(true);
   EXPECT_TRUE(IsMagnifierEnabled());
-  EXPECT_EQ(ash::MAGNIFIER_FULL, GetMagnifierType());
 
   // Logs in (but the session is not started yet).
   session_manager::SessionManager::Get()->CreateSession(test_account_id_,
@@ -341,7 +316,6 @@
 
   // Confirms that magnifier is keeping enabled.
   EXPECT_TRUE(IsMagnifierEnabled());
-  EXPECT_EQ(ash::MAGNIFIER_FULL, GetMagnifierType());
 
   StartUserSession(test_account_id_);
 
@@ -373,11 +347,9 @@
 
 IN_PROC_BROWSER_TEST_F(MagnificationManagerTest, LoginAsNewUserFull) {
   // Enables magnifier on login screen.
-  SetMagnifierType(ash::MAGNIFIER_FULL);
   SetMagnifierEnabled(true);
   SetFullScreenMagnifierScale(2.5);
   EXPECT_TRUE(IsMagnifierEnabled());
-  EXPECT_EQ(ash::MAGNIFIER_FULL, GetMagnifierType());
   EXPECT_EQ(2.5, GetFullScreenMagnifierScale());
 
   // Logs in (but the session is not started yet).
@@ -386,13 +358,11 @@
 
   // Confirms that magnifier is keeping enabled.
   EXPECT_TRUE(IsMagnifierEnabled());
-  EXPECT_EQ(ash::MAGNIFIER_FULL, GetMagnifierType());
 
   StartUserSession(test_account_id_);
 
   // Confirms that magnifier keeps enabled.
   EXPECT_TRUE(IsMagnifierEnabled());
-  EXPECT_EQ(ash::MAGNIFIER_FULL, GetMagnifierType());
   EXPECT_EQ(2.5, GetFullScreenMagnifierScale());
   EXPECT_TRUE(GetScreenMagnifierEnabledFromPref());
 }
@@ -415,63 +385,6 @@
   EXPECT_FALSE(GetScreenMagnifierEnabledFromPref());
 }
 
-IN_PROC_BROWSER_TEST_F(MagnificationManagerTest, ChangeMagnifierType) {
-  // Enables/disables full screen magnifier.
-  SetMagnifierEnabled(false);
-  SetMagnifierType(ash::MAGNIFIER_FULL);
-  EXPECT_FALSE(IsMagnifierEnabled());
-  EXPECT_EQ(ash::MAGNIFIER_FULL, GetMagnifierType());
-
-  SetMagnifierEnabled(true);
-  EXPECT_TRUE(IsMagnifierEnabled());
-  EXPECT_EQ(ash::MAGNIFIER_FULL, GetMagnifierType());
-
-  SetMagnifierEnabled(false);
-  EXPECT_FALSE(IsMagnifierEnabled());
-  EXPECT_EQ(ash::MAGNIFIER_FULL, GetMagnifierType());
-
-  // Enables/disables partial screen magnifier.
-  SetMagnifierType(ash::MAGNIFIER_PARTIAL);
-  EXPECT_FALSE(IsMagnifierEnabled());
-  EXPECT_EQ(ash::MAGNIFIER_FULL, GetMagnifierType());
-
-  SetMagnifierEnabled(true);
-  EXPECT_TRUE(IsMagnifierEnabled());
-  EXPECT_EQ(ash::MAGNIFIER_FULL, GetMagnifierType());
-
-  SetMagnifierEnabled(false);
-  EXPECT_FALSE(IsMagnifierEnabled());
-  EXPECT_EQ(ash::MAGNIFIER_FULL, GetMagnifierType());
-
-  // Changes the magnifier type when the magnifier is enabled.
-  SetMagnifierType(ash::MAGNIFIER_FULL);
-  SetMagnifierEnabled(true);
-  EXPECT_TRUE(IsMagnifierEnabled());
-  EXPECT_EQ(ash::MAGNIFIER_FULL, GetMagnifierType());
-
-  SetMagnifierType(ash::MAGNIFIER_PARTIAL);
-  EXPECT_TRUE(IsMagnifierEnabled());
-  EXPECT_EQ(ash::MAGNIFIER_FULL, GetMagnifierType());
-
-  SetMagnifierType(ash::MAGNIFIER_FULL);
-  EXPECT_TRUE(IsMagnifierEnabled());
-  EXPECT_EQ(ash::MAGNIFIER_FULL, GetMagnifierType());
-
-  // Changes the magnifier type when the magnifier is disabled.
-  SetMagnifierEnabled(false);
-  SetMagnifierType(ash::MAGNIFIER_FULL);
-  EXPECT_FALSE(IsMagnifierEnabled());
-  EXPECT_EQ(ash::MAGNIFIER_FULL, GetMagnifierType());
-
-  SetMagnifierType(ash::MAGNIFIER_PARTIAL);
-  EXPECT_FALSE(IsMagnifierEnabled());
-  EXPECT_EQ(ash::MAGNIFIER_FULL, GetMagnifierType());
-
-  SetMagnifierType(ash::MAGNIFIER_FULL);
-  EXPECT_FALSE(IsMagnifierEnabled());
-  EXPECT_EQ(ash::MAGNIFIER_FULL, GetMagnifierType());
-}
-
 IN_PROC_BROWSER_TEST_F(MagnificationManagerTest, TypePref) {
   // Logs in
   session_manager::SessionManager::Get()->CreateSession(test_account_id_,
@@ -486,7 +399,6 @@
   SetScreenMagnifierEnabledPref(true);
   // Confirms that magnifier is enabled.
   EXPECT_TRUE(IsMagnifierEnabled());
-  EXPECT_EQ(ash::MAGNIFIER_FULL, GetMagnifierType());
 }
 
 IN_PROC_BROWSER_TEST_F(MagnificationManagerTest, ScalePref) {
@@ -497,10 +409,8 @@
   SetSavedFullScreenMagnifierScale(2.5);
 
   // Enables full screen magnifier.
-  SetMagnifierType(ash::MAGNIFIER_FULL);
   SetMagnifierEnabled(true);
   EXPECT_TRUE(IsMagnifierEnabled());
-  EXPECT_EQ(ash::MAGNIFIER_FULL, GetMagnifierType());
 
   // Confirms that 2.5x is restored.
   EXPECT_EQ(2.5, GetFullScreenMagnifierScale());
@@ -519,10 +429,8 @@
   SetSavedFullScreenMagnifierScale(0.5);
 
   // Enables full screen magnifier.
-  SetMagnifierType(ash::MAGNIFIER_FULL);
   SetMagnifierEnabled(true);
   EXPECT_TRUE(IsMagnifierEnabled());
-  EXPECT_EQ(ash::MAGNIFIER_FULL, GetMagnifierType());
 
   // Confirms that the actual scale is set to the minimum scale.
   EXPECT_EQ(1.0, GetFullScreenMagnifierScale());
@@ -537,31 +445,25 @@
   // Enables full screen magnifier.
   SetMagnifierEnabled(true);
   EXPECT_TRUE(IsMagnifierEnabled());
-  EXPECT_EQ(ash::MAGNIFIER_FULL, GetMagnifierType());
 
   // Confirms that the actual scale is set to the maximum scale.
   EXPECT_EQ(4.0, GetFullScreenMagnifierScale());
 }
 
-IN_PROC_BROWSER_TEST_F(MagnificationManagerTest,
-                       ChangingTypeInvokesNotification) {
+IN_PROC_BROWSER_TEST_F(MagnificationManagerTest, MagnificationObserver) {
   MockMagnificationObserver observer;
 
   EXPECT_FALSE(observer.observed());
 
   // Set full screen magnifier, and confirm the observer is called.
   SetMagnifierEnabled(true);
-  SetMagnifierType(ash::MAGNIFIER_FULL);
   EXPECT_TRUE(observer.observed());
   EXPECT_TRUE(observer.observed_enabled());
-  EXPECT_EQ(observer.magnifier_type(), ash::MAGNIFIER_FULL);
-  EXPECT_EQ(GetMagnifierType(), ash::MAGNIFIER_FULL);
   observer.reset();
 
   // Set full screen magnifier again, and confirm the observer is not called.
-  SetMagnifierType(ash::MAGNIFIER_FULL);
+  SetMagnifierEnabled(true);
   EXPECT_FALSE(observer.observed());
-  EXPECT_EQ(GetMagnifierType(), ash::MAGNIFIER_FULL);
   observer.reset();
 }
 
diff --git a/chrome/browser/chromeos/accessibility/magnification_manager_unittest.cc b/chrome/browser/chromeos/accessibility/magnification_manager_unittest.cc
index 7bd33f6..fc301feb 100644
--- a/chrome/browser/chromeos/accessibility/magnification_manager_unittest.cc
+++ b/chrome/browser/chromeos/accessibility/magnification_manager_unittest.cc
@@ -25,20 +25,12 @@
   return MagnificationManager::Get()->IsMagnifierEnabled();
 }
 
-ash::MagnifierType GetMagnifierType() {
-  return MagnificationManager::Get()->GetMagnifierType();
-}
-
-void SetMagnifierType(ash::MagnifierType type) {
-  return MagnificationManager::Get()->SetMagnifierType(type);
-}
-
 }  // namespace
 
 class MagnificationManagerTest : public ash::AshTestBase {
  public:
-  MagnificationManagerTest() {
-  }
+  MagnificationManagerTest() = default;
+  ~MagnificationManagerTest() override = default;
 
   void SetUp() override {
     ash::AshTestBase::SetUp();
@@ -55,22 +47,14 @@
   TestingProfile profile_;
 };
 
-TEST_F(MagnificationManagerTest, ChangeType) {
+TEST_F(MagnificationManagerTest, EnableDisable) {
   // Set full screen magnifier, and confirm the status is set successfully.
   EnableMagnifier();
-  SetMagnifierType(ash::MAGNIFIER_FULL);
   EXPECT_TRUE(IsMagnifierEnabled());
-  EXPECT_EQ(GetMagnifierType(), ash::MAGNIFIER_FULL);
-
-  // Set partial screen magnifier, and confirm the change is ignored.
-  SetMagnifierType(ash::MAGNIFIER_PARTIAL);
-  EXPECT_TRUE(IsMagnifierEnabled());
-  EXPECT_EQ(GetMagnifierType(), ash::MAGNIFIER_FULL);
 
   // Disables magnifier, and confirm the status is set successfully.
   DisableMagnifier();
   EXPECT_FALSE(IsMagnifierEnabled());
-  EXPECT_EQ(GetMagnifierType(), ash::MAGNIFIER_FULL);
 }
 
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/arc/arc_session_manager.cc b/chrome/browser/chromeos/arc/arc_session_manager.cc
index 38c5ae2b..5f2e4e9 100644
--- a/chrome/browser/chromeos/arc/arc_session_manager.cc
+++ b/chrome/browser/chromeos/arc/arc_session_manager.cc
@@ -186,6 +186,8 @@
   // Active Directory managed device.
   registry->RegisterStringPref(prefs::kArcActiveDirectoryPlayUserId,
                                std::string());
+  // This is used to decide whether migration from ecryptfs to ext4 is allowed.
+  registry->RegisterIntegerPref(prefs::kEcryptfsMigrationStrategy, 0);
 }
 
 // static
@@ -698,13 +700,6 @@
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   DCHECK(profile_);
 
-  // The check if migration is allowed is done to make sure the data is not
-  // removed if the device had ARC enabled and became disabled as result of
-  // migration to ext4 policy.
-  // TODO(igorcov): Remove this check after migration. crbug.com/725493
-  if (!arc::IsArcMigrationAllowed())
-    return;
-
   // TODO(hidehiko): DCHECK the previous state. This is called for four cases;
   // 1) Supporting managed user initial disabled case (Please see also
   //    ArcPlayStoreEnabledPreferenceHandler::Start() for details).
diff --git a/chrome/browser/chromeos/arc/arc_util.cc b/chrome/browser/chromeos/arc/arc_util.cc
index ca29a324..01c528b 100644
--- a/chrome/browser/chromeos/arc/arc_util.cc
+++ b/chrome/browser/chromeos/arc/arc_util.cc
@@ -9,35 +9,25 @@
 #include <set>
 
 #include "base/callback.h"
-#include "base/command_line.h"
 #include "base/files/file_path.h"
 #include "base/lazy_instance.h"
 #include "base/logging.h"
-#include "base/optional.h"
 #include "base/sys_info.h"
 #include "base/task_scheduler/post_task.h"
 #include "base/threading/thread_restrictions.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/arc/arc_session_manager.h"
+#include "chrome/browser/chromeos/arc/policy/arc_policy_util.h"
 #include "chrome/browser/chromeos/login/user_flow.h"
 #include "chrome/browser/chromeos/login/users/chrome_user_manager.h"
-#include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
-#include "chrome/browser/chromeos/policy/proto/chrome_device_policy.pb.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
-#include "chrome/browser/chromeos/settings/device_settings_service.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/pref_names.h"
-#include "chromeos/chromeos_switches.h"
 #include "components/arc/arc_util.h"
 #include "components/prefs/pref_service.h"
 #include "components/user_manager/known_user.h"
 #include "components/user_manager/user.h"
 #include "components/user_manager/user_manager.h"
 
-using DeviceEcryptfsMigrationStrategyProto =
-    enterprise_management::DeviceEcryptfsMigrationStrategyProto;
-
 namespace arc {
 
 namespace {
@@ -65,11 +55,6 @@
 base::LazyInstance<std::set<AccountId>>::DestructorAtExit
     g_known_compatible_users = LAZY_INSTANCE_INITIALIZER;
 
-// This flag is set the first time the check if migration to ext4 is allowed,
-// and remains unchanged after that.
-// TODO(igorcov): Remove this after migration. crbug.com/725493
-base::Optional<bool> g_is_arc_migration_allowed;
-
 // Returns whether ARC can run on the filesystem mounted at |path|.
 // This function should run only on threads where IO operations are allowed.
 bool IsArcCompatibleFilesystem(const base::FilePath& path) {
@@ -110,35 +95,6 @@
   callback.Run();
 }
 
-bool IsArcMigrationAllowedInternal() {
-  // If the device is not managed, then the migration allowed.
-  if (!g_browser_process->platform_part()
-           ->browser_policy_connector_chromeos()
-           ->IsEnterpriseManaged()) {
-    return true;
-  }
-
-  const auto* const command_line = base::CommandLine::ForCurrentProcess();
-  // If the command line flag is missing, the migration for this type of
-  // device is allowed regardless of the policy data.
-  if (!command_line->HasSwitch(
-          chromeos::switches::kNeedArcMigrationPolicyCheck)) {
-    return true;
-  }
-
-  const auto* policy =
-      chromeos::DeviceSettingsService::Get()->device_settings();
-  if (policy && policy->has_device_ecryptfs_migration_strategy()) {
-    const DeviceEcryptfsMigrationStrategyProto& container(
-        policy->device_ecryptfs_migration_strategy());
-    return container.has_migration_strategy() &&
-           container.migration_strategy() ==
-               DeviceEcryptfsMigrationStrategyProto::ALLOW_MIGRATION;
-  }
-
-  return false;
-}
-
 }  // namespace
 
 bool IsArcAllowedForProfile(const Profile* profile) {
@@ -177,6 +133,12 @@
     return false;
   }
 
+  if (!IsArcCompatibleFileSystemUsedForProfile(profile) &&
+      !IsArcMigrationAllowedForProfile(profile)) {
+    VLOG(1) << "Incompatible encryption and migration forbidden.";
+    return false;
+  }
+
   // Play Store requires an appropriate application install mechanism. Normal
   // users do this through GAIA, but Kiosk and Active Directory users use
   // different application install mechanism. ARC is not allowed otherwise
@@ -188,22 +150,6 @@
     return false;
   }
 
-  // If migration policy check is needed (specified by commandline flag), check
-  // the policy, which should be already available here. If policy says
-  // migration is not allowed, do not run ARC, regardless whether file system
-  // migration is actually needed. For example, even if file system is still
-  // ecryptfs and ARC version is M, or file system is already migrated into ext4
-  // crypt and ARC version is N or later, if policy says migration is not
-  // allowed, ARC will never run. Practically, in the former example case,
-  // --need-arc-migration-policy-check is not set, so this check passes and user
-  // can use ARC. In latter case, policy should say migration is allowed, so
-  // also user can use ARC then.
-  // TODO(igorcov): Remove this after migration. crbug.com/725493
-  if (!IsArcMigrationAllowed()) {
-    VLOG(1) << "ARC migration is not allowed by policy.";
-    return false;
-  }
-
   // Do not run ARC instance when supervised user is being created.
   // Otherwise noisy notification may be displayed.
   chromeos::UserFlow* user_flow =
@@ -216,6 +162,17 @@
   return true;
 }
 
+bool IsArcMigrationAllowedForProfile(const Profile* profile) {
+  if (!profile || !profile->GetPrefs()->IsManagedPreference(
+                      prefs::kEcryptfsMigrationStrategy)) {
+    return true;
+  }
+
+  return profile->GetPrefs()->GetInteger(prefs::kEcryptfsMigrationStrategy) !=
+         static_cast<int>(
+             arc::policy_util::EcryptfsMigrationAction::kDisallowMigration);
+}
+
 bool IsArcBlockedDueToIncompatibleFileSystem(const Profile* profile) {
   // Test runs on Linux workstation does not have expected /etc/lsb-release
   // field nor profile creation step. Hence it returns a dummy test value.
@@ -361,14 +318,4 @@
       base::Bind(&StoreCompatibilityCheckResult, account_id, callback));
 }
 
-bool IsArcMigrationAllowed() {
-  if (!g_is_arc_migration_allowed.has_value())
-    g_is_arc_migration_allowed = IsArcMigrationAllowedInternal();
-  return g_is_arc_migration_allowed.value();
-}
-
-void ResetArcMigrationAllowedForTesting() {
-  g_is_arc_migration_allowed.reset();
-}
-
 }  // namespace arc
diff --git a/chrome/browser/chromeos/arc/arc_util.h b/chrome/browser/chromeos/arc/arc_util.h
index 94f7b4d2..39c4f9b 100644
--- a/chrome/browser/chromeos/arc/arc_util.h
+++ b/chrome/browser/chromeos/arc/arc_util.h
@@ -46,6 +46,12 @@
 // nullptr can be safely passed to this function. In that case, returns false.
 bool IsArcAllowedForProfile(const Profile* profile);
 
+// Returns true if the profile is unmanaged or if the policy
+// EcryptfsMigrationStrategy for the user doesn't disable the migration.
+// Specifically if the policy states to ask the user, it is also considered that
+// migration is allowed, so return true.
+bool IsArcMigrationAllowedForProfile(const Profile* profile);
+
 // Returns true if the profile is temporarily blocked to run ARC in the current
 // session, because the filesystem storing the profile is incompatible with the
 // currently installed ARC version.
@@ -117,18 +123,6 @@
     const base::FilePath& profile_path,
     const base::Closure& callback);
 
-// Returns if the migration from ecryptfs to ext4 is allowed. It is true if the
-// flag --need-arc-migration-policy-check is not set or if the device is
-// consumer owned or if the device policy is present and has the value
-// |kAllowMigration|. The response is cached the first time the function is
-// used, and a policy update won't change the return value after that until the
-// next Chrome restart.
-bool IsArcMigrationAllowed();
-
-// For testing IsArcMigrationAllowed, the global flags have to be reset before
-// every test.
-void ResetArcMigrationAllowedForTesting();
-
 }  // namespace arc
 
 #endif  // CHROME_BROWSER_CHROMEOS_ARC_ARC_UTIL_H_
diff --git a/chrome/browser/chromeos/arc/arc_util_unittest.cc b/chrome/browser/chromeos/arc/arc_util_unittest.cc
index 5f6c65f..8a9ecd1 100644
--- a/chrome/browser/chromeos/arc/arc_util_unittest.cc
+++ b/chrome/browser/chromeos/arc/arc_util_unittest.cc
@@ -520,41 +520,84 @@
 
 class ArcMigrationTest : public testing::Test {
  protected:
-  ArcMigrationTest() {
-    auto attributes = base::MakeUnique<FakeInstallAttributesManaged>();
-    attributes_ = attributes.get();
-    policy::BrowserPolicyConnectorChromeOS::SetInstallAttributesForTesting(
-        attributes.release());
-  }
+  ArcMigrationTest() {}
   ~ArcMigrationTest() override {}
 
-  void SetUp() override { chromeos::DeviceSettingsService::Initialize(); }
-
-  void TearDown() override { chromeos::DeviceSettingsService::Shutdown(); }
-
-  void SetDeviceIsEnterpriseManaged(bool is_managed) {
-    attributes_->SetIsManaged(is_managed);
+  void SetUp() override {
+    user_manager_enabler_ =
+        base::MakeUnique<chromeos::ScopedUserManagerEnabler>(
+            new FakeUserManagerWithLocalState());
+    // Used by FakeChromeUserManager.
+    chromeos::WallpaperManager::Initialize();
+    profile_ = base::MakeUnique<TestingProfile>();
+    profile_->set_profile_name(kTestProfileName);
   }
 
-  FakeInstallAttributesManaged* attributes_;
+  void TearDown() override {
+    profile_.reset();
+    chromeos::WallpaperManager::Shutdown();
+    user_manager_enabler_.reset();
+    command_line_.reset();
+  }
+
+  TestingProfile* profile() { return profile_.get(); }
+
+  chromeos::FakeChromeUserManager* GetFakeUserManager() const {
+    return static_cast<chromeos::FakeChromeUserManager*>(
+        user_manager::UserManager::Get());
+  }
+
+ private:
+  std::unique_ptr<base::test::ScopedCommandLine> command_line_;
+  content::TestBrowserThreadBundle thread_bundle_;
+  std::unique_ptr<chromeos::ScopedUserManagerEnabler> user_manager_enabler_;
+  std::unique_ptr<TestingProfile> profile_;
+
+  DISALLOW_COPY_AND_ASSIGN(ArcMigrationTest);
 };
 
-TEST_F(ArcMigrationTest, IsMigrationAllowedConsumerOwned) {
-  ResetArcMigrationAllowedForTesting();
-  auto* const command_line = base::CommandLine::ForCurrentProcess();
-  command_line->InitFromArgv({"", "--need-arc-migration-policy-check",
-                              "--arc-availability=officially-supported"});
-  SetDeviceIsEnterpriseManaged(false);
-  EXPECT_TRUE(IsArcMigrationAllowed());
+TEST_F(ArcMigrationTest, IsMigrationAllowedUnmanagedUser) {
+  ScopedLogIn login(GetFakeUserManager(),
+                    AccountId::AdFromUserEmailObjGuid(
+                        profile()->GetProfileUserName(), kTestGaiaId));
+  profile()->GetPrefs()->SetInteger(prefs::kEcryptfsMigrationStrategy, 0);
+  EXPECT_TRUE(IsArcMigrationAllowedForProfile(profile()));
 }
 
-TEST_F(ArcMigrationTest, IsMigrationAllowedNoPolicy) {
-  ResetArcMigrationAllowedForTesting();
-  auto* const command_line = base::CommandLine::ForCurrentProcess();
-  command_line->InitFromArgv({"", "--need-arc-migration-policy-check",
-                              "--arc-availability=officially-supported"});
-  SetDeviceIsEnterpriseManaged(true);
-  EXPECT_FALSE(IsArcMigrationAllowed());
+TEST_F(ArcMigrationTest, IsMigrationAllowedForbiddenByPolicy) {
+  ScopedLogIn login(GetFakeUserManager(),
+                    AccountId::AdFromUserEmailObjGuid(
+                        profile()->GetProfileUserName(), kTestGaiaId));
+  profile()->GetTestingPrefService()->SetManagedPref(
+      prefs::kEcryptfsMigrationStrategy, base::MakeUnique<base::Value>(0));
+  EXPECT_FALSE(IsArcMigrationAllowedForProfile(profile()));
+}
+
+TEST_F(ArcMigrationTest, IsMigrationAllowedMigrate) {
+  ScopedLogIn login(GetFakeUserManager(),
+                    AccountId::AdFromUserEmailObjGuid(
+                        profile()->GetProfileUserName(), kTestGaiaId));
+  profile()->GetTestingPrefService()->SetManagedPref(
+      prefs::kEcryptfsMigrationStrategy, base::MakeUnique<base::Value>(1));
+  EXPECT_TRUE(IsArcMigrationAllowedForProfile(profile()));
+}
+
+TEST_F(ArcMigrationTest, IsMigrationAllowedWipe) {
+  ScopedLogIn login(GetFakeUserManager(),
+                    AccountId::AdFromUserEmailObjGuid(
+                        profile()->GetProfileUserName(), kTestGaiaId));
+  profile()->GetTestingPrefService()->SetManagedPref(
+      prefs::kEcryptfsMigrationStrategy, base::MakeUnique<base::Value>(2));
+  EXPECT_TRUE(IsArcMigrationAllowedForProfile(profile()));
+}
+
+TEST_F(ArcMigrationTest, IsMigrationAllowedAskUser) {
+  ScopedLogIn login(GetFakeUserManager(),
+                    AccountId::AdFromUserEmailObjGuid(
+                        profile()->GetProfileUserName(), kTestGaiaId));
+  profile()->GetTestingPrefService()->SetManagedPref(
+      prefs::kEcryptfsMigrationStrategy, base::MakeUnique<base::Value>(3));
+  EXPECT_TRUE(IsArcMigrationAllowedForProfile(profile()));
 }
 
 }  // namespace util
diff --git a/chrome/browser/chromeos/arc/policy/arc_policy_util.h b/chrome/browser/chromeos/arc/policy/arc_policy_util.h
index 98f1e28..417d040c 100644
--- a/chrome/browser/chromeos/arc/policy/arc_policy_util.h
+++ b/chrome/browser/chromeos/arc/policy/arc_policy_util.h
@@ -5,11 +5,30 @@
 #ifndef CHROME_BROWSER_CHROMEOS_ARC_POLICY_ARC_POLICY_UTIL_H_
 #define CHROME_BROWSER_CHROMEOS_ARC_POLICY_ARC_POLICY_UTIL_H_
 
+#include <stddef.h>
+#include <stdint.h>
+
 class Profile;
 
 namespace arc {
 namespace policy_util {
 
+// The action that should be taken when an ecryptfs user home which needs
+// migration is detected. This must match the order/values of the
+// EcryptfsMigrationStrategy policy.
+enum class EcryptfsMigrationAction : int32_t {
+  // Don't migrate.
+  kDisallowMigration = 0,
+  // Migrate without asking the user.
+  kMigrate = 1,
+  // Wipe the user home and start again.
+  kWipe = 2,
+  // Ask the user if migration should be performed.
+  kAskUser = 3
+};
+constexpr size_t kEcryptfsMigrationActionCount =
+    static_cast<size_t>(EcryptfsMigrationAction::kAskUser);
+
 // Returns true if the account is managed. Otherwise false.
 bool IsAccountManaged(Profile* profile);
 
diff --git a/chrome/browser/chromeos/login/existing_user_controller.cc b/chrome/browser/chromeos/login/existing_user_controller.cc
index bc35d8f..143d93f 100644
--- a/chrome/browser/chromeos/login/existing_user_controller.cc
+++ b/chrome/browser/chromeos/login/existing_user_controller.cc
@@ -25,6 +25,7 @@
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/chromeos/app_mode/kiosk_app_launch_error.h"
 #include "chrome/browser/chromeos/arc/arc_util.h"
+#include "chrome/browser/chromeos/arc/policy/arc_policy_util.h"
 #include "chrome/browser/chromeos/boot_times_recorder.h"
 #include "chrome/browser/chromeos/customization/customization_document.h"
 #include "chrome/browser/chromeos/login/arc_kiosk_controller.h"
@@ -103,6 +104,8 @@
 
 using PolicyFetchResult = policy::PreSigninPolicyFetcher::PolicyFetchResult;
 
+namespace apu = arc::policy_util;
+
 namespace chromeos {
 
 namespace {
@@ -120,22 +123,6 @@
   LOGIN_PASSWORD_CHANGE_FLOW_COUNT,  // Must be the last entry.
 };
 
-// The action that should be taken when an ecryptfs user home which needs
-// migration is detected. This must match the order/values of the
-// EcryptfsMigrationStrategy policy.
-enum class EcryptfsMigrationAction {
-  // Don't migrate.
-  DISALLOW_ARC_NO_MIGRATION,
-  // Migrate.
-  MIGRATE,
-  // Wipe the user home and start again.
-  WIPE,
-  // Ask the user if migration should be performed.
-  ASK_USER,
-  // Last value for validity checks.
-  COUNT
-};
-
 // Delay for transferring the auth cache to the system profile.
 const long int kAuthCacheTransferDelayMs = 2000;
 
@@ -217,11 +204,6 @@
   if (!arc::IsArcAvailable())
     return false;
 
-  // If the device requires ecryptfs to ext4 migration policy check, and the
-  // policy doesn't allow the migration, then return.
-  if (!arc::IsArcMigrationAllowed())
-    return false;
-
   // In some login flows (e.g. when siging in supervised user), ARC can not
   // start. For such cases, we don't need to force Ext4 dircrypto.
   chromeos::UserFlow* user_flow =
@@ -242,7 +224,7 @@
 // *|out_value|. Otherwise, returns false.
 bool DecodeMigrationActionFromPolicy(
     const enterprise_management::CloudPolicySettings* policy,
-    EcryptfsMigrationAction* out_value) {
+    apu::EcryptfsMigrationAction* out_value) {
   if (!policy->has_ecryptfsmigrationstrategy())
     return false;
 
@@ -253,11 +235,11 @@
 
   if (policy_proto.value() < 0 ||
       policy_proto.value() >=
-          static_cast<int64_t>(EcryptfsMigrationAction::COUNT)) {
+          static_cast<int64_t>(apu::kEcryptfsMigrationActionCount)) {
     return false;
   }
 
-  *out_value = static_cast<EcryptfsMigrationAction>(policy_proto.value());
+  *out_value = static_cast<apu::EcryptfsMigrationAction>(policy_proto.value());
   return true;
 }
 
@@ -1025,13 +1007,13 @@
     PolicyFetchResult result,
     std::unique_ptr<enterprise_management::CloudPolicySettings>
         policy_payload) {
-  EcryptfsMigrationAction action =
-      EcryptfsMigrationAction::DISALLOW_ARC_NO_MIGRATION;
+  apu::EcryptfsMigrationAction action =
+      apu::EcryptfsMigrationAction::kDisallowMigration;
   if (result == PolicyFetchResult::NO_POLICY) {
     // There was no policy, the user is unmanaged. They get to choose themselves
     // if they'd like to migrate.
     VLOG(1) << "Policy pre-fetch result: No user policy present";
-    action = EcryptfsMigrationAction::ASK_USER;
+    action = apu::EcryptfsMigrationAction::kAskUser;
   } else if (result == PolicyFetchResult::SUCCESS) {
     // User policy was retreived, adhere to it.
     VLOG(1) << "Policy pre-fetch result: User policy fetched";
@@ -1043,38 +1025,36 @@
       // managed users who don't have the policy value, so testing migration is
       // possible before the policy is supported server-side. This must be
       // reverted before M61 goes stable.
-      action = EcryptfsMigrationAction::ASK_USER;
+      action = apu::EcryptfsMigrationAction::kAskUser;
     }
   } else {
     // We don't know if the user has policy or not. Stay on the safe side and
     // don't start migration.
     VLOG(1) << "Policy pre-fetch: User policy could not be fetched. Result: "
             << static_cast<int>(result);
-    action = EcryptfsMigrationAction::DISALLOW_ARC_NO_MIGRATION;
+    action = apu::EcryptfsMigrationAction::kDisallowMigration;
   }
   VLOG(1) << "Migration action: " << static_cast<int>(action);
 
   switch (action) {
-    case EcryptfsMigrationAction::MIGRATE:
+    case apu::EcryptfsMigrationAction::kMigrate:
       ShowEncryptionMigrationScreen(user_context,
                                     EncryptionMigrationMode::START_MIGRATION);
       break;
 
-    case EcryptfsMigrationAction::ASK_USER:
+    case apu::EcryptfsMigrationAction::kAskUser:
       ShowEncryptionMigrationScreen(user_context,
                                     EncryptionMigrationMode::ASK_USER);
       break;
 
-    case EcryptfsMigrationAction::WIPE:
+    case apu::EcryptfsMigrationAction::kWipe:
       cryptohome::AsyncMethodCaller::GetInstance()->AsyncRemove(
           cryptohome::Identification(user_context.GetAccountId()),
           base::Bind(&ExistingUserController::WipePerformed,
                      weak_factory_.GetWeakPtr(), user_context));
       break;
 
-    case EcryptfsMigrationAction::DISALLOW_ARC_NO_MIGRATION:
-    // Fall-through intended.
-    default:
+    case apu::EcryptfsMigrationAction::kDisallowMigration:
       ContinuePerformLoginWithoutMigration(login_performer_->auth_mode(),
                                            user_context);
       break;
diff --git a/chrome/browser/chromeos/login/screens/user_selection_screen.cc b/chrome/browser/chromeos/login/screens/user_selection_screen.cc
index 132cad5..26fc2e7b 100644
--- a/chrome/browser/chromeos/login/screens/user_selection_screen.cc
+++ b/chrome/browser/chromeos/login/screens/user_selection_screen.cc
@@ -18,7 +18,6 @@
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browser_process_platform_part.h"
-#include "chrome/browser/chromeos/arc/arc_util.h"
 #include "chrome/browser/chromeos/login/lock/screen_locker.h"
 #include "chrome/browser/chromeos/login/quick_unlock/quick_unlock_factory.h"
 #include "chrome/browser/chromeos/login/quick_unlock/quick_unlock_storage.h"
@@ -150,7 +149,7 @@
 bool ShouldCheckNeedDircryptoMigration() {
   return !base::CommandLine::ForCurrentProcess()->HasSwitch(
              switches::kDisableEncryptionMigration) &&
-         arc::IsArcAvailable() && arc::IsArcMigrationAllowed();
+         arc::IsArcAvailable();
 }
 
 // Returns true if the user can run ARC based on the user type.
diff --git a/chrome/browser/chromeos/policy/configuration_policy_handler_chromeos.cc b/chrome/browser/chromeos/policy/configuration_policy_handler_chromeos.cc
index 706ea1d..4853dd11 100644
--- a/chrome/browser/chromeos/policy/configuration_policy_handler_chromeos.cc
+++ b/chrome/browser/chromeos/policy/configuration_policy_handler_chromeos.cc
@@ -339,7 +339,7 @@
 
 ScreenMagnifierPolicyHandler::ScreenMagnifierPolicyHandler()
     : IntRangePolicyHandlerBase(key::kScreenMagnifierType,
-                                0,
+                                ash::MAGNIFIER_DISABLED,
                                 ash::MAGNIFIER_FULL,
                                 false) {}
 
@@ -353,7 +353,7 @@
   int value_in_range;
   if (value && EnsureInRange(value, &value_in_range, NULL)) {
     prefs->SetBoolean(ash::prefs::kAccessibilityScreenMagnifierEnabled,
-                      value_in_range != 0);
+                      value_in_range != ash::MAGNIFIER_DISABLED);
     prefs->SetInteger(ash::prefs::kAccessibilityScreenMagnifierType,
                       value_in_range);
   }
diff --git a/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.cc b/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.cc
index 10dd94cb..6b952c2 100644
--- a/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.cc
+++ b/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.cc
@@ -382,17 +382,6 @@
                   POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                   std::move(input_methods), nullptr);
   }
-
-  if (policy.has_device_ecryptfs_migration_strategy()) {
-    const em::DeviceEcryptfsMigrationStrategyProto& container(
-        policy.device_ecryptfs_migration_strategy());
-    if (container.has_migration_strategy()) {
-      policies->Set(
-          key::kDeviceEcryptfsMigrationStrategy, POLICY_LEVEL_MANDATORY,
-          POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
-          DecodeIntegerValue(container.migration_strategy()), nullptr);
-    }
-  }
 }
 
 void DecodeNetworkPolicies(const em::ChromeDeviceSettingsProto& policy,
diff --git a/chrome/browser/chromeos/policy/login_screen_default_policy_browsertest.cc b/chrome/browser/chromeos/policy/login_screen_default_policy_browsertest.cc
index b8837c8..ba14f38 100644
--- a/chrome/browser/chromeos/policy/login_screen_default_policy_browsertest.cc
+++ b/chrome/browser/chromeos/policy/login_screen_default_policy_browsertest.cc
@@ -333,7 +333,6 @@
       chromeos::MagnificationManager::Get();
   ASSERT_TRUE(magnification_manager);
   EXPECT_TRUE(magnification_manager->IsMagnifierEnabled());
-  EXPECT_EQ(ash::MAGNIFIER_FULL, magnification_manager->GetMagnifierType());
 }
 
 IN_PROC_BROWSER_TEST_F(LoginScreenDefaultPolicyInSessionBrowsertest,
@@ -434,8 +433,6 @@
       chromeos::MagnificationManager::Get();
   ASSERT_TRUE(magnification_manager);
   EXPECT_FALSE(magnification_manager->IsMagnifierEnabled());
-  EXPECT_EQ(ash::kDefaultMagnifierType,
-            magnification_manager->GetMagnifierType());
 }
 
 IN_PROC_BROWSER_TEST_F(LoginScreenDefaultPolicyLoginScreenBrowsertest,
diff --git a/chrome/browser/chromeos/preferences.cc b/chrome/browser/chromeos/preferences.cc
index 6c77943e..0c58744 100644
--- a/chrome/browser/chromeos/preferences.cc
+++ b/chrome/browser/chromeos/preferences.cc
@@ -200,7 +200,7 @@
       ash::prefs::kAccessibilityScreenMagnifierEnabled, false,
       user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
   registry->RegisterIntegerPref(
-      ash::prefs::kAccessibilityScreenMagnifierType, ash::kDefaultMagnifierType,
+      ash::prefs::kAccessibilityScreenMagnifierType, ash::MAGNIFIER_FULL,
       user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
   registry->RegisterDoublePref(ash::prefs::kAccessibilityScreenMagnifierScale,
                                std::numeric_limits<double>::min());
diff --git a/chrome/browser/metrics/subprocess_metrics_provider.cc b/chrome/browser/metrics/subprocess_metrics_provider.cc
index 54c2e05..a10513b 100644
--- a/chrome/browser/metrics/subprocess_metrics_provider.cc
+++ b/chrome/browser/metrics/subprocess_metrics_provider.cc
@@ -89,7 +89,7 @@
   DCHECK(allocator);
 
   // TODO(asvitkine): Remove this after crbug/736675.
-  base::StatisticsRecorder::ValidateAllHistograms();
+  base::StatisticsRecorder::ValidateAllHistograms(1);
 
   int histogram_count = 0;
   base::PersistentHistogramAllocator::Iterator hist_iter(allocator);
@@ -102,7 +102,7 @@
   }
 
   // TODO(asvitkine): Remove this after crbug/736675.
-  base::StatisticsRecorder::ValidateAllHistograms();
+  base::StatisticsRecorder::ValidateAllHistograms(2);
 
   DVLOG(1) << "Reported " << histogram_count << " histograms from subprocess #"
            << id;
diff --git a/chrome/browser/notifications/notification_channels_provider_android.cc b/chrome/browser/notifications/notification_channels_provider_android.cc
index f08f284..3e961aa 100644
--- a/chrome/browser/notifications/notification_channels_provider_android.cc
+++ b/chrome/browser/notifications/notification_channels_provider_android.cc
@@ -126,7 +126,8 @@
     DCHECK(HasNext());
     DCHECK_NE(channels_[index_].status, NotificationChannelStatus::UNAVAILABLE);
     content_settings::Rule rule = content_settings::Rule(
-        ContentSettingsPattern::FromString(channels_[index_].origin),
+        ContentSettingsPattern::FromURLNoWildcard(
+            GURL(channels_[index_].origin)),
         ContentSettingsPattern::Wildcard(),
         new base::Value(
             ChannelStatusToContentSetting(channels_[index_].status)));
diff --git a/chrome/browser/notifications/notification_channels_provider_android_unittest.cc b/chrome/browser/notifications/notification_channels_provider_android_unittest.cc
index 918e027..8234c6a 100644
--- a/chrome/browser/notifications/notification_channels_provider_android_unittest.cc
+++ b/chrome/browser/notifications/notification_channels_provider_android_unittest.cc
@@ -141,6 +141,11 @@
         base::WrapUnique(new NotificationChannelsProviderAndroid(
             base::WrapUnique(fake_bridge_), std::move(clock)));
   }
+
+  ContentSettingsPattern GetTestPattern() {
+    return ContentSettingsPattern::FromURLNoWildcard(GURL(kTestOrigin));
+  }
+
   content::TestBrowserThreadBundle test_browser_thread_bundle_;
   base::test::ScopedFeatureList scoped_feature_list_;
   std::unique_ptr<TestingProfile> profile_;
@@ -155,7 +160,7 @@
        SetWebsiteSettingWhenChannelsShouldNotBeUsed_ReturnsFalse) {
   this->InitChannelsProvider(false /* should_use_channels */);
   bool result = channels_provider_->SetWebsiteSetting(
-      ContentSettingsPattern::FromString(kTestOrigin), ContentSettingsPattern(),
+      GetTestPattern(), ContentSettingsPattern(),
       CONTENT_SETTINGS_TYPE_NOTIFICATIONS, std::string(),
       new base::Value(CONTENT_SETTING_BLOCK));
 
@@ -167,7 +172,7 @@
   InitChannelsProvider(true /* should_use_channels */);
 
   bool result = channels_provider_->SetWebsiteSetting(
-      ContentSettingsPattern::FromString(kTestOrigin), ContentSettingsPattern(),
+      GetTestPattern(), ContentSettingsPattern(),
       CONTENT_SETTINGS_TYPE_NOTIFICATIONS, std::string(),
       new base::Value(CONTENT_SETTING_ALLOW));
   EXPECT_TRUE(result);
@@ -177,8 +182,7 @@
                                           std::string(), false /* incognito */);
   EXPECT_TRUE(rule_iterator->HasNext());
   content_settings::Rule rule = rule_iterator->Next();
-  EXPECT_EQ(ContentSettingsPattern::FromString(kTestOrigin),
-            rule.primary_pattern);
+  EXPECT_EQ(GetTestPattern(), rule.primary_pattern);
   EXPECT_EQ(CONTENT_SETTING_ALLOW,
             content_settings::ValueToContentSetting(rule.value.get()));
   EXPECT_FALSE(rule_iterator->HasNext());
@@ -189,7 +193,7 @@
   InitChannelsProvider(true /* should_use_channels */);
 
   bool result = channels_provider_->SetWebsiteSetting(
-      ContentSettingsPattern::FromString(kTestOrigin), ContentSettingsPattern(),
+      GetTestPattern(), ContentSettingsPattern(),
       CONTENT_SETTINGS_TYPE_NOTIFICATIONS, std::string(),
       new base::Value(CONTENT_SETTING_BLOCK));
 
@@ -199,8 +203,7 @@
                                           std::string(), false /* incognito */);
   EXPECT_TRUE(rule_iterator->HasNext());
   content_settings::Rule rule = rule_iterator->Next();
-  EXPECT_EQ(ContentSettingsPattern::FromString(kTestOrigin),
-            rule.primary_pattern);
+  EXPECT_EQ(GetTestPattern(), rule.primary_pattern);
   EXPECT_EQ(CONTENT_SETTING_BLOCK,
             content_settings::ValueToContentSetting(rule.value.get()));
   EXPECT_FALSE(rule_iterator->HasNext());
@@ -211,11 +214,11 @@
   InitChannelsProvider(true /* should_use_channels */);
 
   channels_provider_->SetWebsiteSetting(
-      ContentSettingsPattern::FromString(kTestOrigin), ContentSettingsPattern(),
+      GetTestPattern(), ContentSettingsPattern(),
       CONTENT_SETTINGS_TYPE_NOTIFICATIONS, std::string(),
       new base::Value(CONTENT_SETTING_ALLOW));
   bool result = channels_provider_->SetWebsiteSetting(
-      ContentSettingsPattern::FromString(kTestOrigin), ContentSettingsPattern(),
+      GetTestPattern(), ContentSettingsPattern(),
       CONTENT_SETTINGS_TYPE_NOTIFICATIONS, std::string(),
       new base::Value(CONTENT_SETTING_ALLOW));
 
@@ -225,8 +228,7 @@
                                           std::string(), false /* incognito */);
   EXPECT_TRUE(rule_iterator->HasNext());
   content_settings::Rule rule = rule_iterator->Next();
-  EXPECT_EQ(ContentSettingsPattern::FromString(kTestOrigin),
-            rule.primary_pattern);
+  EXPECT_EQ(GetTestPattern(), rule.primary_pattern);
   EXPECT_EQ(CONTENT_SETTING_ALLOW,
             content_settings::ValueToContentSetting(rule.value.get()));
   EXPECT_FALSE(rule_iterator->HasNext());
@@ -237,11 +239,11 @@
   InitChannelsProvider(true /* should_use_channels */);
 
   channels_provider_->SetWebsiteSetting(
-      ContentSettingsPattern::FromString(kTestOrigin), ContentSettingsPattern(),
+      GetTestPattern(), ContentSettingsPattern(),
       CONTENT_SETTINGS_TYPE_NOTIFICATIONS, std::string(),
       new base::Value(CONTENT_SETTING_BLOCK));
   bool result = channels_provider_->SetWebsiteSetting(
-      ContentSettingsPattern::FromString(kTestOrigin), ContentSettingsPattern(),
+      GetTestPattern(), ContentSettingsPattern(),
       CONTENT_SETTINGS_TYPE_NOTIFICATIONS, std::string(),
       new base::Value(CONTENT_SETTING_BLOCK));
 
@@ -251,8 +253,7 @@
                                           std::string(), false /* incognito */);
   EXPECT_TRUE(rule_iterator->HasNext());
   content_settings::Rule rule = rule_iterator->Next();
-  EXPECT_EQ(ContentSettingsPattern::FromString(kTestOrigin),
-            rule.primary_pattern);
+  EXPECT_EQ(GetTestPattern(), rule.primary_pattern);
   EXPECT_EQ(CONTENT_SETTING_BLOCK,
             content_settings::ValueToContentSetting(rule.value.get()));
   EXPECT_FALSE(rule_iterator->HasNext());
@@ -262,12 +263,12 @@
        SetWebsiteSettingDefault_DeletesRule) {
   InitChannelsProvider(true /* should_use_channels */);
   channels_provider_->SetWebsiteSetting(
-      ContentSettingsPattern::FromString(kTestOrigin), ContentSettingsPattern(),
+      GetTestPattern(), ContentSettingsPattern(),
       CONTENT_SETTINGS_TYPE_NOTIFICATIONS, std::string(),
       new base::Value(CONTENT_SETTING_ALLOW));
 
   bool result = channels_provider_->SetWebsiteSetting(
-      ContentSettingsPattern::FromString(kTestOrigin), ContentSettingsPattern(),
+      GetTestPattern(), ContentSettingsPattern(),
       CONTENT_SETTINGS_TYPE_NOTIFICATIONS, std::string(), nullptr);
 
   EXPECT_TRUE(result);
@@ -287,9 +288,9 @@
 TEST_F(NotificationChannelsProviderAndroidTest, NoRulesInIncognito) {
   InitChannelsProvider(true /* should_use_channels */);
   channels_provider_->SetWebsiteSetting(
-      ContentSettingsPattern::FromString("https://abc.com"),
-      ContentSettingsPattern(), CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
-      std::string(), new base::Value(CONTENT_SETTING_ALLOW));
+      GetTestPattern(), ContentSettingsPattern(),
+      CONTENT_SETTINGS_TYPE_NOTIFICATIONS, std::string(),
+      new base::Value(CONTENT_SETTING_ALLOW));
   EXPECT_FALSE(
       channels_provider_->GetRuleIterator(CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
                                           std::string(), true /* incognito */));
@@ -306,28 +307,30 @@
 TEST_F(NotificationChannelsProviderAndroidTest,
        SetWebsiteSettingForMultipleOriginsCreatesMultipleRules) {
   InitChannelsProvider(true /* should_use_channels */);
-  channels_provider_->SetWebsiteSetting(
-      ContentSettingsPattern::FromString("https://abc.com"),
-      ContentSettingsPattern(), CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
-      std::string(), new base::Value(CONTENT_SETTING_ALLOW));
-  channels_provider_->SetWebsiteSetting(
-      ContentSettingsPattern::FromString("https://xyz.com"),
-      ContentSettingsPattern(), CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
-      std::string(), new base::Value(CONTENT_SETTING_BLOCK));
+  ContentSettingsPattern abc_pattern =
+      ContentSettingsPattern::FromURLNoWildcard(GURL("https://abc.com"));
+  ContentSettingsPattern xyz_pattern =
+      ContentSettingsPattern::FromURLNoWildcard(GURL("https://xyz.com"));
+  channels_provider_->SetWebsiteSetting(abc_pattern, ContentSettingsPattern(),
+                                        CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
+                                        std::string(),
+                                        new base::Value(CONTENT_SETTING_ALLOW));
+  channels_provider_->SetWebsiteSetting(xyz_pattern, ContentSettingsPattern(),
+                                        CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
+                                        std::string(),
+                                        new base::Value(CONTENT_SETTING_BLOCK));
 
   std::unique_ptr<content_settings::RuleIterator> rule_iterator =
       channels_provider_->GetRuleIterator(CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
                                           std::string(), false /* incognito */);
   EXPECT_TRUE(rule_iterator->HasNext());
   content_settings::Rule first_rule = rule_iterator->Next();
-  EXPECT_EQ(ContentSettingsPattern::FromString("https://abc.com"),
-            first_rule.primary_pattern);
+  EXPECT_EQ(abc_pattern, first_rule.primary_pattern);
   EXPECT_EQ(CONTENT_SETTING_ALLOW,
             content_settings::ValueToContentSetting(first_rule.value.get()));
   EXPECT_TRUE(rule_iterator->HasNext());
   content_settings::Rule second_rule = rule_iterator->Next();
-  EXPECT_EQ(ContentSettingsPattern::FromString("https://xyz.com"),
-            second_rule.primary_pattern);
+  EXPECT_EQ(xyz_pattern, second_rule.primary_pattern);
   EXPECT_EQ(CONTENT_SETTING_BLOCK,
             content_settings::ValueToContentSetting(second_rule.value.get()));
   EXPECT_FALSE(rule_iterator->HasNext());
@@ -374,14 +377,18 @@
   channels_provider_->AddObserver(&mock_observer);
 
   // Set up some channels.
-  channels_provider_->SetWebsiteSetting(
-      ContentSettingsPattern::FromString("https://abc.com"),
-      ContentSettingsPattern(), CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
-      std::string(), new base::Value(CONTENT_SETTING_ALLOW));
-  channels_provider_->SetWebsiteSetting(
-      ContentSettingsPattern::FromString("https://xyz.com"),
-      ContentSettingsPattern(), CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
-      std::string(), new base::Value(CONTENT_SETTING_BLOCK));
+  ContentSettingsPattern abc_pattern =
+      ContentSettingsPattern::FromURLNoWildcard(GURL("https://abc.com"));
+  ContentSettingsPattern xyz_pattern =
+      ContentSettingsPattern::FromURLNoWildcard(GURL("https://xyz.com"));
+  channels_provider_->SetWebsiteSetting(abc_pattern, ContentSettingsPattern(),
+                                        CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
+                                        std::string(),
+                                        new base::Value(CONTENT_SETTING_ALLOW));
+  channels_provider_->SetWebsiteSetting(xyz_pattern, ContentSettingsPattern(),
+                                        CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
+                                        std::string(),
+                                        new base::Value(CONTENT_SETTING_BLOCK));
 
   EXPECT_CALL(mock_observer,
               OnContentSettingChanged(
@@ -402,14 +409,18 @@
   InitChannelsProvider(true /* should_use_channels */);
 
   // Set up some channels.
-  channels_provider_->SetWebsiteSetting(
-      ContentSettingsPattern::FromString("https://abc.com"),
-      ContentSettingsPattern(), CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
-      std::string(), new base::Value(CONTENT_SETTING_ALLOW));
-  channels_provider_->SetWebsiteSetting(
-      ContentSettingsPattern::FromString("https://xyz.com"),
-      ContentSettingsPattern(), CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
-      std::string(), new base::Value(CONTENT_SETTING_BLOCK));
+  ContentSettingsPattern abc_pattern =
+      ContentSettingsPattern::FromURLNoWildcard(GURL("https://abc.com"));
+  ContentSettingsPattern xyz_pattern =
+      ContentSettingsPattern::FromURLNoWildcard(GURL("https://xyz.com"));
+  channels_provider_->SetWebsiteSetting(abc_pattern, ContentSettingsPattern(),
+                                        CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
+                                        std::string(),
+                                        new base::Value(CONTENT_SETTING_ALLOW));
+  channels_provider_->SetWebsiteSetting(xyz_pattern, ContentSettingsPattern(),
+                                        CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
+                                        std::string(),
+                                        new base::Value(CONTENT_SETTING_BLOCK));
 
   channels_provider_->ClearAllContentSettingsRules(
       CONTENT_SETTINGS_TYPE_COOKIES);
@@ -434,7 +445,7 @@
   InitChannelsProvider(true /* should_use_channels */);
 
   auto result = channels_provider_->GetWebsiteSettingLastModified(
-      ContentSettingsPattern::FromString(kTestOrigin), ContentSettingsPattern(),
+      GetTestPattern(), ContentSettingsPattern(),
       CONTENT_SETTINGS_TYPE_NOTIFICATIONS, std::string());
 
   EXPECT_TRUE(result.is_null());
@@ -445,19 +456,19 @@
   InitChannelsProvider(true /* should_use_channels */);
 
   channels_provider_->SetWebsiteSetting(
-      ContentSettingsPattern::FromString(kTestOrigin), ContentSettingsPattern(),
+      GetTestPattern(), ContentSettingsPattern(),
       CONTENT_SETTINGS_TYPE_NOTIFICATIONS, std::string(),
       new base::Value(CONTENT_SETTING_ALLOW));
 
   auto result = channels_provider_->GetWebsiteSettingLastModified(
-      ContentSettingsPattern::FromString(kTestOrigin), ContentSettingsPattern(),
+      GetTestPattern(), ContentSettingsPattern(),
       CONTENT_SETTINGS_TYPE_GEOLOCATION, std::string());
 
   EXPECT_TRUE(result.is_null());
 
   result = channels_provider_->GetWebsiteSettingLastModified(
-      ContentSettingsPattern::FromString(kTestOrigin), ContentSettingsPattern(),
-      CONTENT_SETTINGS_TYPE_COOKIES, std::string());
+      GetTestPattern(), ContentSettingsPattern(), CONTENT_SETTINGS_TYPE_COOKIES,
+      std::string());
 
   EXPECT_TRUE(result.is_null());
 }
diff --git a/chrome/browser/policy/configuration_policy_handler_list_factory.cc b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
index 610002e9..c37f982 100644
--- a/chrome/browser/policy/configuration_policy_handler_list_factory.cc
+++ b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
@@ -586,6 +586,9 @@
   { key::kNativePrinters,
     prefs::kRecommendedNativePrinters,
     base::Value::Type::LIST },
+  { key::kEcryptfsMigrationStrategy,
+    prefs::kEcryptfsMigrationStrategy,
+    base::Value::Type::INTEGER },
 #endif  // defined(OS_CHROMEOS)
 
 // Metrics reporting is controlled by a platform specific policy for ChromeOS
@@ -1034,8 +1037,8 @@
   handlers->AddHandler(base::MakeUnique<IntRangePolicyHandler>(
       key::kUptimeLimit, prefs::kUptimeLimit, 3600, INT_MAX, true));
   handlers->AddHandler(base::WrapUnique(new IntRangePolicyHandler(
-      key::kDeviceLoginScreenDefaultScreenMagnifierType, NULL, 0,
-      ash::MAGNIFIER_FULL, false)));
+      key::kDeviceLoginScreenDefaultScreenMagnifierType, nullptr,
+      ash::MAGNIFIER_DISABLED, ash::MAGNIFIER_FULL, false)));
   // TODO(binjin): Remove LegacyPoliciesDeprecatingPolicyHandler for these two
   // policies once deprecation of legacy power management policies is done.
   // http://crbug.com/346229
diff --git a/chrome/browser/policy/policy_browsertest.cc b/chrome/browser/policy/policy_browsertest.cc
index e287af9..273d554 100644
--- a/chrome/browser/policy/policy_browsertest.cc
+++ b/chrome/browser/policy/policy_browsertest.cc
@@ -2873,9 +2873,7 @@
       chromeos::MagnificationManager::Get();
 
   // Manually enable the full-screen magnifier.
-  magnification_manager->SetMagnifierType(ash::MAGNIFIER_FULL);
   magnification_manager->SetMagnifierEnabled(true);
-  EXPECT_EQ(ash::MAGNIFIER_FULL, magnification_manager->GetMagnifierType());
   EXPECT_TRUE(magnification_manager->IsMagnifierEnabled());
 
   // Verify that policy overrides the manual setting.
@@ -2905,7 +2903,6 @@
                POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
                base::MakeUnique<base::Value>(ash::MAGNIFIER_FULL), nullptr);
   UpdateProviderPolicy(policies);
-  EXPECT_EQ(ash::MAGNIFIER_FULL, magnification_manager->GetMagnifierType());
   EXPECT_TRUE(magnification_manager->IsMagnifierEnabled());
 
   // Verify that the screen magnifier cannot be disabled manually anymore.
diff --git a/chrome/browser/resource_coordinator/resource_coordinator_web_contents_observer.cc b/chrome/browser/resource_coordinator/resource_coordinator_web_contents_observer.cc
index 425f822..5045eba5 100644
--- a/chrome/browser/resource_coordinator/resource_coordinator_web_contents_observer.cc
+++ b/chrome/browser/resource_coordinator/resource_coordinator_web_contents_observer.cc
@@ -28,6 +28,10 @@
 
 DEFINE_WEB_CONTENTS_USER_DATA_KEY(ResourceCoordinatorWebContentsObserver);
 
+// We delay the sending of favicon/title update signal to GRC for 5 minutes
+// after the main frame navigation is committed.
+const base::TimeDelta kFaviconAndTitleUpdateIgnoredTimeout =
+    base::TimeDelta::FromMinutes(5);
 bool ResourceCoordinatorWebContentsObserver::ukm_recorder_initialized = false;
 
 ResourceCoordinatorWebContentsObserver::ResourceCoordinatorWebContentsObserver(
@@ -145,8 +149,7 @@
   if (navigation_handle->IsInMainFrame()) {
     UpdateUkmRecorder(navigation_handle->GetNavigationId());
     ResetFlag();
-    tab_resource_coordinator_->SendEvent(
-        resource_coordinator::mojom::Event::kNavigationCommitted);
+    navigation_finished_time_ = base::TimeTicks::Now();
   }
 
   content::RenderFrameHost* render_frame_host =
@@ -168,6 +171,13 @@
     first_time_title_set_ = true;
     return;
   }
+  // Ignore update when the tab is in foreground or the update happens within 5
+  // minutes after the main frame is committed.
+  if (web_contents()->IsVisible() ||
+      base::TimeTicks::Now() - navigation_finished_time_ <
+          kFaviconAndTitleUpdateIgnoredTimeout) {
+    return;
+  }
   tab_resource_coordinator_->SendEvent(
       resource_coordinator::mojom::Event::kTitleUpdated);
 }
@@ -178,6 +188,13 @@
     first_time_favicon_set_ = true;
     return;
   }
+  // Ignore update when the tab is in foreground or the update happens within 5
+  // minutes after the main frame is committed.
+  if (web_contents()->IsVisible() ||
+      base::TimeTicks::Now() - navigation_finished_time_ <
+          kFaviconAndTitleUpdateIgnoredTimeout) {
+    return;
+  }
   tab_resource_coordinator_->SendEvent(
       resource_coordinator::mojom::Event::kFaviconUpdated);
 }
diff --git a/chrome/browser/resource_coordinator/resource_coordinator_web_contents_observer.h b/chrome/browser/resource_coordinator/resource_coordinator_web_contents_observer.h
index fc02cae..7fb8945 100644
--- a/chrome/browser/resource_coordinator/resource_coordinator_web_contents_observer.h
+++ b/chrome/browser/resource_coordinator/resource_coordinator_web_contents_observer.h
@@ -61,6 +61,12 @@
       tab_resource_coordinator_;
   ukm::SourceId ukm_source_id_;
 
+  // We only want to send signals to GRC 5 minutes after the main frame is
+  // committed. Thus we record the time when navigation of main frame is
+  // finished, when title/favicon is changed, we check whether it's already more
+  // than 5 minutes from the time navigation of main frame is finished.
+  base::TimeTicks navigation_finished_time_;
+
   // Favicon and title are set when a page is loaded, we only want to send
   // signals to GRC about title and favicon update from the previous title and
   // favicon, thus we want to ignore the very first update since it is always
diff --git a/chrome/browser/resources/md_history/externs.js b/chrome/browser/resources/md_history/externs.js
index 6ba6f5a..590c127 100644
--- a/chrome/browser/resources/md_history/externs.js
+++ b/chrome/browser/resources/md_history/externs.js
@@ -35,8 +35,6 @@
  *     BrowsingHistoryHandler::QueryComplete()
  * @typedef {{finished: boolean,
  *            hasSyncedResults: boolean,
- *            queryEndTime: string,
- *            queryStartTime: string,
  *            term: string}}
  */
 var HistoryQuery;
diff --git a/chrome/browser/ui/ash/ash_init.cc b/chrome/browser/ui/ash/ash_init.cc
index 8d51414..2b99983 100644
--- a/chrome/browser/ui/ash/ash_init.cc
+++ b/chrome/browser/ui/ash/ash_init.cc
@@ -9,7 +9,6 @@
 #include "ash/accessibility_types.h"
 #include "ash/high_contrast/high_contrast_controller.h"
 #include "ash/magnifier/magnification_controller.h"
-#include "ash/magnifier/partial_magnification_controller.h"
 #include "ash/mus/bridge/shell_port_mash.h"
 #include "ash/mus/window_manager.h"
 #include "ash/public/cpp/config.h"
@@ -123,14 +122,8 @@
       chromeos::AccessibilityManager::Get()->IsHighContrastEnabled());
 
   DCHECK(chromeos::MagnificationManager::Get());
-  bool magnifier_enabled =
-      chromeos::MagnificationManager::Get()->IsMagnifierEnabled();
-  ash::MagnifierType magnifier_type =
-      chromeos::MagnificationManager::Get()->GetMagnifierType();
   shell->magnification_controller()->SetEnabled(
-      magnifier_enabled && magnifier_type == ash::MAGNIFIER_FULL);
-  shell->partial_magnification_controller()->SetEnabled(
-      magnifier_enabled && magnifier_type == ash::MAGNIFIER_PARTIAL);
+      chromeos::MagnificationManager::Get()->IsMagnifierEnabled());
 
   if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kDisableZeroBrowsersOpenForTests)) {
diff --git a/chrome/browser/ui/ash/chrome_shell_delegate.cc b/chrome/browser/ui/ash/chrome_shell_delegate.cc
index 6bc26e8..6052b947 100644
--- a/chrome/browser/ui/ash/chrome_shell_delegate.cc
+++ b/chrome/browser/ui/ash/chrome_shell_delegate.cc
@@ -140,21 +140,11 @@
     return chromeos::MagnificationManager::Get()->SetMagnifierEnabled(enabled);
   }
 
-  void SetMagnifierType(ash::MagnifierType type) override {
-    DCHECK(chromeos::MagnificationManager::Get());
-    return chromeos::MagnificationManager::Get()->SetMagnifierType(type);
-  }
-
   bool IsMagnifierEnabled() const override {
     DCHECK(chromeos::MagnificationManager::Get());
     return chromeos::MagnificationManager::Get()->IsMagnifierEnabled();
   }
 
-  ash::MagnifierType GetMagnifierType() const override {
-    DCHECK(chromeos::MagnificationManager::Get());
-    return chromeos::MagnificationManager::Get()->GetMagnifierType();
-  }
-
   void SetLargeCursorEnabled(bool enabled) override {
     DCHECK(AccessibilityManager::Get());
     return AccessibilityManager::Get()->EnableLargeCursor(enabled);
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.cc b/chrome/browser/ui/autofill/chrome_autofill_client.cc
index 6c5f1f8..77c841a 100644
--- a/chrome/browser/ui/autofill/chrome_autofill_client.cc
+++ b/chrome/browser/ui/autofill/chrome_autofill_client.cc
@@ -423,8 +423,10 @@
 
 bool ChromeAutofillClient::IsAutofillSupported() {
   // VR browsing does not support popups at the moment.
-  if (vr::VrTabHelper::IsInVr(web_contents()))
+  if (vr::VrTabHelper::IsInVr(web_contents())) {
+    vr::VrTabHelper::UISuppressed(vr::UiSuppressedElement::kAutofill);
     return false;
+  }
 
   return true;
 }
diff --git a/chrome/browser/ui/webui/browsing_history_handler.cc b/chrome/browser/ui/webui/browsing_history_handler.cc
index 5f5d01c..d4158841 100644
--- a/chrome/browser/ui/webui/browsing_history_handler.cc
+++ b/chrome/browser/ui/webui/browsing_history_handler.cc
@@ -14,7 +14,6 @@
 #include "base/i18n/time_formatting.h"
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
-#include "base/strings/string16.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/default_clock.h"
@@ -69,23 +68,6 @@
 static const char kDeviceTypePhone[] = "phone";
 static const char kDeviceTypeTablet[] = "tablet";
 
-// Returns a localized version of |visit_time| including a relative
-// indicator (e.g. today, yesterday).
-base::string16 GetRelativeDateLocalized(base::Clock* clock,
-                                        const base::Time& visit_time) {
-  base::Time midnight = clock->Now().LocalMidnight();
-  base::string16 date_str = ui::TimeFormat::RelativeDate(visit_time, &midnight);
-  if (date_str.empty()) {
-    date_str = base::TimeFormatFriendlyDate(visit_time);
-  } else {
-    date_str = l10n_util::GetStringFUTF16(
-        IDS_HISTORY_DATE_WITH_RELATIVE_TIME,
-        date_str,
-        base::TimeFormatFriendlyDate(visit_time));
-  }
-  return date_str;
-}
-
 // Gets the name and type of a device for the given sync client ID.
 // |name| and |type| are out parameters.
 void GetDeviceNameAndType(const browser_sync::ProfileSyncService* sync_service,
@@ -396,15 +378,6 @@
   results_info.SetBoolean("hasSyncedResults",
                           query_results_info.has_synced_results);
 
-  // Add the specific dates that were searched to display them.
-  // TODO(sergiu): Put today if the start is in the future.
-  results_info.SetString(
-      "queryStartTime",
-      GetRelativeDateLocalized(clock_.get(), query_results_info.start_time));
-  results_info.SetString(
-      "queryEndTime",
-      GetRelativeDateLocalized(clock_.get(), query_results_info.end_time));
-
   web_ui()->CallJavascriptFunctionUnsafe("historyResult", results_info,
                                          results_value);
 }
diff --git a/chrome/browser/vr/ui_suppressed_element.h b/chrome/browser/vr/ui_suppressed_element.h
index c657c0c..a5594a63 100644
--- a/chrome/browser/vr/ui_suppressed_element.h
+++ b/chrome/browser/vr/ui_suppressed_element.h
@@ -21,6 +21,7 @@
   kDownloadPermission,
   kFileAccessPermission,
   kPasswordManager,
+  kAutofill,
 
   // This must be last.
   kCount,
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index dc35aa3f..b664681 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -957,6 +957,10 @@
 // String pref indicating what name should be advertised for casting to.
 // If the string is empty or blank the system name will be used.
 const char kCastReceiverName[] = "cast_receiver.name";
+
+// Integer pref indicating the ecryptfs to ext4 migration strategy. One of
+// options: forbidden = 0, migrate = 1, wipe = 2 or ask the user = 3.
+const char kEcryptfsMigrationStrategy[] = "ecryptfs_migration_strategy";
 #endif  // defined(OS_CHROMEOS)
 
 // A boolean pref set to true if a Home button to open the Home pages should be
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index 7d3c963..17b4577 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -317,6 +317,7 @@
 extern const char kInstantTetheringBleAdvertisingSupported[];
 extern const char kCastReceiverEnabled[];
 extern const char kCastReceiverName[];
+extern const char kEcryptfsMigrationStrategy[];
 #endif  // defined(OS_CHROMEOS)
 extern const char kShowHomeButton[];
 extern const char kSpeechRecognitionFilterProfanities[];
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeActivityTestCommon.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeActivityTestCommon.java
index d6c9695..93e2ae5 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeActivityTestCommon.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeActivityTestCommon.java
@@ -24,7 +24,6 @@
 import org.chromium.base.ApplicationStatus.ActivityStateListener;
 import org.chromium.base.Log;
 import org.chromium.base.ThreadUtils;
-import org.chromium.base.annotations.SuppressFBWarnings;
 import org.chromium.base.test.util.CallbackHelper;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeActivity;
@@ -154,7 +153,6 @@
         final CallbackHelper activityCallback = new CallbackHelper();
         final AtomicReference<T> activityRef = new AtomicReference<>();
         ActivityStateListener stateListener = new ActivityStateListener() {
-            @SuppressFBWarnings("BC_UNCONFIRMED_CAST")
             @SuppressWarnings("unchecked")
             @Override
             public void onActivityStateChange(Activity activity, int newState) {
diff --git a/chrome/test/base/testing_profile.cc b/chrome/test/base/testing_profile.cc
index e4bb4a6..158e3310 100644
--- a/chrome/test/base/testing_profile.cc
+++ b/chrome/test/base/testing_profile.cc
@@ -428,16 +428,6 @@
              content::BrowserThread::UI) ||
          content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
 
-#if defined(OS_CHROMEOS)
-  if (!chromeos::CrosSettings::IsInitialized()) {
-    scoped_cros_settings_test_helper_.reset(
-        new chromeos::ScopedCrosSettingsTestHelper);
-  }
-  arc::ArcServiceLauncher* launcher = arc::ArcServiceLauncher::Get();
-  if (launcher)
-    launcher->MaybeSetProfile(this);
-#endif
-
   set_is_guest_profile(guest_session_);
 
   BrowserContext::Initialize(this, profile_path_);
@@ -481,6 +471,16 @@
   if (!base::PathExists(profile_path_))
     base::CreateDirectory(profile_path_);
 
+#if defined(OS_CHROMEOS)
+  if (!chromeos::CrosSettings::IsInitialized()) {
+    scoped_cros_settings_test_helper_.reset(
+        new chromeos::ScopedCrosSettingsTestHelper);
+  }
+  arc::ArcServiceLauncher* launcher = arc::ArcServiceLauncher::Get();
+  if (launcher)
+    launcher->MaybeSetProfile(this);
+#endif
+
   // TODO(joaodasilva): remove this once this PKS isn't created in ProfileImpl
   // anymore, after converting the PrefService to a PKS. Until then it must
   // be associated with a TestingProfile too.
diff --git a/chrome/test/data/policy/policy_test_cases.json b/chrome/test/data/policy/policy_test_cases.json
index b2f66ae..228b4572 100644
--- a/chrome/test/data/policy/policy_test_cases.json
+++ b/chrome/test/data/policy/policy_test_cases.json
@@ -2794,7 +2794,10 @@
 
   "EcryptfsMigrationStrategy": {
     "os": ["chromeos"],
-    "test_policy": { "EcryptfsMigrationStrategy": 1 }
+    "test_policy": { "EcryptfsMigrationStrategy": 1 },
+    "pref_mappings": [
+      { "pref": "ecryptfs_migration_strategy" }
+    ]
   },
 
   "CloudPolicyOverridesMachinePolicy": {
@@ -3135,8 +3138,8 @@
   },
 
   "DeviceEcryptfsMigrationStrategy": {
-    "os": ["chromeos"],
-    "test_policy": { "DeviceEcryptfsMigrationStrategy": 1 }
+    "note": "This policy is deprecated.",
+    "os": ["chromeos"]
   },
 
   "NoteTakingAppsLockScreenWhitelist": {
diff --git a/components/cronet/ios/BUILD.gn b/components/cronet/ios/BUILD.gn
index d2e6eece..b77ddf3 100644
--- a/components/cronet/ios/BUILD.gn
+++ b/components/cronet/ios/BUILD.gn
@@ -65,8 +65,12 @@
 ]
 
 _cronet_sources = [
+  "../cronet_prefs_manager.cc",
+  "../cronet_prefs_manager.h",
   "../histogram_manager.cc",
   "../histogram_manager.h",
+  "../host_cache_persistence_manager.cc",
+  "../host_cache_persistence_manager.h",
   "../stale_host_resolver.cc",
   "../stale_host_resolver.h",
   "../url_request_context_config.cc",
diff --git a/components/cronet/ios/Cronet.mm b/components/cronet/ios/Cronet.mm
index 3d426940..eeee8b65 100644
--- a/components/cronet/ios/Cronet.mm
+++ b/components/cronet/ios/Cronet.mm
@@ -39,28 +39,27 @@
 base::LazyInstance<std::unique_ptr<cronet::CronetEnvironment>>::Leaky
     gChromeNet = LAZY_INSTANCE_INITIALIZER;
 
-// TODO(lilyhoughton) make these independent across Cronet instances, i.e.:
-// refresh them on shutdown, and add tests to make sure the defaults are
-// sane.
-BOOL gHttp2Enabled = YES;
-BOOL gQuicEnabled = NO;
-BOOL gBrotliEnabled = NO;
-cronet::URLRequestContextConfig::HttpCacheType gHttpCache =
-    cronet::URLRequestContextConfig::HttpCacheType::DISK;
-QuicHintVector gQuicHints;
-NSString* gExperimentalOptions = @"{}";
-NSString* gUserAgent = nil;
-BOOL gUserAgentPartial = NO;
-NSString* gSslKeyLogFileName = nil;
-std::vector<std::unique_ptr<cronet::URLRequestContextConfig::Pkp>> gPkpList;
-RequestFilterBlock gRequestFilterBlock = nil;
 base::LazyInstance<std::unique_ptr<CronetHttpProtocolHandlerDelegate>>::Leaky
     gHttpProtocolHandlerDelegate = LAZY_INSTANCE_INITIALIZER;
-NSURLCache* gPreservedSharedURLCache = nil;
-BOOL gEnableTestCertVerifierForTesting = NO;
+
+// See [Cronet initialize] method to set the default values of the global
+// variables.
+BOOL gHttp2Enabled;
+BOOL gQuicEnabled;
+BOOL gBrotliEnabled;
+cronet::URLRequestContextConfig::HttpCacheType gHttpCache;
+QuicHintVector gQuicHints;
+NSString* gExperimentalOptions;
+NSString* gUserAgent;
+BOOL gUserAgentPartial;
+NSString* gSslKeyLogFileName;
+std::vector<std::unique_ptr<cronet::URLRequestContextConfig::Pkp>> gPkpList;
+RequestFilterBlock gRequestFilterBlock;
+NSURLCache* gPreservedSharedURLCache;
+BOOL gEnableTestCertVerifierForTesting;
 std::unique_ptr<net::CertVerifier> gMockCertVerifier;
-NSString* gAcceptLanguages = nil;
-BOOL gEnablePKPBypassForLocalTrustAnchors = YES;
+NSString* gAcceptLanguages;
+BOOL gEnablePKPBypassForLocalTrustAnchors;
 
 // CertVerifier, which allows any certificates for testing.
 class TestCertVerifier : public net::CertVerifier {
@@ -255,9 +254,11 @@
 
   // Pinning a key only makes sense if pin bypassing has been disabled
   if (gEnablePKPBypassForLocalTrustAnchors) {
-    *outError =
-        [self createUnsupportedConfigurationError:
-                  @"Cannot pin keys while public key pinning is bypassed"];
+    if (outError != nil) {
+      *outError =
+          [self createUnsupportedConfigurationError:
+                    @"Cannot pin keys while public key pinning is bypassed"];
+    }
     return NO;
   }
 
@@ -290,6 +291,10 @@
   gEnablePKPBypassForLocalTrustAnchors = enable;
 }
 
++ (base::SingleThreadTaskRunner*)getFileThreadRunnerForTesting {
+  return gChromeNet.Get()->GetFileThreadRunnerForTesting();
+}
+
 + (void)startInternal {
   std::string user_agent = base::SysNSStringToUTF8(gUserAgent);
 
@@ -342,7 +347,7 @@
 }
 
 + (void)shutdownForTesting {
-  gChromeNet.Get().reset();
+  [Cronet initialize];
 }
 
 + (void)registerHttpProtocolHandler {
@@ -481,4 +486,26 @@
                          userInfo:userInfo];
 }
 
+// Static class initializer.
++ (void)initialize {
+  gChromeNet.Get().reset();
+  gHttp2Enabled = YES;
+  gQuicEnabled = NO;
+  gBrotliEnabled = NO;
+  gHttpCache = cronet::URLRequestContextConfig::HttpCacheType::DISK;
+  gQuicHints.clear();
+  gExperimentalOptions = @"{}";
+  gUserAgent = nil;
+  gUserAgentPartial = NO;
+  gSslKeyLogFileName = nil;
+  gPkpList.clear();
+  gRequestFilterBlock = nil;
+  gHttpProtocolHandlerDelegate.Get().reset(nullptr);
+  gPreservedSharedURLCache = nil;
+  gEnableTestCertVerifierForTesting = NO;
+  gMockCertVerifier.reset(nullptr);
+  gAcceptLanguages = nil;
+  gEnablePKPBypassForLocalTrustAnchors = YES;
+}
+
 @end
diff --git a/components/cronet/ios/cronet_environment.h b/components/cronet/ios/cronet_environment.h
index 160d5a9..5ecc0ea 100644
--- a/components/cronet/ios/cronet_environment.h
+++ b/components/cronet/ios/cronet_environment.h
@@ -32,6 +32,8 @@
 }  // namespace net
 
 namespace cronet {
+class CronetPrefsManager;
+
 // CronetEnvironment contains all the network stack configuration
 // and initialization.
 class CronetEnvironment {
@@ -117,6 +119,9 @@
   // Return the URLRequestContextGetter associated with this object.
   net::URLRequestContextGetter* GetURLRequestContextGetter() const;
 
+  // Used by Cronet tests.
+  base::SingleThreadTaskRunner* GetFileThreadRunnerForTesting() const;
+
  private:
   // Performs initialization tasks that must happen on the network thread.
   void InitializeOnNetworkThread();
@@ -128,10 +133,6 @@
   void PostToNetworkThread(const tracked_objects::Location& from_here,
                            const base::Closure& task);
 
-  // Runs a closure on the file user blocking thread.
-  void PostToFileUserBlockingThread(const tracked_objects::Location& from_here,
-                                    const base::Closure& task);
-
   // Helper methods that start/stop net logging on the network thread.
   void StartNetLogOnNetworkThread(const base::FilePath&, bool log_bytes);
   void StopNetLogOnNetworkThread(base::WaitableEvent* log_stopped_event);
@@ -147,6 +148,8 @@
 
   std::string getDefaultQuicUserAgentId() const;
 
+  void PrepareForDestroyOnNetworkThread();
+
   bool http2_enabled_;
   bool quic_enabled_;
   bool brotli_enabled_;
@@ -160,8 +163,7 @@
   std::list<net::HostPortPair> quic_hints_;
 
   std::unique_ptr<base::Thread> network_io_thread_;
-  std::unique_ptr<base::Thread> network_cache_thread_;
-  std::unique_ptr<base::Thread> file_user_blocking_thread_;
+  std::unique_ptr<base::Thread> file_thread_;
   scoped_refptr<base::SequencedTaskRunner> pref_store_worker_pool_;
   std::unique_ptr<net::CertVerifier> mock_cert_verifier_;
   std::unique_ptr<net::CookieStore> cookie_store_;
@@ -172,6 +174,7 @@
   std::unique_ptr<net::NetLog> net_log_;
   std::unique_ptr<net::FileNetLogObserver> file_net_log_observer_;
   bool enable_pkp_bypass_for_local_trust_anchors_;
+  std::unique_ptr<CronetPrefsManager> cronet_prefs_manager_;
 
   DISALLOW_COPY_AND_ASSIGN(CronetEnvironment);
 };
diff --git a/components/cronet/ios/cronet_environment.mm b/components/cronet/ios/cronet_environment.mm
index 98ab86b..e4f7324 100644
--- a/components/cronet/ios/cronet_environment.mm
+++ b/components/cronet/ios/cronet_environment.mm
@@ -13,7 +13,6 @@
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_file.h"
-#include "base/json/json_writer.h"
 #include "base/mac/bind_objc_block.h"
 #include "base/mac/foundation_util.h"
 #include "base/macros.h"
@@ -23,9 +22,9 @@
 #include "base/path_service.h"
 #include "base/single_thread_task_runner.h"
 #include "base/synchronization/waitable_event.h"
+#include "components/cronet/cronet_prefs_manager.h"
 #include "components/cronet/histogram_manager.h"
 #include "components/cronet/ios/version.h"
-#include "components/prefs/json_pref_store.h"
 #include "components/prefs/pref_filter.h"
 #include "ios/net/cookies/cookie_store_ios.h"
 #include "ios/web/public/global_state/ios_global_state.h"
@@ -113,12 +112,6 @@
   GetNetworkThreadTaskRunner()->PostTask(from_here, task);
 }
 
-void CronetEnvironment::PostToFileUserBlockingThread(
-    const tracked_objects::Location& from_here,
-    const base::Closure& task) {
-  file_user_blocking_thread_->task_runner()->PostTask(from_here, task);
-}
-
 net::URLRequestContext* CronetEnvironment::GetURLRequestContext() const {
   return main_context_.get();
 }
@@ -233,8 +226,8 @@
 
 void CronetEnvironment::Start() {
   // Threads setup.
-  network_cache_thread_.reset(new base::Thread("Chrome Network Cache Thread"));
-  network_cache_thread_->StartWithOptions(
+  file_thread_.reset(new base::Thread("Chrome File Thread"));
+  file_thread_->StartWithOptions(
       base::Thread::Options(base::MessageLoop::TYPE_IO, 0));
   // Fetching the task_runner will create the shared thread if necessary.
   scoped_refptr<base::SingleThreadTaskRunner> task_runner =
@@ -244,10 +237,6 @@
     network_io_thread_->StartWithOptions(
         base::Thread::Options(base::MessageLoop::TYPE_IO, 0));
   }
-  file_user_blocking_thread_.reset(
-      new base::Thread("Chrome File User Blocking Thread"));
-  file_user_blocking_thread_->StartWithOptions(
-      base::Thread::Options(base::MessageLoop::TYPE_IO, 0));
 
   main_context_getter_ = new CronetURLRequestContextGetter(
       this, CronetEnvironment::GetNetworkThreadTaskRunner());
@@ -257,7 +246,7 @@
                                  base::Unretained(this)));
 }
 
-CronetEnvironment::~CronetEnvironment() {
+void CronetEnvironment::PrepareForDestroyOnNetworkThread() {
   // TODO(lilyhoughton) make unregistering of this work.
   // net::HTTPProtocolHandlerDelegate::SetInstance(nullptr);
 
@@ -267,12 +256,29 @@
   // if (ts)
   //  ts->Shutdown();
 
+  if (cronet_prefs_manager_) {
+    cronet_prefs_manager_->PrepareForShutdown();
+  }
+
+  // cronet_prefs_manager_ should be deleted on the network thread.
+  cronet_prefs_manager_.reset(nullptr);
+
+  file_thread_.reset(nullptr);
+
   // TODO(lilyhoughton) this should be smarter about making sure there are no
   // pending requests, etc.
+  main_context_.reset(nullptr);
+}
 
+CronetEnvironment::~CronetEnvironment() {
+  PostToNetworkThread(
+      FROM_HERE,
+      base::Bind(&CronetEnvironment::PrepareForDestroyOnNetworkThread,
+                 base::Unretained(this)));
   if (network_io_thread_) {
-    network_io_thread_->task_runner().get()->DeleteSoon(
-        FROM_HERE, main_context_.release());
+    // Deleting a thread blocks the current thread and waits until all pending
+    // tasks are completed.
+    network_io_thread_.reset(nullptr);
   }
 }
 
@@ -290,17 +296,17 @@
     user_agent_ = web::BuildUserAgentFromProduct(user_agent_);
 
   // Cache
-  base::FilePath cache_path;
-  if (!PathService::Get(base::DIR_CACHE, &cache_path))
+  base::FilePath storage_path;
+  if (!PathService::Get(base::DIR_CACHE, &storage_path))
     return;
-  cache_path = cache_path.Append(FILE_PATH_LITERAL("cronet"));
+  storage_path = storage_path.Append(FILE_PATH_LITERAL("cronet"));
 
   URLRequestContextConfigBuilder context_config_builder;
   context_config_builder.enable_quic = quic_enabled_;   // Enable QUIC.
   context_config_builder.enable_spdy = http2_enabled_;  // Enable HTTP/2.
   context_config_builder.http_cache = http_cache_;      // Set HTTP cache
   context_config_builder.storage_path =
-      cache_path.value();  // Storage path for http cache and cookie storage.
+      storage_path.value();  // Storage path for http cache and prefs storage.
   context_config_builder.user_agent =
       user_agent_;  // User-Agent request header field.
   context_config_builder.experimental_options =
@@ -328,6 +334,13 @@
       new net::MappedHostResolver(
           net::HostResolver::CreateDefaultResolver(nullptr)));
 
+  if (!config->storage_path.empty()) {
+    cronet_prefs_manager_ = std::make_unique<CronetPrefsManager>(
+        config->storage_path, GetNetworkThreadTaskRunner(),
+        file_thread_->task_runner(), false /* nqe */, false /* host_cache */,
+        net_log_.get(), &context_builder);
+  }
+
   context_builder.set_host_resolver(std::move(mapped_host_resolver));
 
   // TODO(690969): This behavior matches previous behavior of CookieStoreIOS in
@@ -340,8 +353,8 @@
           [NSHTTPCookieStorage sharedHTTPCookieStorage]);
   context_builder.SetCookieAndChannelIdStores(std::move(cookie_store), nullptr);
 
-  std::unique_ptr<net::HttpServerProperties> http_server_properties(
-      new net::HttpServerPropertiesImpl());
+  context_builder.set_enable_brotli(brotli_enabled_);
+  main_context_ = context_builder.Build();
 
   for (const auto& quic_hint : quic_hints_) {
     url::CanonHostInfo host_info;
@@ -357,16 +370,11 @@
 
     url::SchemeHostPort quic_hint_server("https", quic_hint.host(),
                                          quic_hint.port());
-    http_server_properties->SetQuicAlternativeService(
+    main_context_->http_server_properties()->SetQuicAlternativeService(
         quic_hint_server, alternative_service, base::Time::Max(),
         net::QuicVersionVector());
   }
 
-  context_builder.SetHttpServerProperties(std::move(http_server_properties));
-
-  context_builder.set_enable_brotli(brotli_enabled_);
-  main_context_ = context_builder.Build();
-
   main_context_->transport_security_state()
       ->SetEnablePublicKeyPinningBypassForLocalTrustAnchors(
           enable_pkp_bypass_for_local_trust_anchors_);
@@ -422,4 +430,9 @@
          " Cronet/" + CRONET_VERSION;
 }
 
+base::SingleThreadTaskRunner* CronetEnvironment::GetFileThreadRunnerForTesting()
+    const {
+  return file_thread_->task_runner().get();
+}
+
 }  // namespace cronet
diff --git a/components/cronet/ios/test/BUILD.gn b/components/cronet/ios/test/BUILD.gn
index a0b2954b..607f355 100644
--- a/components/cronet/ios/test/BUILD.gn
+++ b/components/cronet/ios/test/BUILD.gn
@@ -12,6 +12,7 @@
     "cronet_http_test.mm",
     "cronet_netlog_test.mm",
     "cronet_pkp_test.mm",
+    "cronet_prefs_test.mm",
     "cronet_quic_test.mm",
     "cronet_test_base.mm",
     "cronet_test_runner.mm",
diff --git a/components/cronet/ios/test/cronet_pkp_test.mm b/components/cronet/ios/test/cronet_pkp_test.mm
index baf896a..a430a51 100644
--- a/components/cronet/ios/test/cronet_pkp_test.mm
+++ b/components/cronet/ios/test/cronet_pkp_test.mm
@@ -4,9 +4,9 @@
 
 #import <Cronet/Cronet.h>
 
+#include "components/cronet/ios/test/cronet_test_base.h"
 #include "components/cronet/ios/test/start_cronet.h"
 #include "components/grpc_support/test/quic_test_server.h"
-#include "cronet_test_base.h"
 #include "net/base/mac/url_conversions.h"
 #include "net/cert/mock_cert_verifier.h"
 #include "net/test/cert_test_util.h"
@@ -210,6 +210,7 @@
 
 // Tests that an error is returned when PKP hash size is not equal to 256 bits.
 TEST_F(PkpTest, TestHashLengthError) {
+  [Cronet setEnablePublicKeyPinningBypassForLocalTrustAnchors:NO];
   char hash[31];
   NSData* shortHash = [NSData dataWithBytes:hash length:sizeof(hash)];
   NSSet* hashes = [NSSet setWithObject:shortHash];
@@ -235,6 +236,7 @@
 // Tests that setting pins for the same host second time overrides the previous
 // pins.
 TEST_F(PkpTest, TestPkpOverrideNonMatchingToMatching) {
+  [Cronet setEnablePublicKeyPinningBypassForLocalTrustAnchors:NO];
   // Add non-matching pin.
   BOOL success =
       [Cronet addPublicKeyPinsForHost:server_host_
@@ -252,6 +254,7 @@
 // Tests that setting pins for the same host second time overrides the previous
 // pins.
 TEST_F(PkpTest, TestPkpOverrideMatchingToNonMatching) {
+  [Cronet setEnablePublicKeyPinningBypassForLocalTrustAnchors:NO];
   // Add matching pin.
   BOOL success =
       [Cronet addPublicKeyPinsForHost:server_host_
diff --git a/components/cronet/ios/test/cronet_prefs_test.mm b/components/cronet/ios/test/cronet_prefs_test.mm
new file mode 100644
index 0000000..494c85e
--- /dev/null
+++ b/components/cronet/ios/test/cronet_prefs_test.mm
@@ -0,0 +1,146 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/path_service.h"
+#include "base/threading/thread.h"
+#include "components/cronet/ios/test/cronet_test_base.h"
+#include "components/cronet/ios/test/start_cronet.h"
+#include "components/cronet/ios/test/test_server.h"
+#include "components/grpc_support/test/quic_test_server.h"
+#include "net/base/mac/url_conversions.h"
+#include "testing/gtest_mac.h"
+#include "url/gurl.h"
+
+namespace {
+typedef void (^BlockType)(void);
+}  // namespace
+
+namespace cronet {
+class PrefsTest : public CronetTestBase {
+ protected:
+  void SetUp() override {
+    CronetTestBase::SetUp();
+    TestServer::Start();
+
+    [Cronet setRequestFilterBlock:^(NSURLRequest* request) {
+      return YES;
+    }];
+    NSURLSessionConfiguration* config =
+        [NSURLSessionConfiguration ephemeralSessionConfiguration];
+    [Cronet installIntoSessionConfiguration:config];
+    session_ = [NSURLSession sessionWithConfiguration:config
+                                             delegate:delegate_
+                                        delegateQueue:nil];
+  }
+
+  void TearDown() override {
+    TestServer::Shutdown();
+    [Cronet stopNetLog];
+    [Cronet shutdownForTesting];
+    CronetTestBase::TearDown();
+  }
+
+  NSString* GetFileContentWaitUntilCreated(NSString* file,
+                                           NSTimeInterval timeout,
+                                           NSError** error) {
+    // Wait until the file appears on disk.
+    NSFileManager* file_manager = [NSFileManager defaultManager];
+    NSLog(@"Waiting for file %@.", file);
+    while (timeout > 0) {
+      if ([file_manager fileExistsAtPath:file]) {
+        NSLog(@"File %@ exists.", file);
+        break;
+      }
+      NSLog(@"Time left: %i seconds", (int)timeout);
+      NSTimeInterval sleep_interval = fmin(5.0, timeout);
+      [NSThread sleepForTimeInterval:sleep_interval];
+      timeout -= sleep_interval;
+    }
+
+    // Read the file on the file thread to avoid reading the changing file.
+    dispatch_semaphore_t lock = dispatch_semaphore_create(0);
+    __block NSString* file_content = nil;
+    __block NSError* block_error = nil;
+    base::SingleThreadTaskRunner* file_runner =
+        [Cronet getFileThreadRunnerForTesting];
+    file_runner->PostTask(
+        FROM_HERE,
+        base::Bind(&PrefsTest::ExecuteBlockOnFileThread, base::Unretained(this),
+                   ^{
+                     file_content =
+                         [NSString stringWithContentsOfFile:file
+                                                   encoding:NSUTF8StringEncoding
+                                                      error:&block_error];
+                     dispatch_semaphore_signal(lock);
+                   }));
+
+    // Wait for the file thread to finish reading the file content.
+    dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);
+    if (block_error) {
+      *error = block_error;
+    }
+    return file_content;
+  }
+
+  void ExecuteBlockOnFileThread(BlockType block) { block(); }
+
+  NSURLSession* session_;
+};
+
+TEST_F(PrefsTest, HttpSeverProperties) {
+  base::FilePath storage_path;
+  bool result = PathService::Get(base::DIR_CACHE, &storage_path);
+  ASSERT_TRUE(result);
+  storage_path =
+      storage_path.Append(FILE_PATH_LITERAL("cronet/prefs/local_prefs.json"));
+  NSString* prefs_file_name =
+      [NSString stringWithCString:storage_path.AsUTF8Unsafe().c_str()
+                         encoding:NSUTF8StringEncoding];
+
+  // Delete the prefs file if it exists.
+  [[NSFileManager defaultManager] removeItemAtPath:prefs_file_name error:nil];
+
+  // Add "max_server_configs_stored_in_properties" experimental option.
+  NSString* options =
+      @"{ \"QUIC\" : {\"max_server_configs_stored_in_properties\" : 5} }";
+  [Cronet setExperimentalOptions:options];
+
+  // Start Cronet Engine
+  StartCronet(grpc_support::GetQuicTestServerPort());
+
+  // Start the request
+  NSURL* url = net::NSURLWithGURL(GURL(grpc_support::kTestServerSimpleUrl));
+  NSURLSessionDataTask* task = [session_ dataTaskWithURL:url];
+  StartDataTaskAndWaitForCompletion(task);
+
+  // Wait 80 seconds for the prefs file to appear on the disk.
+  NSError* error = nil;
+  NSString* prefs_file_content =
+      GetFileContentWaitUntilCreated(prefs_file_name, 80, &error);
+  ASSERT_FALSE(error) << "Unable to read " << storage_path << " file. Error: "
+                      << error.localizedDescription.UTF8String;
+
+  // Check the file content
+  ASSERT_TRUE(prefs_file_content);
+  ASSERT_TRUE(
+      [prefs_file_content rangeOfString:@"{\"http_server_properties\":{"]
+          .location != NSNotFound)
+      << "Unable to find 'http_server_properties' in the JSON prefs.";
+  ASSERT_TRUE(
+      [prefs_file_content rangeOfString:@"\"supports_quic\":{\"address\""
+                                         ":\"127.0.0.1\",\"used_quic\":true}"]
+          .location != NSNotFound)
+      << "Unable to find 'supports_quic' in the JSON prefs.";
+  ASSERT_TRUE(
+      [prefs_file_content rangeOfString:@"{\"server_info\":\""].location !=
+      NSNotFound)
+      << "Unable to find 'server_info' in the JSON prefs.";
+
+  // Delete the prefs file to avoid side effects with other tests.
+  [[NSFileManager defaultManager] removeItemAtPath:prefs_file_name error:nil];
+}
+
+}  // namespace cronet
diff --git a/components/cronet/ios/test/cronet_test_base.h b/components/cronet/ios/test/cronet_test_base.h
index 8735f07..1580e78 100644
--- a/components/cronet/ios/test/cronet_test_base.h
+++ b/components/cronet/ios/test/cronet_test_base.h
@@ -12,12 +12,18 @@
 
 #pragma mark
 
+namespace base {
+class SingleThreadTaskRunner;
+class Thread;
+}
+
 // Exposes private test-only methods of the Cronet class.
 @interface Cronet (ExposedForTesting)
 + (void)shutdownForTesting;
 + (void)setMockCertVerifierForTesting:
     (std::unique_ptr<net::CertVerifier>)certVerifier;
 + (void)setEnablePublicKeyPinningBypassForLocalTrustAnchors:(BOOL)enable;
++ (base::SingleThreadTaskRunner*)getFileThreadRunnerForTesting;
 @end
 
 // NSURLSessionDataDelegate delegate implementation used by the tests to
diff --git a/components/cronet/ios/test/cronet_test_runner.mm b/components/cronet/ios/test/cronet_test_runner.mm
index aca8fee..175a976e 100644
--- a/components/cronet/ios/test/cronet_test_runner.mm
+++ b/components/cronet/ios/test/cronet_test_runner.mm
@@ -1,15 +1,15 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/at_exit.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/gtest_mac.h"
-
-base::AtExitManager* g_at_exit_ = nullptr;
+#include "base/bind.h"
+#include "base/test/launcher/unit_test_launcher.h"
+#include "base/test/test_suite.h"
 
 int main(int argc, char* argv[]) {
-  g_at_exit_ = new base::AtExitManager;
-  ::testing::InitGoogleTest(&argc, argv);
-  return RUN_ALL_TESTS();
+  base::TestSuite test_suite(argc, argv);
+
+  return base::LaunchUnitTests(
+      argc, argv,
+      base::Bind(&base::TestSuite::Run, base::Unretained(&test_suite)));
 }
diff --git a/components/history/core/browser/browsing_history_service.cc b/components/history/core/browser/browsing_history_service.cc
index 0596d86..96b43ef 100644
--- a/components/history/core/browser/browsing_history_service.cc
+++ b/components/history/core/browser/browsing_history_service.cc
@@ -172,7 +172,7 @@
     local_history_->QueryHistory(
         search_text, options,
         base::Bind(&BrowsingHistoryService::QueryComplete,
-                   base::Unretained(this), search_text, options),
+                   weak_factory_.GetWeakPtr(), search_text, options),
         &query_task_tracker_);
   }
 
@@ -219,7 +219,8 @@
     web_history_request_ = web_history->QueryHistory(
         search_text, options,
         base::Bind(&BrowsingHistoryService::WebHistoryQueryComplete,
-                   base::Unretained(this), search_text, options, clock_->Now()),
+                   weak_factory_.GetWeakPtr(), search_text, options,
+                   clock_->Now()),
         partial_traffic_annotation);
 
     // Test the existence of other forms of browsing history.
@@ -294,7 +295,7 @@
     local_history_->ExpireHistory(
         expire_list,
         base::Bind(&BrowsingHistoryService::RemoveComplete,
-                   base::Unretained(this)),
+                   weak_factory_.GetWeakPtr()),
         &delete_task_tracker_);
   }
 
@@ -398,15 +399,6 @@
 
   query_results_info_.search_text = search_text;
   query_results_info_.reached_beginning_of_local = results->reached_beginning();
-  query_results_info_.start_time = options.begin_time;
-  // TODO(skym): |end_time| doesn't seem to be used anymore, and this logic's
-  // intention is very confusing. Consider removing.
-  if (!options.end_time.is_null()) {
-    query_results_info_.end_time =
-        options.end_time - base::TimeDelta::FromDays(1);
-  } else {
-    query_results_info_.end_time = clock_->Now();
-  }
 
   if (!web_history_timer_.IsRunning())
     ReturnResultsToDriver();
diff --git a/components/history/core/browser/browsing_history_service.h b/components/history/core/browser/browsing_history_service.h
index a4c778bf..42ea9ff 100644
--- a/components/history/core/browser/browsing_history_service.h
+++ b/components/history/core/browser/browsing_history_service.h
@@ -124,12 +124,6 @@
 
     // Whether the query reached the beginning of the synced history results.
     bool reached_beginning_of_sync = false;
-
-    // The localized query start time.
-    base::Time start_time;
-
-    // The localized query end time.
-    base::Time end_time;
   };
 
   BrowsingHistoryService(BrowsingHistoryDriver* driver,
diff --git a/components/metrics/metrics_service.cc b/components/metrics/metrics_service.cc
index c4a9194..7f604e7 100644
--- a/components/metrics/metrics_service.cc
+++ b/components/metrics/metrics_service.cc
@@ -259,11 +259,9 @@
 }
 
 void MetricsService::Start() {
-  base::StatisticsRecorder::ValidateAllHistograms();
   HandleIdleSinceLastTransmission(false);
   EnableRecording();
   EnableReporting();
-  base::StatisticsRecorder::ValidateAllHistograms();
 }
 
 void MetricsService::StartRecordingForTests() {
@@ -273,11 +271,9 @@
 }
 
 void MetricsService::Stop() {
-  base::StatisticsRecorder::ValidateAllHistograms();
   HandleIdleSinceLastTransmission(false);
   DisableReporting();
   DisableRecording();
-  base::StatisticsRecorder::ValidateAllHistograms();
 }
 
 void MetricsService::EnableReporting() {
@@ -389,7 +385,6 @@
 
 #if defined(OS_ANDROID) || defined(OS_IOS)
 void MetricsService::OnAppEnterBackground() {
-  base::StatisticsRecorder::ValidateAllHistograms();
   rotation_scheduler_->Stop();
   reporting_service_.Stop();
 
@@ -411,15 +406,12 @@
     // process is killed.
     OpenNewLog();
   }
-  base::StatisticsRecorder::ValidateAllHistograms();
 }
 
 void MetricsService::OnAppEnterForeground() {
-  base::StatisticsRecorder::ValidateAllHistograms();
   state_manager_->clean_exit_beacon()->WriteBeaconValue(false);
   ExecutionPhaseManager(local_state_).OnAppEnterForeground();
   StartSchedulerIfNecessary();
-  base::StatisticsRecorder::ValidateAllHistograms();
 }
 #else
 void MetricsService::LogNeedForCleanShutdown() {
@@ -597,7 +589,6 @@
 
 void MetricsService::OpenNewLog() {
   DCHECK(!log_manager_.current_log());
-  base::StatisticsRecorder::ValidateAllHistograms();
 
   log_manager_.BeginLoggingWithLog(CreateLog(MetricsLog::ONGOING_LOG));
   delegating_provider_.OnDidCreateMetricsLog();
@@ -616,8 +607,6 @@
                    self_ptr_factory_.GetWeakPtr()),
         base::TimeDelta::FromSeconds(2 * kInitializationDelaySeconds));
   }
-
-  base::StatisticsRecorder::ValidateAllHistograms();
 }
 
 void MetricsService::StartInitTask() {
@@ -626,8 +615,6 @@
 }
 
 void MetricsService::CloseCurrentLog() {
-  base::StatisticsRecorder::ValidateAllHistograms();
-
   if (!log_manager_.current_log())
     return;
 
@@ -654,8 +641,6 @@
   current_log->TruncateEvents();
   DVLOG(1) << "Generated an ongoing log.";
   log_manager_.FinishCurrentLog(log_store());
-
-  base::StatisticsRecorder::ValidateAllHistograms();
 }
 
 void MetricsService::PushPendingLogsToPersistentStorage() {
@@ -687,7 +672,7 @@
 void MetricsService::StartScheduledUpload() {
   DVLOG(1) << "StartScheduledUpload";
   DCHECK(state_ >= INIT_TASK_DONE);
-  base::StatisticsRecorder::ValidateAllHistograms();
+
   // If we're getting no notifications, then the log won't have much in it, and
   // it's possible the computer is about to go to sleep, so don't upload and
   // stop the scheduler.
@@ -715,13 +700,11 @@
         base::Bind(&MetricsService::OnFinalLogInfoCollectionDone,
                    self_ptr_factory_.GetWeakPtr()));
   }
-
-  base::StatisticsRecorder::ValidateAllHistograms();
 }
 
 void MetricsService::OnFinalLogInfoCollectionDone() {
   DVLOG(1) << "OnFinalLogInfoCollectionDone";
-  base::StatisticsRecorder::ValidateAllHistograms();
+
   // Abort if metrics were turned off during the final info gathering.
   if (!recording_active()) {
     rotation_scheduler_->Stop();
@@ -739,7 +722,6 @@
   reporting_service_.Start();
   rotation_scheduler_->RotationFinished();
   HandleIdleSinceLastTransmission(true);
-  base::StatisticsRecorder::ValidateAllHistograms();
 }
 
 bool MetricsService::PrepareInitialStabilityLog(
diff --git a/components/printing/service/public/cpp/pdf_compositor_service_factory.cc b/components/printing/service/public/cpp/pdf_compositor_service_factory.cc
index f832f86..555394c 100644
--- a/components/printing/service/public/cpp/pdf_compositor_service_factory.cc
+++ b/components/printing/service/public/cpp/pdf_compositor_service_factory.cc
@@ -16,7 +16,7 @@
   content::UtilityThread::Get()->EnsureBlinkInitialized();
   // Hook up blink's codecs so skia can call them.
   SkGraphics::SetImageGeneratorFromEncodedDataFactory(
-      blink::WebImageGenerator::Create);
+      blink::WebImageGenerator::CreateAsSkImageGenerator);
   return printing::PdfCompositorService::Create(creator);
 }
 
diff --git a/components/subresource_filter/content/browser/fake_safe_browsing_database_manager.cc b/components/subresource_filter/content/browser/fake_safe_browsing_database_manager.cc
index 14c9cab3..49e98b75 100644
--- a/components/subresource_filter/content/browser/fake_safe_browsing_database_manager.cc
+++ b/components/subresource_filter/content/browser/fake_safe_browsing_database_manager.cc
@@ -15,8 +15,17 @@
 void FakeSafeBrowsingDatabaseManager::AddBlacklistedUrl(
     const GURL& url,
     safe_browsing::SBThreatType threat_type,
+    const safe_browsing::ThreatMetadata& metadata) {
+  url_to_threat_type_[url] = std::make_pair(threat_type, metadata);
+}
+
+void FakeSafeBrowsingDatabaseManager::AddBlacklistedUrl(
+    const GURL& url,
+    safe_browsing::SBThreatType threat_type,
     safe_browsing::ThreatPatternType pattern_type) {
-  url_to_threat_type_[url] = std::make_pair(threat_type, pattern_type);
+  safe_browsing::ThreatMetadata metadata;
+  metadata.threat_pattern_type = pattern_type;
+  AddBlacklistedUrl(url, threat_type, metadata);
 }
 
 void FakeSafeBrowsingDatabaseManager::RemoveBlacklistedUrl(const GURL& url) {
@@ -68,7 +77,7 @@
   auto it = url_to_threat_type_.find(url);
   if (it != url_to_threat_type_.end()) {
     threat_type = it->second.first;
-    metadata.threat_pattern_type = it->second.second;
+    metadata = it->second.second;
   }
   client->OnCheckBrowseUrlResult(url, threat_type, metadata);
 
diff --git a/components/subresource_filter/content/browser/fake_safe_browsing_database_manager.h b/components/subresource_filter/content/browser/fake_safe_browsing_database_manager.h
index d28c028..4409468 100644
--- a/components/subresource_filter/content/browser/fake_safe_browsing_database_manager.h
+++ b/components/subresource_filter/content/browser/fake_safe_browsing_database_manager.h
@@ -23,6 +23,9 @@
 
   void AddBlacklistedUrl(const GURL& url,
                          safe_browsing::SBThreatType threat_type,
+                         const safe_browsing::ThreatMetadata& metadata);
+  void AddBlacklistedUrl(const GURL& url,
+                         safe_browsing::SBThreatType threat_type,
                          safe_browsing::ThreatPatternType pattern_type =
                              safe_browsing::ThreatPatternType::NONE);
   void RemoveBlacklistedUrl(const GURL& url);
@@ -56,7 +59,7 @@
   std::set<Client*> checks_;
   std::map<
       GURL,
-      std::pair<safe_browsing::SBThreatType, safe_browsing::ThreatPatternType>>
+      std::pair<safe_browsing::SBThreatType, safe_browsing::ThreatMetadata>>
       url_to_threat_type_;
   bool simulate_timeout_ = false;
   bool synchronous_failure_ = false;
diff --git a/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.cc b/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.cc
index 04dd48c..df027958 100644
--- a/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.cc
+++ b/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.cc
@@ -242,24 +242,26 @@
   const GURL& url(navigation_handle()->GetURL());
   ActivationList matched_list = ActivationList::NONE;
   DCHECK(!database_client_ || !check_results_.empty());
+  bool experimental_list = false;
   if (!check_results_.empty()) {
-    DCHECK(check_results_.back().finished);
-    matched_list =
-        GetListForThreatTypeAndMetadata(check_results_.back().threat_type,
-                                        check_results_.back().threat_metadata);
+    const auto& check_result = check_results_.back();
+    DCHECK(check_result.finished);
+    matched_list = GetListForThreatTypeAndMetadata(
+        check_result.threat_type, check_result.threat_metadata);
+    experimental_list = check_result.threat_metadata.experimental;
   }
 
   const auto config_list = GetEnabledConfigurations();
   bool scheme_is_http_or_https = url.SchemeIsHTTPOrHTTPS();
-  const auto highest_priority_activated_config =
-      std::find_if(config_list->configs_by_decreasing_priority().begin(),
-                   config_list->configs_by_decreasing_priority().end(),
-                   [&url, scheme_is_http_or_https, matched_list,
-                    this](const Configuration& config) {
-                     return DoesMainFrameURLSatisfyActivationConditions(
-                         url, scheme_is_http_or_https,
-                         config.activation_conditions, matched_list);
-                   });
+  const auto highest_priority_activated_config = std::find_if(
+      config_list->configs_by_decreasing_priority().begin(),
+      config_list->configs_by_decreasing_priority().end(),
+      [&url, scheme_is_http_or_https, matched_list, experimental_list,
+       this](const Configuration& config) {
+        return DoesMainFrameURLSatisfyActivationConditions(
+            url, scheme_is_http_or_https, config.activation_conditions,
+            matched_list, experimental_list);
+      });
 
   bool has_activated_config =
       highest_priority_activated_config !=
@@ -293,7 +295,8 @@
         const GURL& url,
         bool scheme_is_http_or_https,
         const Configuration::ActivationConditions& conditions,
-        ActivationList matched_list) const {
+        ActivationList matched_list,
+        bool experimental_list) const {
   // Avoid copies when tracing disabled.
   auto list_to_string = [](ActivationList activation_list) {
     std::ostringstream matched_list_stream;
@@ -314,8 +317,15 @@
         return false;
       if (matched_list == ActivationList::NONE)
         return false;
-      if (conditions.activation_list == matched_list)
-        return true;
+
+      // Normal match. Make sure that if the list is experimental, we only match
+      // if our activation conditions also specify that we support experimental
+      // lists.
+      if (conditions.activation_list == matched_list) {
+        return !experimental_list || conditions.experimental;
+      }
+
+      // Phishing / SocEng lists don't have experimental metadata.
       if (conditions.activation_list == ActivationList::PHISHING_INTERSTITIAL &&
           matched_list == ActivationList::SOCIAL_ENG_ADS_INTERSTITIAL) {
         // Handling special case, where activation on the phishing sites also
diff --git a/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.h b/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.h
index e9feaef..bd5f519 100644
--- a/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.h
+++ b/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.h
@@ -73,7 +73,8 @@
       const GURL& url,
       bool scheme_is_http_or_https,
       const Configuration::ActivationConditions& conditions,
-      ActivationList matched_list) const;
+      ActivationList matched_list,
+      bool experimental_list) const;
 
   std::vector<SubresourceFilterSafeBrowsingClient::CheckResult> check_results_;
 
diff --git a/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle_unittest.cc b/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle_unittest.cc
index a67823f..0f465a4d 100644
--- a/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle_unittest.cc
+++ b/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle_unittest.cc
@@ -797,6 +797,34 @@
                             0);
 }
 
+TEST_F(SubresourceFilterSafeBrowsingActivationThrottleTest,
+       ExperimentalMetadata) {
+  const GURL url("https://example.test/");
+
+  // Set the list metadata for |url| to be experimental.
+  safe_browsing::ThreatMetadata metadata;
+  metadata.experimental = true;
+  fake_safe_browsing_database()->AddBlacklistedUrl(
+      url, safe_browsing::SB_THREAT_TYPE_SUBRESOURCE_FILTER, metadata);
+
+  // Navigate without an experimental config.
+  SimulateStartAndExpectProceed(url);
+  SimulateCommitAndExpectProceed();
+  EXPECT_EQ(ActivationDecision::ACTIVATION_CONDITIONS_NOT_MET,
+            *observer()->GetPageActivationForLastCommittedLoad());
+
+  // Navigate with an experimental config.
+  Configuration config(ActivationLevel::ENABLED,
+                       ActivationScope::ACTIVATION_LIST,
+                       ActivationList::SUBRESOURCE_FILTER);
+  config.activation_conditions.experimental = true;
+  scoped_configuration()->ResetConfiguration(std::move(config));
+  SimulateStartAndExpectProceed(url);
+  SimulateCommitAndExpectProceed();
+  EXPECT_EQ(ActivationDecision::ACTIVATED,
+            *observer()->GetPageActivationForLastCommittedLoad());
+}
+
 TEST_P(SubresourceFilterSafeBrowsingActivationThrottleScopeTest,
        ActivateForScopeType) {
   const ActivationScopeTestData& test_data = GetParam();
diff --git a/components/subresource_filter/core/browser/subresource_filter_features.cc b/components/subresource_filter/core/browser/subresource_filter_features.cc
index aa706f3..0d35776 100644
--- a/components/subresource_filter/core/browser/subresource_filter_features.cc
+++ b/components/subresource_filter/core/browser/subresource_filter_features.cc
@@ -163,6 +163,10 @@
       ParseInt(TakeVariationParamOrReturnEmpty(
           params, kActivationPriorityParameterName));
 
+  configuration.activation_conditions.experimental =
+      ParseBool(TakeVariationParamOrReturnEmpty(
+          params, kActivationExperimentalParameterName));
+
   // ActivationOptions:
   configuration.activation_options.activation_level = ParseActivationLevel(
       TakeVariationParamOrReturnEmpty(params, kActivationLevelParameterName));
@@ -271,6 +275,7 @@
 const char kActivationListAllAds[] = "all_ads";
 
 const char kActivationPriorityParameterName[] = "activation_priority";
+const char kActivationExperimentalParameterName[] = "experimental";
 
 const char kPerformanceMeasurementRateParameterName[] =
     "performance_measurement_rate";
@@ -325,6 +330,7 @@
     return std::tie(config.activation_conditions.activation_scope,
                     config.activation_conditions.activation_list,
                     config.activation_conditions.priority,
+                    config.activation_conditions.experimental,
                     config.activation_options.activation_level,
                     config.activation_options.performance_measurement_rate,
                     config.activation_options.should_whitelist_site_on_reload,
@@ -346,6 +352,7 @@
   value->SetString("activation_scope", StreamToString(activation_scope));
   value->SetString("activation_list", StreamToString(activation_list));
   value->SetInteger("priority", priority);
+  value->SetBoolean("experimental", experimental);
   return value;
 }
 
diff --git a/components/subresource_filter/core/browser/subresource_filter_features.h b/components/subresource_filter/core/browser/subresource_filter_features.h
index 31216b8..82741bb 100644
--- a/components/subresource_filter/core/browser/subresource_filter_features.h
+++ b/components/subresource_filter/core/browser/subresource_filter_features.h
@@ -62,6 +62,9 @@
     // otherwise satisfied. A greater value indicates higher priority.
     int priority = 0;
 
+    // Whether to activate on SafeBrowsing lists with experimental metadata.
+    bool experimental = false;
+
     std::unique_ptr<base::trace_event::TracedValue> ToTracedValue() const;
   };
 
@@ -206,6 +209,7 @@
 extern const char kActivationListAllAds[];
 
 extern const char kActivationPriorityParameterName[];
+extern const char kActivationExperimentalParameterName[];
 
 extern const char kPerformanceMeasurementRateParameterName[];
 
diff --git a/components/viz/client/client_layer_tree_frame_sink.cc b/components/viz/client/client_layer_tree_frame_sink.cc
index 1d61f66..524b86f 100644
--- a/components/viz/client/client_layer_tree_frame_sink.cc
+++ b/components/viz/client/client_layer_tree_frame_sink.cc
@@ -129,10 +129,12 @@
   TRACE_EVENT_CATEGORY_GROUP_ENABLED(TRACE_DISABLED_BY_DEFAULT("cc.debug.ipc"),
                                      &tracing_enabled);
 
-  // TODO(gklassen): Use hit_test_data_provider_->GetHitTestData() to obtain
-  // hit-test data and send to |compositor_frame_sink_|.
+  mojom::HitTestRegionListPtr hit_test_region_list;
+  if (hit_test_data_provider_)
+    hit_test_region_list = hit_test_data_provider_->GetHitTestData();
+
   compositor_frame_sink_->SubmitCompositorFrame(
-      local_surface_id_, std::move(frame), nullptr,
+      local_surface_id_, std::move(frame), std::move(hit_test_region_list),
       tracing_enabled ? base::TimeTicks::Now().since_origin().InMicroseconds()
                       : 0);
 }
diff --git a/content/browser/devtools/devtools_manager_unittest.cc b/content/browser/devtools/devtools_manager_unittest.cc
index 22329b12..f243e4e 100644
--- a/content/browser/devtools/devtools_manager_unittest.cc
+++ b/content/browser/devtools/devtools_manager_unittest.cc
@@ -25,6 +25,7 @@
 #include "content/public/browser/devtools_external_agent_proxy_delegate.h"
 #include "content/public/browser/web_contents_delegate.h"
 #include "content/public/common/browser_side_navigation_policy.h"
+#include "content/public/test/navigation_simulator.h"
 #include "content/public/test/test_utils.h"
 #include "content/test/test_content_browser_client.h"
 #include "content/test/test_render_view_host.h"
@@ -179,13 +180,7 @@
     return;
   // Navigate to URL.  First URL should use first RenderViewHost.
   const GURL url("http://www.google.com");
-  controller().LoadURL(
-      url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
-  int pending_id = controller().GetPendingEntry()->GetUniqueID();
-  contents()->GetMainFrame()->PrepareForCommit();
-  contents()->TestDidNavigate(contents()->GetMainFrame(), pending_id, true,
-                              url, ui::PAGE_TRANSITION_TYPED);
-  contents()->GetMainFrame()->SimulateNavigationStop();
+  NavigationSimulator::NavigateAndCommitFromBrowser(web_contents(), url);
   EXPECT_FALSE(contents()->CrossProcessNavigationPending());
 
   TestDevToolsClientHost client_host;
@@ -194,20 +189,15 @@
 
   // Navigate to new site which should get a new RenderViewHost.
   const GURL url2("http://www.yahoo.com");
-  controller().LoadURL(
-      url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
-  contents()->GetMainFrame()->PrepareForCommit();
+  auto navigation =
+      NavigationSimulator::CreateBrowserInitiated(url2, web_contents());
+  navigation->ReadyToCommit();
   EXPECT_TRUE(contents()->CrossProcessNavigationPending());
   EXPECT_EQ(client_host.agent_host(),
             DevToolsAgentHost::GetOrCreateFor(web_contents()).get());
 
   // Interrupt pending navigation and navigate back to the original site.
-  controller().LoadURL(
-      url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
-  pending_id = controller().GetPendingEntry()->GetUniqueID();
-  contents()->GetMainFrame()->PrepareForCommit();
-  contents()->TestDidNavigate(contents()->GetMainFrame(), pending_id, false,
-                              url, ui::PAGE_TRANSITION_TYPED);
+  NavigationSimulator::NavigateAndCommitFromBrowser(web_contents(), url);
   EXPECT_FALSE(contents()->CrossProcessNavigationPending());
   EXPECT_EQ(client_host.agent_host(),
             DevToolsAgentHost::GetOrCreateFor(web_contents()).get());
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index a502303e..e380eb1 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -1758,23 +1758,6 @@
           converter.ToLocalTimeTicks(
               RemoteTimeTicks::FromTimeTicks(renderer_before_unload_end_time));
       before_unload_end_time = browser_before_unload_end_time.ToTimeTicks();
-
-      // Collect UMA on the inter-process skew.
-      bool is_skew_additive = false;
-      if (converter.IsSkewAdditiveForMetrics()) {
-        is_skew_additive = true;
-        base::TimeDelta skew = converter.GetSkewForMetrics();
-        if (skew >= base::TimeDelta()) {
-          UMA_HISTOGRAM_TIMES(
-              "InterProcessTimeTicks.BrowserBehind_RendererToBrowser", skew);
-        } else {
-          UMA_HISTOGRAM_TIMES(
-              "InterProcessTimeTicks.BrowserAhead_RendererToBrowser", -skew);
-        }
-      }
-      UMA_HISTOGRAM_BOOLEAN(
-          "InterProcessTimeTicks.IsSkewAdditive_RendererToBrowser",
-          is_skew_additive);
     }
 
     base::TimeDelta on_before_unload_overhead_time =
diff --git a/content/browser/frame_host/render_frame_host_manager_unittest.cc b/content/browser/frame_host/render_frame_host_manager_unittest.cc
index 3301a64..c56b8a1 100644
--- a/content/browser/frame_host/render_frame_host_manager_unittest.cc
+++ b/content/browser/frame_host/render_frame_host_manager_unittest.cc
@@ -1753,10 +1753,10 @@
   EXPECT_TRUE(rfh1->is_active());
 
   // Navigate to new site, simulating onbeforeunload approval.
-  controller().LoadURL(
-      kUrl2, Referrer(), ui::PAGE_TRANSITION_LINK, std::string());
+  auto navigation =
+      NavigationSimulator::CreateBrowserInitiated(kUrl2, contents());
+  navigation->ReadyToCommit();
   int entry_id = controller().GetPendingEntry()->GetUniqueID();
-  contents()->GetMainFrame()->PrepareForCommit();
   EXPECT_TRUE(contents()->CrossProcessNavigationPending());
   EXPECT_TRUE(rfh1->is_active());
   TestRenderFrameHost* rfh2 = contents()->GetPendingMainFrame();
@@ -1801,10 +1801,10 @@
   rfh1->GetSiteInstance()->IncrementActiveFrameCount();
 
   // Navigate to new site, simulating onbeforeunload approval.
-  controller().LoadURL(
-      kUrl2, Referrer(), ui::PAGE_TRANSITION_LINK, std::string());
+  auto navigation =
+      NavigationSimulator::CreateBrowserInitiated(kUrl2, contents());
+  navigation->ReadyToCommit();
   int entry_id = controller().GetPendingEntry()->GetUniqueID();
-  contents()->GetMainFrame()->PrepareForCommit();
   EXPECT_TRUE(contents()->CrossProcessNavigationPending());
   EXPECT_TRUE(rfh1->is_active());
   TestRenderFrameHost* rfh2 = contents()->GetPendingMainFrame();
@@ -1846,11 +1846,12 @@
   site_instance->IncrementActiveFrameCount();
 
   // Navigate to new site, simulating onbeforeunload approval.
-  controller().LoadURL(
-      kUrl2, Referrer(), ui::PAGE_TRANSITION_LINK, std::string());
+  auto navigation =
+      NavigationSimulator::CreateBrowserInitiated(kUrl2, contents());
+  navigation->ReadyToCommit();
   int entry_id = controller().GetPendingEntry()->GetUniqueID();
-  rfh1->PrepareForCommit();
   EXPECT_TRUE(contents()->CrossProcessNavigationPending());
+  EXPECT_TRUE(rfh1->is_active());
   TestRenderFrameHost* rfh2 = contents()->GetPendingMainFrame();
 
   // The new page commits.
diff --git a/content/browser/renderer_host/input/input_router_impl.cc b/content/browser/renderer_host/input/input_router_impl.cc
index 783e64fc..0b60ae4 100644
--- a/content/browser/renderer_host/input/input_router_impl.cc
+++ b/content/browser/renderer_host/input/input_router_impl.cc
@@ -161,7 +161,8 @@
     InputEventAckSource source,
     const ui::LatencyInfo& latency,
     InputEventAckState state,
-    const base::Optional<ui::DidOverscrollParams>& overscroll) {
+    const base::Optional<ui::DidOverscrollParams>& overscroll,
+    const base::Optional<cc::TouchAction>& touch_action) {
   TRACE_EVENT2("input", "InputRouterImpl::KeboardEventHandled", "type",
                WebInputEvent::GetName(event.event.GetType()), "ack",
                GetEventAckName(state));
@@ -232,7 +233,8 @@
     InputEventAckSource source,
     const ui::LatencyInfo& latency,
     InputEventAckState state,
-    const base::Optional<ui::DidOverscrollParams>& overscroll) {
+    const base::Optional<ui::DidOverscrollParams>& overscroll,
+    const base::Optional<cc::TouchAction>& touch_action) {
   TRACE_EVENT2("input", "InputRouterImpl::MouseEventHandled", "type",
                WebInputEvent::GetName(event.event.GetType()), "ack",
                GetEventAckName(state));
@@ -256,7 +258,8 @@
     InputEventAckSource source,
     const ui::LatencyInfo& latency,
     InputEventAckState state,
-    const base::Optional<ui::DidOverscrollParams>& overscroll) {
+    const base::Optional<ui::DidOverscrollParams>& overscroll,
+    const base::Optional<cc::TouchAction>& touch_action) {
   TRACE_EVENT2("input", "InputRouterImpl::TouchEventHandled", "type",
                WebInputEvent::GetName(touch_event.event.GetType()), "ack",
                GetEventAckName(state));
@@ -264,6 +267,12 @@
     client_->DecrementInFlightEventCount(source);
   touch_event.latency.AddNewLatencyFrom(latency);
 
+  // The SetTouchAction IPC occurs on a different channel so always
+  // send it in the input event ack to ensure it is available at the
+  // time the ACK is handled.
+  if (touch_action.has_value())
+    OnSetTouchAction(touch_action.value());
+
   // |touch_event_queue_| will forward to OnTouchEventAck when appropriate.
   touch_event_queue_->ProcessTouchAck(state, latency,
                                       touch_event.event.unique_touch_event_id);
@@ -300,7 +309,8 @@
     InputEventAckSource source,
     const ui::LatencyInfo& latency,
     InputEventAckState state,
-    const base::Optional<ui::DidOverscrollParams>& overscroll) {
+    const base::Optional<ui::DidOverscrollParams>& overscroll,
+    const base::Optional<cc::TouchAction>& touch_action) {
   TRACE_EVENT2("input", "InputRouterImpl::GestureEventHandled", "type",
                WebInputEvent::GetName(gesture_event.event.GetType()), "ack",
                GetEventAckName(state));
@@ -390,7 +400,8 @@
     InputEventAckSource source,
     const ui::LatencyInfo& latency,
     InputEventAckState state,
-    const base::Optional<ui::DidOverscrollParams>& overscroll) {
+    const base::Optional<ui::DidOverscrollParams>& overscroll,
+    const base::Optional<cc::TouchAction>& touch_action) {
   TRACE_EVENT2("input", "InputRouterImpl::MouseWheelEventHandled", "type",
                WebInputEvent::GetName(event.event.GetType()), "ack",
                GetEventAckName(state));
@@ -428,7 +439,7 @@
   if (WasHandled(filtered_state)) {
     if (filtered_state != INPUT_EVENT_ACK_STATE_UNKNOWN) {
       std::move(callback).Run(InputEventAckSource::BROWSER, latency_info,
-                              filtered_state, base::nullopt);
+                              filtered_state, base::nullopt, base::nullopt);
     }
     return;
   }
@@ -445,7 +456,8 @@
     client_->GetWidgetInputHandler()->DispatchNonBlockingEvent(
         std::move(event));
     std::move(callback).Run(InputEventAckSource::BROWSER, latency_info,
-                            INPUT_EVENT_ACK_STATE_IGNORED, base::nullopt);
+                            INPUT_EVENT_ACK_STATE_IGNORED, base::nullopt,
+                            base::nullopt);
   }
 }
 
diff --git a/content/browser/renderer_host/input/input_router_impl.h b/content/browser/renderer_host/input/input_router_impl.h
index 661152b6..2748e0b 100644
--- a/content/browser/renderer_host/input/input_router_impl.h
+++ b/content/browser/renderer_host/input/input_router_impl.h
@@ -122,33 +122,36 @@
       InputEventAckSource source,
       const ui::LatencyInfo& latency,
       InputEventAckState state,
-      const base::Optional<ui::DidOverscrollParams>& overscroll);
-
+      const base::Optional<ui::DidOverscrollParams>& overscroll,
+      const base::Optional<cc::TouchAction>& touch_action);
   void MouseEventHandled(
       const MouseEventWithLatencyInfo& event,
       InputEventAckSource source,
       const ui::LatencyInfo& latency,
       InputEventAckState state,
-      const base::Optional<ui::DidOverscrollParams>& overscroll);
-
+      const base::Optional<ui::DidOverscrollParams>& overscroll,
+      const base::Optional<cc::TouchAction>& touch_action);
   void TouchEventHandled(
       const TouchEventWithLatencyInfo& touch_event,
       InputEventAckSource source,
       const ui::LatencyInfo& latency,
       InputEventAckState state,
-      const base::Optional<ui::DidOverscrollParams>& overscroll);
+      const base::Optional<ui::DidOverscrollParams>& overscroll,
+      const base::Optional<cc::TouchAction>& touch_action);
   void GestureEventHandled(
       const GestureEventWithLatencyInfo& gesture_event,
       InputEventAckSource source,
       const ui::LatencyInfo& latency,
       InputEventAckState state,
-      const base::Optional<ui::DidOverscrollParams>& overscroll);
+      const base::Optional<ui::DidOverscrollParams>& overscroll,
+      const base::Optional<cc::TouchAction>& touch_action);
   void MouseWheelEventHandled(
       const MouseWheelEventWithLatencyInfo& event,
       InputEventAckSource source,
       const ui::LatencyInfo& latency,
       InputEventAckState state,
-      const base::Optional<ui::DidOverscrollParams>& overscroll);
+      const base::Optional<ui::DidOverscrollParams>& overscroll,
+      const base::Optional<cc::TouchAction>& touch_action);
 
   // IPC message handlers
   void OnDidOverscroll(const ui::DidOverscrollParams& params);
diff --git a/content/browser/renderer_host/input/input_router_impl_unittest.cc b/content/browser/renderer_host/input/input_router_impl_unittest.cc
index 8343c36..873e82f 100644
--- a/content/browser/renderer_host/input/input_router_impl_unittest.cc
+++ b/content/browser/renderer_host/input/input_router_impl_unittest.cc
@@ -97,7 +97,17 @@
 void CallCallback(mojom::WidgetInputHandler::DispatchEventCallback callback,
                   InputEventAckState state) {
   std::move(callback).Run(InputEventAckSource::COMPOSITOR_THREAD,
-                          ui::LatencyInfo(), state, base::nullopt);
+                          ui::LatencyInfo(), state, base::nullopt,
+                          base::nullopt);
+}
+
+void CallCallbackWithTouchAction(
+    mojom::WidgetInputHandler::DispatchEventCallback callback,
+    InputEventAckState state,
+    cc::TouchAction touch_action) {
+  std::move(callback).Run(InputEventAckSource::COMPOSITOR_THREAD,
+                          ui::LatencyInfo(), state, base::nullopt,
+                          touch_action);
 }
 
 enum WheelScrollingMode {
@@ -1831,7 +1841,7 @@
   std::move(dispatched_events.at(0).callback_)
       .Run(InputEventAckSource::COMPOSITOR_THREAD, ui::LatencyInfo(),
            INPUT_EVENT_ACK_STATE_NOT_CONSUMED,
-           DidOverscrollParams(wheel_overscroll));
+           DidOverscrollParams(wheel_overscroll), base::nullopt);
 
   client_overscroll = client_->GetAndResetOverscroll();
   EXPECT_EQ(wheel_overscroll.accumulated_overscroll,
@@ -1898,6 +1908,22 @@
                INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
 }
 
+TEST_F(InputRouterImplTest, TouchActionInCallback) {
+  OnHasTouchEventHandlers(true);
+
+  // Send a touchstart
+  PressTouchPoint(1, 1);
+  SendTouchEvent();
+  DispatchedEvents dispatched_events = GetAndResetDispatchedEvents();
+  EXPECT_EQ(1U, dispatched_events.size());
+  CallCallbackWithTouchAction(std::move(dispatched_events.at(0).callback_),
+                              INPUT_EVENT_ACK_STATE_CONSUMED,
+                              cc::TouchAction::kTouchActionNone);
+  ASSERT_EQ(1U, disposition_handler_->GetAndResetAckCount());
+  EXPECT_EQ(cc::TouchAction::kTouchActionNone,
+            input_router_->AllowedTouchAction());
+}
+
 namespace {
 
 class InputRouterImplScaleEventTest : public InputRouterImplTest {
diff --git a/content/browser/renderer_host/input/legacy_input_router_impl.cc b/content/browser/renderer_host/input/legacy_input_router_impl.cc
index 24507ea5..ff807e38 100644
--- a/content/browser/renderer_host/input/legacy_input_router_impl.cc
+++ b/content/browser/renderer_host/input/legacy_input_router_impl.cc
@@ -450,6 +450,11 @@
     OnDidOverscroll(*ack.overscroll);
   }
 
+  // Since input messages over mojo require the touch action in the
+  // ACK we mirror that behavior in Chrome IPC for simplicity.
+  if (ack.touch_action.has_value())
+    OnSetTouchAction(ack.touch_action.value());
+
   ProcessInputEventAck(ack.type, ack.state, ack.latency,
                        ack.unique_touch_event_id, RENDERER);
 }
diff --git a/content/browser/renderer_host/render_widget_host_unittest.cc b/content/browser/renderer_host/render_widget_host_unittest.cc
index bdb5e3d..168e9b2 100644
--- a/content/browser/renderer_host/render_widget_host_unittest.cc
+++ b/content/browser/renderer_host/render_widget_host_unittest.cc
@@ -910,7 +910,8 @@
 void CallCallback(mojom::WidgetInputHandler::DispatchEventCallback callback,
                   InputEventAckState state) {
   std::move(callback).Run(InputEventAckSource::COMPOSITOR_THREAD,
-                          ui::LatencyInfo(), state, base::nullopt);
+                          ui::LatencyInfo(), state, base::nullopt,
+                          base::nullopt);
 }
 
 }  // namespace
diff --git a/content/browser/web_contents/web_contents_impl_unittest.cc b/content/browser/web_contents/web_contents_impl_unittest.cc
index e4a8ff72..a11f6f08 100644
--- a/content/browser/web_contents/web_contents_impl_unittest.cc
+++ b/content/browser/web_contents/web_contents_impl_unittest.cc
@@ -542,13 +542,7 @@
 
   // Navigate to URL.  First URL should use first RenderViewHost.
   const GURL url("http://www.google.com");
-  controller().LoadURL(
-      url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
-  int entry_id = controller().GetPendingEntry()->GetUniqueID();
-  orig_rfh->PrepareForCommit();
-  contents()->TestDidNavigateWithSequenceNumber(
-      orig_rfh, entry_id, true, url, Referrer(), ui::PAGE_TRANSITION_TYPED,
-      false, 0, 0);
+  NavigationSimulator::NavigateAndCommitFromBrowser(contents(), url);
 
   // Keep the number of active frames in orig_rfh's SiteInstance non-zero so
   // that orig_rfh doesn't get deleted when it gets swapped out.
@@ -563,7 +557,7 @@
   const GURL url2("http://www.yahoo.com");
   controller().LoadURL(
       url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
-  entry_id = controller().GetPendingEntry()->GetUniqueID();
+  int entry_id = controller().GetPendingEntry()->GetUniqueID();
   if (IsBrowserSideNavigationEnabled())
     orig_rfh->PrepareForCommit();
   EXPECT_TRUE(contents()->CrossProcessNavigationPending());
@@ -582,7 +576,7 @@
     EXPECT_FALSE(pending_rfh->are_navigations_suspended());
   }
 
-  // DidNavigate from the pending page
+  // DidNavigate from the pending page.
   contents()->TestDidNavigateWithSequenceNumber(
       pending_rfh, entry_id, true, url2, Referrer(), ui::PAGE_TRANSITION_TYPED,
       false, 1, 1);
@@ -621,7 +615,7 @@
     EXPECT_FALSE(goback_rfh->are_navigations_suspended());
   }
 
-  // DidNavigate from the back action
+  // DidNavigate from the back action.
   contents()->TestDidNavigateWithSequenceNumber(
       goback_rfh, entry_id, false, url2, Referrer(), ui::PAGE_TRANSITION_TYPED,
       false, 2, 0);
@@ -1159,19 +1153,12 @@
   // Start with a web ui page, which gets a new RVH with WebUI bindings.
   GURL url1(std::string(kChromeUIScheme) + "://" +
             std::string(kChromeUIGpuHost));
-  controller().LoadURL(
-      url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
-  int entry_id = controller().GetPendingEntry()->GetUniqueID();
+  NavigationSimulator::NavigateAndCommitFromBrowser(contents(), url1);
   TestRenderFrameHost* webui_rfh = main_test_rfh();
-  webui_rfh->PrepareForCommit();
-  contents()->TestDidNavigateWithSequenceNumber(
-      webui_rfh, entry_id, true, url1, Referrer(), ui::PAGE_TRANSITION_TYPED,
-      false, 0, 0);
   NavigationEntry* entry1 = controller().GetLastCommittedEntry();
   SiteInstance* instance1 = contents()->GetSiteInstance();
 
   EXPECT_FALSE(contents()->CrossProcessNavigationPending());
-  EXPECT_EQ(webui_rfh, main_test_rfh());
   EXPECT_EQ(url1, entry1->GetURL());
   EXPECT_EQ(instance1,
             NavigationEntryImpl::FromNavigationEntry(entry1)->site_instance());
@@ -1179,25 +1166,12 @@
 
   // Navigate to new site.
   const GURL url2("http://www.google.com");
-  controller().LoadURL(
-      url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
-  entry_id = controller().GetPendingEntry()->GetUniqueID();
-  EXPECT_TRUE(contents()->CrossProcessNavigationPending());
-  TestRenderFrameHost* google_rfh = contents()->GetPendingMainFrame();
-
-  // Simulate beforeunload approval.
-  EXPECT_TRUE(webui_rfh->is_waiting_for_beforeunload_ack());
-  webui_rfh->PrepareForCommit();
-
-  // DidNavigate from the pending page.
-  contents()->TestDidNavigateWithSequenceNumber(
-      google_rfh, entry_id, true, url2, Referrer(), ui::PAGE_TRANSITION_TYPED,
-      false, 1, 1);
+  NavigationSimulator::NavigateAndCommitFromBrowser(contents(), url2);
+  TestRenderFrameHost* google_rfh = main_test_rfh();
   NavigationEntry* entry2 = controller().GetLastCommittedEntry();
   SiteInstance* instance2 = contents()->GetSiteInstance();
 
   EXPECT_FALSE(contents()->CrossProcessNavigationPending());
-  EXPECT_EQ(google_rfh, main_test_rfh());
   EXPECT_NE(instance1, instance2);
   EXPECT_FALSE(contents()->GetPendingMainFrame());
   EXPECT_EQ(url2, entry2->GetURL());
@@ -1207,14 +1181,7 @@
 
   // Navigate to third page on same site.
   const GURL url3("http://news.google.com");
-  controller().LoadURL(
-      url3, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
-  entry_id = controller().GetPendingEntry()->GetUniqueID();
-  EXPECT_FALSE(contents()->CrossProcessNavigationPending());
-  main_test_rfh()->PrepareForCommit();
-  contents()->TestDidNavigateWithSequenceNumber(
-      google_rfh, entry_id, true, url3, Referrer(), ui::PAGE_TRANSITION_TYPED,
-      false, 2, 2);
+  NavigationSimulator::NavigateAndCommitFromBrowser(contents(), url3);
   NavigationEntry* entry3 = controller().GetLastCommittedEntry();
   SiteInstance* instance3 = contents()->GetSiteInstance();
 
diff --git a/content/child/resource_dispatcher.cc b/content/child/resource_dispatcher.cc
index 96e1dd2c..e631a12 100644
--- a/content/child/resource_dispatcher.cc
+++ b/content/child/resource_dispatcher.cc
@@ -768,23 +768,6 @@
   RemoteToLocalTimeTicks(converter, &load_timing->push_end);
   RemoteToLocalTimeTicks(converter, &renderer_info->service_worker_start_time);
   RemoteToLocalTimeTicks(converter, &renderer_info->service_worker_ready_time);
-
-  // Collect UMA on the inter-process skew.
-  bool is_skew_additive = false;
-  if (converter.IsSkewAdditiveForMetrics()) {
-    is_skew_additive = true;
-    base::TimeDelta skew = converter.GetSkewForMetrics();
-    if (skew >= base::TimeDelta()) {
-      UMA_HISTOGRAM_TIMES(
-          "InterProcessTimeTicks.BrowserAhead_BrowserToRenderer", skew);
-    } else {
-      UMA_HISTOGRAM_TIMES(
-          "InterProcessTimeTicks.BrowserBehind_BrowserToRenderer", -skew);
-    }
-  }
-  UMA_HISTOGRAM_BOOLEAN(
-      "InterProcessTimeTicks.IsSkewAdditive_BrowserToRenderer",
-      is_skew_additive);
 }
 
 base::TimeTicks ResourceDispatcher::ToRendererCompletionTime(
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn
index 6060e6eeb..89cc6c26 100644
--- a/content/common/BUILD.gn
+++ b/content/common/BUILD.gn
@@ -193,6 +193,8 @@
     "input/synthetic_tap_gesture_params.h",
     "input/synthetic_web_input_event_builders.cc",
     "input/synthetic_web_input_event_builders.h",
+    "input/touch_action_optional_struct_traits.cc",
+    "input/touch_action_optional_struct_traits.h",
     "input/touch_event_stream_validator.cc",
     "input/touch_event_stream_validator.h",
     "input/web_touch_event_traits.cc",
diff --git a/content/common/input/input_event_ack.cc b/content/common/input/input_event_ack.cc
index c067e91..98a50178 100644
--- a/content/common/input/input_event_ack.cc
+++ b/content/common/input/input_event_ack.cc
@@ -14,13 +14,15 @@
     InputEventAckState state,
     const ui::LatencyInfo& latency,
     std::unique_ptr<ui::DidOverscrollParams> overscroll,
-    uint32_t unique_touch_event_id)
+    uint32_t unique_touch_event_id,
+    base::Optional<cc::TouchAction> touch_action)
     : source(source),
       type(type),
       state(state),
       latency(latency),
       overscroll(std::move(overscroll)),
-      unique_touch_event_id(unique_touch_event_id) {}
+      unique_touch_event_id(unique_touch_event_id),
+      touch_action(touch_action) {}
 
 InputEventAck::InputEventAck(InputEventAckSource source,
                              blink::WebInputEvent::Type type,
@@ -32,7 +34,8 @@
                     state,
                     latency,
                     nullptr,
-                    unique_touch_event_id) {}
+                    unique_touch_event_id,
+                    base::nullopt) {}
 
 InputEventAck::InputEventAck(InputEventAckSource source,
                              blink::WebInputEvent::Type type,
diff --git a/content/common/input/input_event_ack.h b/content/common/input/input_event_ack.h
index f94b5e1..1614965 100644
--- a/content/common/input/input_event_ack.h
+++ b/content/common/input/input_event_ack.h
@@ -9,6 +9,8 @@
 
 #include <memory>
 
+#include "base/optional.h"
+#include "cc/input/touch_action.h"
 #include "content/common/content_export.h"
 #include "content/common/input/input_event_ack_source.h"
 #include "content/common/input/input_event_ack_state.h"
@@ -25,7 +27,8 @@
                 InputEventAckState state,
                 const ui::LatencyInfo& latency,
                 std::unique_ptr<ui::DidOverscrollParams> overscroll,
-                uint32_t unique_touch_event_id);
+                uint32_t unique_touch_event_id,
+                base::Optional<cc::TouchAction> touch_action);
   InputEventAck(InputEventAckSource source,
                 blink::WebInputEvent::Type type,
                 InputEventAckState state,
@@ -47,6 +50,7 @@
   ui::LatencyInfo latency;
   std::unique_ptr<ui::DidOverscrollParams> overscroll;
   uint32_t unique_touch_event_id;
+  base::Optional<cc::TouchAction> touch_action;
 };
 
 }  // namespace content
diff --git a/content/common/input/input_handler.mojom b/content/common/input/input_handler.mojom
index 47317d5..86aabcc 100644
--- a/content/common/input/input_handler.mojom
+++ b/content/common/input/input_handler.mojom
@@ -143,6 +143,10 @@
   TouchData? touch_data;
 };
 
+struct TouchActionOptional {
+  TouchAction touch_action;
+};
+
 interface WidgetInputHandler {
   // Tells widget focus has been changed.
   SetFocus(bool focused);
@@ -199,7 +203,8 @@
   // you don't require notification.
   DispatchEvent(Event event)
       => (InputEventAckSource source, ui.mojom.LatencyInfo updated_latency,
-         InputEventAckState state, DidOverscrollParams? overscroll);
+         InputEventAckState state, DidOverscrollParams? overscroll,
+         TouchActionOptional? touch_action);
 
   // Sends a non-blocking input event to the render widget. The behaviour
   // of this API is the same as DispatchEvent just that there is no callback
diff --git a/content/common/input/touch_action_optional_struct_traits.cc b/content/common/input/touch_action_optional_struct_traits.cc
new file mode 100644
index 0000000..b2b4c33
--- /dev/null
+++ b/content/common/input/touch_action_optional_struct_traits.cc
@@ -0,0 +1,16 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/common/input/touch_action_optional_struct_traits.h"
+
+#include "content/common/input_messages.h"
+
+namespace mojo {
+bool StructTraits<
+    content::mojom::TouchActionOptionalDataView,
+    cc::TouchAction>::Read(content::mojom::TouchActionOptionalDataView r,
+                           cc::TouchAction* out) {
+  return r.ReadTouchAction(out);
+}
+}  // namespace mojo
diff --git a/content/common/input/touch_action_optional_struct_traits.h b/content/common/input/touch_action_optional_struct_traits.h
new file mode 100644
index 0000000..82751b1
--- /dev/null
+++ b/content/common/input/touch_action_optional_struct_traits.h
@@ -0,0 +1,23 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_COMMON_INPUT_TOUCH_ACTION_OPTIONAL_STRUCT_TRAITS_H_
+#define CONTENT_COMMON_INPUT_TOUCH_ACTION_OPTIONAL_STRUCT_TRAITS_H_
+
+#include "base/optional.h"
+#include "content/common/input/input_handler.mojom.h"
+
+namespace mojo {
+
+template <>
+struct StructTraits<content::mojom::TouchActionOptionalDataView,
+                    cc::TouchAction> {
+  static cc::TouchAction touch_action(cc::TouchAction action) { return action; }
+  static bool Read(content::mojom::TouchActionOptionalDataView r,
+                   cc::TouchAction* out);
+};
+
+}  // namespace mojo
+
+#endif  // CONTENT_COMMON_INPUT_TOUCH_ACTION_OPTIONAL_STRUCT_TRAITS_H_
diff --git a/content/common/input_messages.h b/content/common/input_messages.h
index 58a46ad..7355b8d 100644
--- a/content/common/input_messages.h
+++ b/content/common/input_messages.h
@@ -149,6 +149,7 @@
   IPC_STRUCT_TRAITS_MEMBER(latency)
   IPC_STRUCT_TRAITS_MEMBER(overscroll)
   IPC_STRUCT_TRAITS_MEMBER(unique_touch_event_id)
+  IPC_STRUCT_TRAITS_MEMBER(touch_action)
 IPC_STRUCT_TRAITS_END()
 
 // Sends an input event to the render widget. The input event in general
diff --git a/content/common/inter_process_time_ticks_converter.cc b/content/common/inter_process_time_ticks_converter.cc
index f50aa3e..be36224a 100644
--- a/content/common/inter_process_time_ticks_converter.cc
+++ b/content/common/inter_process_time_ticks_converter.cc
@@ -79,10 +79,6 @@
   return numerator_ * value / denominator_;
 }
 
-bool InterProcessTimeTicksConverter::IsSkewAdditiveForMetrics() const {
-  return numerator_ == 1 && denominator_ == 1;
-}
-
 base::TimeDelta InterProcessTimeTicksConverter::GetSkewForMetrics() const {
   return base::TimeTicks::FromInternalValue(remote_lower_bound_) -
       base::TimeTicks::FromInternalValue(local_base_time_);
diff --git a/content/common/inter_process_time_ticks_converter.h b/content/common/inter_process_time_ticks_converter.h
index cc5de55..bbefaa6 100644
--- a/content/common/inter_process_time_ticks_converter.h
+++ b/content/common/inter_process_time_ticks_converter.h
@@ -64,11 +64,6 @@
   // |remote_delta|.
   LocalTimeDelta ToLocalTimeDelta(const RemoteTimeDelta& remote_delta) const;
 
-  // Returns true iff the TimeTicks are converted by adding a constant, without
-  // scaling. This is the case whenever the remote timespan is smaller than the
-  // local timespan, which should be the majority of cases due to IPC overhead.
-  bool IsSkewAdditiveForMetrics() const;
-
   // Returns the (remote time) - (local time) difference estimated by the
   // converter. This is the constant that is subtracted from remote TimeTicks to
   // get local TimeTicks when no scaling is applied.
diff --git a/content/common/inter_process_time_ticks_converter_unittest.cc b/content/common/inter_process_time_ticks_converter_unittest.cc
index 9d53d79..0a555e0 100644
--- a/content/common/inter_process_time_ticks_converter_unittest.cc
+++ b/content/common/inter_process_time_ticks_converter_unittest.cc
@@ -27,7 +27,6 @@
 struct TestResults {
   int64_t result_time;
   int32_t result_delta;
-  bool is_skew_additive;
   int64_t skew;
 };
 
@@ -54,7 +53,6 @@
           test_time)).ToTimeTicks().ToInternalValue();
   results.result_delta = converter.ToLocalTimeDelta(
       RemoteTimeDelta::FromRawDelta(params.test_delta)).ToInt32();
-  results.is_skew_additive = converter.IsSkewAdditiveForMetrics();
   results.skew = converter.GetSkewForMetrics().ToInternalValue();
   return results;
 }
@@ -85,7 +83,6 @@
   TestResults results = RunTest(p);
   EXPECT_EQ(3, results.result_time);
   EXPECT_EQ(1, results.result_delta);
-  EXPECT_TRUE(results.is_skew_additive);
   EXPECT_EQ(0, results.skew);
 }
 
@@ -102,7 +99,6 @@
   TestResults results = RunTest(p);
   EXPECT_EQ(3, results.result_time);
   EXPECT_EQ(1, results.result_delta);
-  EXPECT_TRUE(results.is_skew_additive);
   EXPECT_EQ(1, results.skew);
 }
 
@@ -122,7 +118,6 @@
   TestResults results = RunTest(p);
   EXPECT_EQ(5, results.result_time);
   EXPECT_EQ(1, results.result_delta);
-  EXPECT_FALSE(results.is_skew_additive);
 }
 
 TEST(InterProcessTimeTicksConverterTest, FrontEndSkew) {
@@ -140,7 +135,6 @@
   TestResults results = RunTest(p);
   EXPECT_EQ(4, results.result_time);
   EXPECT_EQ(1, results.result_delta);
-  EXPECT_FALSE(results.is_skew_additive);
 }
 
 TEST(InterProcessTimeTicksConverterTest, BackEndSkew) {
@@ -156,7 +150,6 @@
   TestResults results = RunTest(p);
   EXPECT_EQ(2, results.result_time);
   EXPECT_EQ(1, results.result_delta);
-  EXPECT_FALSE(results.is_skew_additive);
 }
 
 TEST(InterProcessTimeTicksConverterTest, Instantaneous) {
diff --git a/content/common/native_types.mojom b/content/common/native_types.mojom
index 61d28a2e..a8e8cff 100644
--- a/content/common/native_types.mojom
+++ b/content/common/native_types.mojom
@@ -94,3 +94,6 @@
 
 [Native]
 struct SyntheticPointerAction;
+
+[Native]
+enum TouchAction;
diff --git a/content/common/native_types.typemap b/content/common/native_types.typemap
index 2d463f1b..a8e0c0cd 100644
--- a/content/common/native_types.typemap
+++ b/content/common/native_types.typemap
@@ -4,6 +4,7 @@
 
 mojom = "//content/common/native_types.mojom"
 public_headers = [
+  "//cc/input/touch_action.h",
   "//content/common/edit_command.h",
   "//content/common/frame_owner_properties.h",
   "//content/common/frame_replication_state.h",
@@ -35,6 +36,7 @@
   "//content/common/frame_messages.h",
   "//content/common/input_messages.h",
   "//content/common/input/input_event_struct_traits.h",
+  "//content/common/input/touch_action_optional_struct_traits.h",
   "//content/common/view_messages.h",
   "//content/public/common/common_param_traits.h",
 ]
@@ -83,6 +85,7 @@
   "content.mojom.SyntheticPinch=content::SyntheticPinchGestureParams",
   "content.mojom.SyntheticTap=content::SyntheticTapGestureParams",
   "content.mojom.SyntheticPointerAction=content::SyntheticPointerActionListParams",
+  "content.mojom.TouchActionOptional=cc::TouchAction",
   "content.mojom.TouchState=blink::WebTouchPoint::State",
   "content.mojom.WebPopupType=blink::WebPopupType",
   "content.mojom.WebPreferences=content::WebPreferences",
diff --git a/content/public/android/java/src/org/chromium/content/browser/input/SuggestionsPopupWindow.java b/content/public/android/java/src/org/chromium/content/browser/input/SuggestionsPopupWindow.java
index 4919d11..70c6a93 100644
--- a/content/public/android/java/src/org/chromium/content/browser/input/SuggestionsPopupWindow.java
+++ b/content/public/android/java/src/org/chromium/content/browser/input/SuggestionsPopupWindow.java
@@ -27,7 +27,6 @@
 
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.base.VisibleForTesting;
-import org.chromium.base.annotations.SuppressFBWarnings;
 import org.chromium.content.R;
 import org.chromium.content.browser.WindowAndroidProvider;
 import org.chromium.ui.UiUtils;
@@ -211,7 +210,6 @@
         }
 
         @Override
-        @SuppressFBWarnings("BC_UNCONFIRMED_CAST")
         public View getView(int position, View convertView, ViewGroup parent) {
             TextView textView = (TextView) convertView;
             if (textView == null) {
diff --git a/content/renderer/input/input_event_filter.cc b/content/renderer/input/input_event_filter.cc
index f0d87bb..5def8fc 100644
--- a/content/renderer/input/input_event_filter.cc
+++ b/content/renderer/input/input_event_filter.cc
@@ -276,7 +276,7 @@
   }
   if (callback) {
     std::move(callback).Run(ack_state, latency_info,
-                            std::move(overscroll_params));
+                            std::move(overscroll_params), base::nullopt);
   }
 }
 
@@ -286,13 +286,15 @@
     int unique_touch_event_id,
     InputEventAckState ack_state,
     const ui::LatencyInfo& latency_info,
-    std::unique_ptr<ui::DidOverscrollParams> overscroll_params) {
+    std::unique_ptr<ui::DidOverscrollParams> overscroll_params,
+    base::Optional<cc::TouchAction> touch_action) {
   bool main_thread = main_task_runner_->BelongsToCurrentThread();
 
   InputEventAck ack(main_thread ? InputEventAckSource::MAIN_THREAD
                                 : InputEventAckSource::COMPOSITOR_THREAD,
                     event_type, ack_state, latency_info,
-                    std::move(overscroll_params), unique_touch_event_id);
+                    std::move(overscroll_params), unique_touch_event_id,
+                    touch_action);
   SendMessage(std::unique_ptr<IPC::Message>(
       new InputHostMsg_HandleInputEvent_ACK(routing_id, ack)));
 }
diff --git a/content/renderer/input/input_event_filter.h b/content/renderer/input/input_event_filter.h
index 83ed2471..f0a5f3b 100644
--- a/content/renderer/input/input_event_filter.h
+++ b/content/renderer/input/input_event_filter.h
@@ -107,7 +107,8 @@
       int unique_touch_event_id,
       InputEventAckState ack_state,
       const ui::LatencyInfo& latency_info,
-      std::unique_ptr<ui::DidOverscrollParams> overscroll_params);
+      std::unique_ptr<ui::DidOverscrollParams> overscroll_params,
+      base::Optional<cc::TouchAction> touch_action);
   void SendMessage(std::unique_ptr<IPC::Message> message);
   void SendMessageOnIOThread(std::unique_ptr<IPC::Message> message);
 
diff --git a/content/renderer/input/input_event_filter_unittest.cc b/content/renderer/input/input_event_filter_unittest.cc
index 1bee1ab..595e4e7 100644
--- a/content/renderer/input/input_event_filter_unittest.cc
+++ b/content/renderer/input/input_event_filter_unittest.cc
@@ -264,7 +264,7 @@
                         HandledEventCallback callback) override {
     message_recorder_.AppendEvent(event);
     std::move(callback).Run(INPUT_EVENT_ACK_STATE_NOT_CONSUMED, latency,
-                            nullptr);
+                            nullptr, base::nullopt);
   }
 
   void SetNeedsMainFrame() override { event_recorder_->NeedsMainFrame(); }
diff --git a/content/renderer/input/main_thread_event_queue.cc b/content/renderer/input/main_thread_event_queue.cc
index 3f5bce49..ff164ef2 100644
--- a/content/renderer/input/main_thread_event_queue.cc
+++ b/content/renderer/input/main_thread_event_queue.cc
@@ -128,15 +128,17 @@
   void HandledEvent(MainThreadEventQueue* queue,
                     InputEventAckState ack_result,
                     const ui::LatencyInfo& latency_info,
-                    std::unique_ptr<ui::DidOverscrollParams> overscroll) {
+                    std::unique_ptr<ui::DidOverscrollParams> overscroll,
+                    base::Optional<cc::TouchAction> touch_action) {
     if (callback_) {
-      std::move(callback_).Run(ack_result, latency_info, std::move(overscroll));
+      std::move(callback_).Run(ack_result, latency_info, std::move(overscroll),
+                               touch_action);
     } else {
       DCHECK(!overscroll) << "Unexpected overscroll for un-acked event";
     }
 
     for (auto&& callback : blocking_coalesced_callbacks_)
-      std::move(callback).Run(ack_result, latency_info, nullptr);
+      std::move(callback).Run(ack_result, latency_info, nullptr, base::nullopt);
 
     size_t num_events_handled = 1 + blocking_coalesced_callbacks_.size();
     if (queue->renderer_scheduler_) {
@@ -352,7 +354,7 @@
   QueueEvent(std::move(queued_event));
 
   if (callback)
-    std::move(callback).Run(ack_result, latency, nullptr);
+    std::move(callback).Run(ack_result, latency, nullptr, base::nullopt);
 }
 
 void MainThreadEventQueue::QueueClosure(base::OnceClosure closure) {
diff --git a/content/renderer/input/main_thread_event_queue.h b/content/renderer/input/main_thread_event_queue.h
index 193aa92..d1eac0e 100644
--- a/content/renderer/input/main_thread_event_queue.h
+++ b/content/renderer/input/main_thread_event_queue.h
@@ -9,6 +9,7 @@
 #include "base/feature_list.h"
 #include "base/memory/weak_ptr.h"
 #include "base/single_thread_task_runner.h"
+#include "cc/input/touch_action.h"
 #include "content/common/content_export.h"
 #include "content/common/input/input_event_ack_state.h"
 #include "content/common/input/input_event_dispatch_type.h"
@@ -26,7 +27,8 @@
 using HandledEventCallback =
     base::OnceCallback<void(InputEventAckState ack_state,
                             const ui::LatencyInfo& latency_info,
-                            std::unique_ptr<ui::DidOverscrollParams>)>;
+                            std::unique_ptr<ui::DidOverscrollParams>,
+                            base::Optional<cc::TouchAction>)>;
 
 // All interaction with the MainThreadEventQueueClient will occur
 // on the main thread.
diff --git a/content/renderer/input/main_thread_event_queue_unittest.cc b/content/renderer/input/main_thread_event_queue_unittest.cc
index 97203cb..b30cebe 100644
--- a/content/renderer/input/main_thread_event_queue_unittest.cc
+++ b/content/renderer/input/main_thread_event_queue_unittest.cc
@@ -115,7 +115,8 @@
   void DidHandleEvent(size_t index,
                       InputEventAckState ack_result,
                       const ui::LatencyInfo& latency,
-                      std::unique_ptr<ui::DidOverscrollParams> params) {
+                      std::unique_ptr<ui::DidOverscrollParams> params,
+                      base::Optional<cc::TouchAction> touch_action) {
     callbacks_received_[index] =
         handling_event_ ? CallbackReceivedState::kCalledWhileHandlingEvent
                         : CallbackReceivedState::kCalledAfterHandleEvent;
@@ -220,7 +221,7 @@
     std::unique_ptr<HandledTask> handled_event(new HandledEvent(event));
     handled_tasks_.push_back(std::move(handled_event));
     std::move(callback).Run(INPUT_EVENT_ACK_STATE_NOT_CONSUMED, latency,
-                            nullptr);
+                            nullptr, base::nullopt);
   }
 
   void SetNeedsMainFrame() override { needs_main_frame_ = true; }
@@ -1107,7 +1108,7 @@
                         const ui::LatencyInfo& latency,
                         HandledEventCallback callback) override {
     std::move(callback).Run(INPUT_EVENT_ACK_STATE_NOT_CONSUMED, latency,
-                            nullptr);
+                            nullptr, base::nullopt);
   }
 
   void SetNeedsMainFrame() override {}
diff --git a/content/renderer/input/render_widget_input_handler.cc b/content/renderer/input/render_widget_input_handler.cc
index 4edd56c..965e4cb7 100644
--- a/content/renderer/input/render_widget_input_handler.cc
+++ b/content/renderer/input/render_widget_input_handler.cc
@@ -169,6 +169,12 @@
       handling_event_overscroll_resetter(&handling_event_overscroll_,
                                          &event_overscroll);
 
+  // Calls into |ProcessTouchAction()| while handling this event will
+  // populate |handling_touch_action_|, which in turn will be bundled with
+  // the event ack.
+  base::AutoReset<base::Optional<cc::TouchAction>>
+      handling_touch_action_resetter(&handling_touch_action_, base::nullopt);
+
 #if defined(OS_ANDROID)
   ImeEventGuard guard(widget_);
 #endif
@@ -336,7 +342,8 @@
 
   if (callback) {
     std::move(callback).Run(ack_result, swap_latency_info,
-                            std::move(event_overscroll));
+                            std::move(event_overscroll),
+                            handling_touch_action_);
   } else {
     DCHECK(!event_overscroll) << "Unexpected overscroll for un-acked event";
   }
@@ -389,4 +396,15 @@
   delegate_->OnDidOverscroll(*params);
 }
 
+bool RenderWidgetInputHandler::ProcessTouchAction(
+    cc::TouchAction touch_action) {
+  // Ignore setTouchAction calls that result from synthetic touch events (eg.
+  // when blink is emulating touch with mouse).
+  if (handling_event_type_ != WebInputEvent::kTouchStart)
+    return false;
+
+  handling_touch_action_ = touch_action;
+  return true;
+}
+
 }  // namespace content
diff --git a/content/renderer/input/render_widget_input_handler.h b/content/renderer/input/render_widget_input_handler.h
index 611ff3a1..4d03077 100644
--- a/content/renderer/input/render_widget_input_handler.h
+++ b/content/renderer/input/render_widget_input_handler.h
@@ -56,9 +56,9 @@
     handling_input_event_ = handling_input_event;
   }
 
-  blink::WebInputEvent::Type handling_event_type() const {
-    return handling_event_type_;
-  }
+  // Process the touch action, returning whether the action should be relayed
+  // to the browser.
+  bool ProcessTouchAction(cc::TouchAction touch_action);
 
  private:
   RenderWidgetInputHandlerDelegate* const delegate_;
@@ -74,6 +74,8 @@
   // supporting overscroll IPC notifications due to fling animation updates.
   std::unique_ptr<ui::DidOverscrollParams>* handling_event_overscroll_;
 
+  base::Optional<cc::TouchAction> handling_touch_action_;
+
   // Type of the input event we are currently handling.
   blink::WebInputEvent::Type handling_event_type_;
 
diff --git a/content/renderer/input/widget_input_handler_manager.cc b/content/renderer/input/widget_input_handler_manager.cc
index a4cc46d6..b5ea44a 100644
--- a/content/renderer/input/widget_input_handler_manager.cc
+++ b/content/renderer/input/widget_input_handler_manager.cc
@@ -45,12 +45,14 @@
 void CallCallback(mojom::WidgetInputHandler::DispatchEventCallback callback,
                   InputEventAckState ack_state,
                   const ui::LatencyInfo& latency_info,
-                  std::unique_ptr<ui::DidOverscrollParams> overscroll_params) {
+                  std::unique_ptr<ui::DidOverscrollParams> overscroll_params,
+                  base::Optional<cc::TouchAction> touch_action) {
   std::move(callback).Run(
       InputEventAckSource::MAIN_THREAD, latency_info, ack_state,
       overscroll_params
           ? base::Optional<ui::DidOverscrollParams>(*overscroll_params)
-          : base::nullopt);
+          : base::nullopt,
+      touch_action);
 }
 
 }  // namespace
@@ -267,7 +269,8 @@
     mojom::WidgetInputHandler::DispatchEventCallback callback) {
   if (!render_widget_) {
     std::move(callback).Run(InputEventAckSource::MAIN_THREAD, latency,
-                            INPUT_EVENT_ACK_STATE_NOT_CONSUMED, base::nullopt);
+                            INPUT_EVENT_ACK_STATE_NOT_CONSUMED, base::nullopt,
+                            base::nullopt);
     return;
   }
   auto send_callback = base::BindOnce(
@@ -321,7 +324,8 @@
         InputEventAckSource::COMPOSITOR_THREAD, latency_info, ack_state,
         overscroll_params
             ? base::Optional<ui::DidOverscrollParams>(*overscroll_params)
-            : base::nullopt);
+            : base::nullopt,
+        base::nullopt);
   }
 }
 
@@ -329,19 +333,22 @@
     mojom::WidgetInputHandler::DispatchEventCallback callback,
     InputEventAckState ack_state,
     const ui::LatencyInfo& latency_info,
-    std::unique_ptr<ui::DidOverscrollParams> overscroll_params) {
+    std::unique_ptr<ui::DidOverscrollParams> overscroll_params,
+    base::Optional<cc::TouchAction> touch_action) {
   if (!callback)
     return;
   if (compositor_task_runner_) {
     compositor_task_runner_->PostTask(
         FROM_HERE, base::BindOnce(CallCallback, std::move(callback), ack_state,
-                                  latency_info, std::move(overscroll_params)));
+                                  latency_info, std::move(overscroll_params),
+                                  touch_action));
   } else {
     std::move(callback).Run(
         InputEventAckSource::COMPOSITOR_THREAD, latency_info, ack_state,
         overscroll_params
             ? base::Optional<ui::DidOverscrollParams>(*overscroll_params)
-            : base::nullopt);
+            : base::nullopt,
+        touch_action);
   }
 }
 
diff --git a/content/renderer/input/widget_input_handler_manager.h b/content/renderer/input/widget_input_handler_manager.h
index a97c5e1..676f4a7 100644
--- a/content/renderer/input/widget_input_handler_manager.h
+++ b/content/renderer/input/widget_input_handler_manager.h
@@ -100,7 +100,8 @@
       mojom::WidgetInputHandler::DispatchEventCallback callback,
       InputEventAckState ack_state,
       const ui::LatencyInfo& latency_info,
-      std::unique_ptr<ui::DidOverscrollParams> overscroll_params);
+      std::unique_ptr<ui::DidOverscrollParams> overscroll_params,
+      base::Optional<cc::TouchAction> touch_action);
   void ObserveGestureEventOnCompositorThread(
       const blink::WebGestureEvent& gesture_event,
       const cc::InputHandlerScrollResult& scroll_result);
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index a99ee51..dbf1a196 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -1279,7 +1279,7 @@
 
   // Hook up blink's codecs so skia can call them
   SkGraphics::SetImageGeneratorFromEncodedDataFactory(
-      blink::WebImageGenerator::Create);
+      blink::WebImageGenerator::CreateAsSkImageGenerator);
 
   if (command_line.HasSwitch(switches::kExplicitlyAllowedPorts)) {
     std::string allowed_ports =
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index 91ee579..94acf02 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -2528,7 +2528,7 @@
     HandledEventCallback callback) {
   if (is_swapped_out_) {
     std::move(callback).Run(INPUT_EVENT_ACK_STATE_NOT_CONSUMED, latency_info,
-                            nullptr);
+                            nullptr, base::nullopt);
     return;
   }
   idle_user_detector_->ActivityDetected();
diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc
index c33df91..fdec645 100644
--- a/content/renderer/render_widget.cc
+++ b/content/renderer/render_widget.cc
@@ -858,9 +858,11 @@
     uint32_t touch_event_id,
     InputEventAckState ack_state,
     const ui::LatencyInfo& latency_info,
-    std::unique_ptr<ui::DidOverscrollParams> overscroll_params) {
+    std::unique_ptr<ui::DidOverscrollParams> overscroll_params,
+    base::Optional<cc::TouchAction> touch_action) {
   InputEventAck ack(InputEventAckSource::MAIN_THREAD, type, ack_state,
-                    latency_info, std::move(overscroll_params), touch_event_id);
+                    latency_info, std::move(overscroll_params), touch_event_id,
+                    touch_action);
   Send(new InputHostMsg_HandleInputEvent_ACK(routing_id_, ack));
 }
 
@@ -2321,9 +2323,7 @@
 }
 
 void RenderWidget::SetTouchAction(cc::TouchAction touch_action) {
-  // Ignore setTouchAction calls that result from synthetic touch events (eg.
-  // when blink is emulating touch with mouse).
-  if (input_handler_->handling_event_type() != WebInputEvent::kTouchStart)
+  if (!input_handler_->ProcessTouchAction(touch_action))
     return;
 
   Send(new InputHostMsg_SetTouchAction(routing_id_, touch_action));
diff --git a/content/renderer/render_widget.h b/content/renderer/render_widget.h
index e743b4d6..a5cf1b4c 100644
--- a/content/renderer/render_widget.h
+++ b/content/renderer/render_widget.h
@@ -846,7 +846,8 @@
                          uint32_t touch_event_id,
                          InputEventAckState ack_state,
                          const ui::LatencyInfo& latency_info,
-                         std::unique_ptr<ui::DidOverscrollParams>);
+                         std::unique_ptr<ui::DidOverscrollParams>,
+                         base::Optional<cc::TouchAction>);
 
 #if BUILDFLAG(ENABLE_PLUGINS)
   // Returns the focused pepper plugin, if any, inside the WebWidget. That is
diff --git a/extensions/browser/guest_view/extensions_guest_view_message_filter.cc b/extensions/browser/guest_view/extensions_guest_view_message_filter.cc
index 120dee5f..67d21e9 100644
--- a/extensions/browser/guest_view/extensions_guest_view_message_filter.cc
+++ b/extensions/browser/guest_view/extensions_guest_view_message_filter.cc
@@ -137,7 +137,9 @@
     const gfx::Size& new_size) {
   // We should have a GuestViewManager at this point. If we don't then the
   // embedder is misbehaving.
-  auto* manager = GetGuestViewManagerOrKill();
+  // TODO(mcnee): The renderer currently does this. Correct its behaviour
+  // so that we can enforce this.
+  auto* manager = GuestViewManager::FromBrowserContext(browser_context_);
   if (!manager)
     return;
 
diff --git a/extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container.cc b/extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container.cc
index 76eced0..b18769a 100644
--- a/extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container.cc
+++ b/extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container.cc
@@ -194,12 +194,6 @@
 void MimeHandlerViewContainer::DidResizeElement(const gfx::Size& new_size) {
   element_size_ = new_size;
 
-  // Don't try to resize a guest that hasn't been created yet. It is enough to
-  // initialise |element_size_| here and then we'll send that to the browser
-  // during guest creation.
-  if (!guest_created_)
-    return;
-
   render_frame()->Send(new ExtensionsGuestViewHostMsg_ResizeGuest(
       render_frame()->GetRoutingID(), element_instance_id(), new_size));
 }
@@ -277,8 +271,6 @@
   DCHECK_NE(this->element_instance_id(), guest_view::kInstanceIDNone);
   DCHECK_EQ(this->element_instance_id(), element_instance_id);
 
-  guest_created_ = true;
-
   if (!render_frame())
     return;
 
diff --git a/extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container.h b/extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container.h
index 268d8ae..7f5915c 100644
--- a/extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container.h
+++ b/extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container.h
@@ -116,10 +116,6 @@
   // has been called.
   bool guest_loaded_;
 
-  // True once we receive an ACK from the browser that the guest has been
-  // created.
-  bool guest_created_ = false;
-
   // The size of the element.
   gfx::Size element_size_;
 
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm
index f608eb2..1a4ae45 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm
@@ -237,6 +237,19 @@
 
 - (void)viewDidAppear:(BOOL)animated {
   [super viewDidAppear:animated];
+  // Resize the collection as it might have been rotated while not being
+  // presented (e.g. rotation on stack view).
+  [self.collectionUpdater
+      updateMostVisitedForSize:self.collectionView.bounds.size];
+  [self.headerCommandHandler
+      updateFakeOmniboxOnNewWidth:self.collectionView.bounds.size.width];
+  [self.collectionView reloadData];
+  if (ShouldCellsBeFullWidth(
+          [UIApplication sharedApplication].keyWindow.traitCollection)) {
+    self.styler.cellStyle = MDCCollectionViewCellStyleGrouped;
+  } else {
+    self.styler.cellStyle = MDCCollectionViewCellStyleCard;
+  }
   // Update the shadow bar.
   [self.audience contentOffsetDidChange];
 }
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.mm b/ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.mm
index 5f3f9ca..988c0f9 100644
--- a/ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.mm
+++ b/ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.mm
@@ -250,8 +250,16 @@
   _preEditStaticLabel.textColor = _displayedTextColor;
   _preEditStaticLabel.lineBreakMode = NSLineBreakByTruncatingHead;
 
-  NSDictionary* attributes =
-      @{NSBackgroundColorAttributeName : [self selectedTextBackgroundColor]};
+  NSMutableParagraphStyle* style = [[NSMutableParagraphStyle alloc] init];
+  // URLs have their text direction set to to LTR (avoids RTL characters
+  // making the URL render from right to left, as per the URL rendering standard
+  // described here: https://url.spec.whatwg.org/#url-rendering
+  [style setBaseWritingDirection:NSWritingDirectionLeftToRight];
+  NSDictionary* attributes = @{
+    NSBackgroundColorAttributeName : [self selectedTextBackgroundColor],
+    NSParagraphStyleAttributeName : style
+  };
+
   NSAttributedString* preEditString =
       [[NSAttributedString alloc] initWithString:self.text
                                       attributes:attributes];
@@ -526,7 +534,8 @@
   } else {
     NSMutableParagraphStyle* style = [[NSMutableParagraphStyle alloc] init];
     // URLs have their text direction set to to LTR (avoids RTL characters
-    // making the URL render from right to left, as per RFC 3987 Section 4.1).
+    // making the URL render from right to left, as per the URL rendering
+    // standard described here: https://url.spec.whatwg.org/#url-rendering
     [style setBaseWritingDirection:NSWritingDirectionLeftToRight];
 
     // Set linebreak mode to 'clipping' to ensure the text is never elided.
diff --git a/ios/chrome/browser/ui/payments/payment_request_coordinator.h b/ios/chrome/browser/ui/payments/payment_request_coordinator.h
index 2066fda..0835361 100644
--- a/ios/chrome/browser/ui/payments/payment_request_coordinator.h
+++ b/ios/chrome/browser/ui/payments/payment_request_coordinator.h
@@ -64,6 +64,10 @@
           didSelectShippingOption:
               (const payments::PaymentShippingOption&)shippingOption;
 
+// Notifies the delegate that the presenting view controller is dismissed.
+- (void)paymentRequestCoordinatorDidStop:
+    (PaymentRequestCoordinator*)coordinator;
+
 @end
 
 // Coordinator responsible for creating and presenting the PaymentRequest view
@@ -119,10 +123,6 @@
 // The delegate to be notified when the user confirms or cancels the request.
 @property(nonatomic, weak) id<PaymentRequestCoordinatorDelegate> delegate;
 
-// Dismisses the presenting view controller. Invokes |callback| when the view
-// controller is dismissed.
-- (void)stopWithCallback:(ProceduralBlock)callback;
-
 // Initiates the UI that will request card details from the user.
 - (void)
 requestFullCreditCard:(const autofill::CreditCard&)card
diff --git a/ios/chrome/browser/ui/payments/payment_request_coordinator.mm b/ios/chrome/browser/ui/payments/payment_request_coordinator.mm
index 41087458..ab28b216 100644
--- a/ios/chrome/browser/ui/payments/payment_request_coordinator.mm
+++ b/ios/chrome/browser/ui/payments/payment_request_coordinator.mm
@@ -31,6 +31,15 @@
 const NSTimeInterval kUpdatePaymentSummaryItemIntervalSeconds = 10.0;
 }  // namespace
 
+@interface PaymentRequestCoordinator ()
+
+// A weak reference to self used in -stop. -stop gets called in the
+// ChromeCoordinator's -dealloc. It is not possible to create a weak reference
+// to self in the process of deallocation.
+@property(nonatomic, weak) PaymentRequestCoordinator* weakSelf;
+
+@end
+
 @implementation PaymentRequestCoordinator {
   UINavigationController* _navigationController;
   AddressEditCoordinator* _addressEditCoordinator;
@@ -67,8 +76,11 @@
 @synthesize pending = _pending;
 @synthesize cancellable = _cancellable;
 @synthesize delegate = _delegate;
+@synthesize weakSelf = _weakSelf;
 
 - (void)start {
+  _weakSelf = self;
+
   _mediator =
       [[PaymentRequestMediator alloc] initWithPaymentRequest:_paymentRequest];
 
@@ -97,15 +109,15 @@
 }
 
 - (void)stop {
-  [self stopWithCallback:nil];
-}
-
-- (void)stopWithCallback:(ProceduralBlock)callback {
   [_updatePaymentSummaryItemTimer invalidate];
 
+  ProceduralBlock callback = ^() {
+    [_weakSelf.delegate paymentRequestCoordinatorDidStop:_weakSelf];
+  };
   [[_navigationController presentingViewController]
       dismissViewControllerAnimated:YES
                          completion:callback];
+
   [_addressEditCoordinator stop];
   _addressEditCoordinator = nil;
   [_creditCardEditCoordinator stop];
diff --git a/ios/chrome/browser/ui/payments/payment_request_coordinator_unittest.mm b/ios/chrome/browser/ui/payments/payment_request_coordinator_unittest.mm
index 4b53b950..41377afd 100644
--- a/ios/chrome/browser/ui/payments/payment_request_coordinator_unittest.mm
+++ b/ios/chrome/browser/ui/payments/payment_request_coordinator_unittest.mm
@@ -105,6 +105,18 @@
   [coordinator setPaymentRequest:payment_request()];
   [coordinator setBrowserState:browser_state()];
 
+  // Mock the coordinator delegate.
+  id check_block = ^BOOL(id value) {
+    EXPECT_TRUE(value == coordinator);
+    return YES;
+  };
+  id delegate = [OCMockObject
+      mockForProtocol:@protocol(PaymentRequestCoordinatorDelegate)];
+  [[delegate expect]
+      paymentRequestCoordinatorDidStop:[OCMArg checkWithBlock:check_block]];
+
+  [coordinator setDelegate:delegate];
+
   [coordinator start];
   // Spin the run loop to trigger the animation.
   base::test::ios::SpinRunLoopWithMaxDelay(base::TimeDelta::FromSecondsD(1));
@@ -124,6 +136,8 @@
     return !base_view_controller.presentedViewController;
   });
   EXPECT_EQ(nil, base_view_controller.presentedViewController);
+
+  EXPECT_OCMOCK_VERIFY(delegate);
 }
 
 // Tests that calling the ShippingAddressSelectionCoordinator delegate method
diff --git a/ios/chrome/browser/ui/payments/payment_request_manager.mm b/ios/chrome/browser/ui/payments/payment_request_manager.mm
index 1b0eac4..3569c9df 100644
--- a/ios/chrome/browser/ui/payments/payment_request_manager.mm
+++ b/ios/chrome/browser/ui/payments/payment_request_manager.mm
@@ -159,6 +159,10 @@
 // The dispatcher for Payment Requests.
 @property(nonatomic, weak, readonly) id<ApplicationCommands> dispatcher;
 
+// A block to be run when the |_paymentRequestCoordinator| stops.
+@property(nonatomic, strong, nullable)
+    ProceduralBlock coordinatorDidStopCallback;
+
 // Terminates the pending request with |errorMessage| and dismisses the UI.
 // Invokes the callback once the request has been terminated.
 - (void)terminatePendingRequestWithErrorMessage:(NSString*)errorMessage
@@ -242,6 +246,7 @@
 @synthesize paymentRequestJsManager = _paymentRequestJsManager;
 @synthesize pendingPaymentRequest = _pendingPaymentRequest;
 @synthesize dispatcher = _dispatcher;
+@synthesize coordinatorDidStopCallback = _coordinatorDidStopCallback;
 
 - (instancetype)initWithBaseViewController:(UIViewController*)viewController
                               browserState:
@@ -332,7 +337,6 @@
         rejectRequestPromiseWithErrorName:kAbortError
                              errorMessage:errorMessage
                         completionHandler:callback];
-    weakSelf.paymentRequestCoordinator = nil;
   };
   [self dismissUIWithCallback:dismissUICallback];
 }
@@ -712,10 +716,8 @@
     ProceduralBlock dismissUICallback = ^() {
       [weakSelf.paymentRequestJsManager
           resolveResponsePromiseWithCompletionHandler:nil];
-      weakSelf.paymentRequestCoordinator = nil;
     };
     [weakSelf dismissUIWithCallback:dismissUICallback];
-
   };
 
   // Display UI indicating failure if the value of |result| is "fail".
@@ -808,9 +810,8 @@
 }
 
 - (void)dismissUIWithCallback:(ProceduralBlock)callback {
-  [_paymentRequestCoordinator stopWithCallback:callback];
-  if (!callback)
-    _paymentRequestCoordinator = nil;
+  _coordinatorDidStopCallback = callback;
+  [_paymentRequestCoordinator stop];
 }
 
 - (BOOL)webStateContentIsSecureHTML {
@@ -966,6 +967,17 @@
   [self setUpdateEventTimeoutTimer];
 }
 
+- (void)paymentRequestCoordinatorDidStop:
+    (PaymentRequestCoordinator*)coordinator {
+  // The coordinator can now be safely set to nil.
+  _paymentRequestCoordinator = nil;
+
+  if (_coordinatorDidStopCallback) {
+    _coordinatorDidStopCallback();
+    _coordinatorDidStopCallback = nil;
+  }
+}
+
 #pragma mark - PaymentResponseHelperConsumer methods
 
 - (void)paymentResponseHelperDidReceivePaymentMethodDetails {
diff --git a/ipc/ipc_message_templates.h b/ipc/ipc_message_templates.h
index cc90376..8c9f3eeb 100644
--- a/ipc/ipc_message_templates.h
+++ b/ipc/ipc_message_templates.h
@@ -23,8 +23,8 @@
 // This function is for all the async IPCs that don't pass an extra parameter
 // using IPC_BEGIN_MESSAGE_MAP_WITH_PARAM.
 template <typename ObjT, typename Method, typename P, typename Tuple>
-void DispatchToMethod(ObjT* obj, Method method, P*, const Tuple& tuple) {
-  base::DispatchToMethod(obj, method, tuple);
+void DispatchToMethod(ObjT* obj, Method method, P*, Tuple&& tuple) {
+  base::DispatchToMethod(obj, method, std::forward<Tuple>(tuple));
 }
 
 template <typename ObjT,
@@ -35,22 +35,22 @@
 void DispatchToMethodImpl(ObjT* obj,
                           Method method,
                           P* parameter,
-                          const Tuple& tuple,
+                          Tuple&& tuple,
                           std::index_sequence<Ns...>) {
-  // TODO(mdempsky): Apply UnwrapTraits like base::DispatchToMethod?
-  (obj->*method)(parameter, std::get<Ns>(tuple)...);
+  (obj->*method)(parameter, std::get<Ns>(std::forward<Tuple>(tuple))...);
 }
 
 // The following function is for async IPCs which have a dispatcher with an
 // extra parameter specified using IPC_BEGIN_MESSAGE_MAP_WITH_PARAM.
-template <typename ObjT, typename P, typename... Args, typename... Ts>
-typename std::enable_if<sizeof...(Args) == sizeof...(Ts)>::type
+template <typename ObjT, typename P, typename... Args, typename Tuple>
+std::enable_if_t<sizeof...(Args) == std::tuple_size<std::decay_t<Tuple>>::value>
 DispatchToMethod(ObjT* obj,
                  void (ObjT::*method)(P*, Args...),
                  P* parameter,
-                 const std::tuple<Ts...>& tuple) {
-  DispatchToMethodImpl(obj, method, parameter, tuple,
-                       std::make_index_sequence<sizeof...(Ts)>());
+                 Tuple&& tuple) {
+  constexpr size_t size = std::tuple_size<std::decay_t<Tuple>>::value;
+  DispatchToMethodImpl(obj, method, parameter, std::forward<Tuple>(tuple),
+                       std::make_index_sequence<size>());
 }
 
 enum class MessageKind {
@@ -119,7 +119,7 @@
     TRACE_EVENT0("ipc", Meta::kName);
     Param p;
     if (Read(msg, &p)) {
-      DispatchToMethod(obj, func, parameter, p);
+      DispatchToMethod(obj, func, parameter, std::move(p));
       return true;
     }
     return false;
@@ -171,7 +171,7 @@
     Message* reply = SyncMessage::GenerateReply(msg);
     if (ok) {
       ReplyParam reply_params;
-      base::DispatchToMethod(obj, func, send_params, &reply_params);
+      base::DispatchToMethod(obj, func, std::move(send_params), &reply_params);
       WriteParam(reply, reply_params);
       LogReplyParamsToMessage(reply_params, msg);
     } else {
@@ -194,7 +194,7 @@
     if (ok) {
       std::tuple<Message&> t = std::tie(*reply);
       ConnectMessageAndReply(msg, reply);
-      base::DispatchToMethod(obj, func, send_params, &t);
+      base::DispatchToMethod(obj, func, std::move(send_params), &t);
     } else {
       NOTREACHED() << "Error deserializing message " << msg->type();
       reply->set_reply_error();
@@ -216,8 +216,9 @@
       std::tuple<Message&> t = std::tie(*reply);
       ConnectMessageAndReply(msg, reply);
       std::tuple<P*> parameter_tuple(parameter);
-      auto concat_params = std::tuple_cat(parameter_tuple, send_params);
-      base::DispatchToMethod(obj, func, concat_params, &t);
+      auto concat_params =
+          std::tuple_cat(std::move(parameter_tuple), std::move(send_params));
+      base::DispatchToMethod(obj, func, std::move(concat_params), &t);
     } else {
       NOTREACHED() << "Error deserializing message " << msg->type();
       reply->set_reply_error();
diff --git a/net/dns/dns_config_service_posix.cc b/net/dns/dns_config_service_posix.cc
index 088fb9b..a118257 100644
--- a/net/dns/dns_config_service_posix.cc
+++ b/net/dns/dns_config_service_posix.cc
@@ -174,14 +174,16 @@
 // TODO(juliatuttle): Depend on libcutils, then switch this (and other uses of
 //                    __system_property_get) to property_get.
 ConfigParsePosixResult ReadDnsConfig(DnsConfig* dns_config) {
+  dns_config->nameservers.clear();
+
   if (base::android::BuildInfo::GetInstance()->sdk_int() >=
       base::android::SDK_VERSION_MARSHMALLOW) {
-    dns_config->nameservers.clear();
     net::android::GetDnsServers(&dns_config->nameservers);
     if (dns_config->nameservers.empty())
       return CONFIG_PARSE_POSIX_NO_NAMESERVERS;
     return CONFIG_PARSE_POSIX_OK;
   }
+
   char property_value[PROP_VALUE_MAX];
   __system_property_get("net.dns1", property_value);
   std::string dns1_string = property_value;
diff --git a/net/dns/dns_config_service_posix_unittest.cc b/net/dns/dns_config_service_posix_unittest.cc
index 2333ab4..0626fa7e 100644
--- a/net/dns/dns_config_service_posix_unittest.cc
+++ b/net/dns/dns_config_service_posix_unittest.cc
@@ -211,6 +211,7 @@
   void OnConfigChanged(const DnsConfig& config) {
     EXPECT_TRUE(config.IsValid());
     seen_config_ = true;
+    real_config_ = config;
     run_loop_->QuitWhenIdle();
   }
 
@@ -253,15 +254,15 @@
     // ASSERT_TRUE(hosts.GetInfo(&hosts_info));
     // ASSERT_TRUE(base::TouchFile(temp_file_, hosts_info.last_modified,
     //                            hosts_info.last_accessed));
+
+    creation_time_ = base::Time::Now();
+    service_.reset(new DnsConfigServicePosix());
+    MockHostsFilePath(temp_file_.value().c_str());
   }
 
   void TearDown() override { ASSERT_TRUE(base::DeleteFile(temp_file_, false)); }
 
   void StartWatching() {
-    creation_time_ = base::Time::Now();
-    service_.reset(new DnsConfigServicePosix());
-    MockHostsFilePath(temp_file_.value().c_str());
-    MockDNSConfig("8.8.8.8");
     seen_config_ = false;
     service_->WatchConfig(base::Bind(
         &DnsConfigServicePosixTest::OnConfigChanged, base::Unretained(this)));
@@ -281,11 +282,13 @@
   base::FilePath temp_file_;
   std::unique_ptr<DnsConfigServicePosix> service_;
   DnsConfig test_config_;
+  DnsConfig real_config_;
   std::unique_ptr<base::RunLoop> run_loop_;
 };
 
 TEST_F(DnsConfigServicePosixTest, SeenChangeSinceNetworkChange) {
   // Verify SeenChangeSince() returns false if no changes
+  MockDNSConfig("8.8.8.8");
   StartWatching();
   EXPECT_FALSE(service_->SeenChangeSince(creation_time_));
   // Verify SeenChangeSince() returns true if network change
@@ -295,6 +298,25 @@
   ExpectChange();
 }
 
+// Regression test for https://crbug.com/704662.
+TEST_F(DnsConfigServicePosixTest, ChangeConfigMultipleTimes) {
+  service_->WatchConfig(base::Bind(&DnsConfigServicePosixTest::OnConfigChanged,
+                                   base::Unretained(this)));
+  base::RunLoop().RunUntilIdle();
+
+  for (int i = 0; i < 5; i++) {
+    service_->OnNetworkChanged(NetworkChangeNotifier::CONNECTION_WIFI);
+    // Wait for config read after the change. OnConfigChanged() will only be
+    // called if the new config is different from the old one, so this can't be
+    // ExpectChange().
+    base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(50));
+    base::RunLoop().RunUntilIdle();
+  }
+
+  // There should never be more than 4 nameservers in a real config.
+  EXPECT_GT(5u, real_config_.nameservers.size());
+}
+
 }  // namespace internal
 
 #endif  // OS_ANDROID
diff --git a/services/resource_coordinator/BUILD.gn b/services/resource_coordinator/BUILD.gn
index 6e363bd..757fb90 100644
--- a/services/resource_coordinator/BUILD.gn
+++ b/services/resource_coordinator/BUILD.gn
@@ -12,7 +12,6 @@
 
 source_set("lib") {
   sources = [
-    "coordination_unit/background_metrics_reporter.h",
     "coordination_unit/coordination_unit_graph_observer.cc",
     "coordination_unit/coordination_unit_graph_observer.h",
     "coordination_unit/coordination_unit_impl.cc",
diff --git a/services/resource_coordinator/coordination_unit/background_metrics_reporter.h b/services/resource_coordinator/coordination_unit/background_metrics_reporter.h
deleted file mode 100644
index a2692a6..0000000
--- a/services/resource_coordinator/coordination_unit/background_metrics_reporter.h
+++ /dev/null
@@ -1,136 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef SERVICES_RESOURCE_COORDINATOR_COORDINATION_UNIT_BACKGROUND_METRICS_REPORTER_H_
-#define SERVICES_RESOURCE_COORDINATOR_COORDINATION_UNIT_BACKGROUND_METRICS_REPORTER_H_
-
-#include "base/macros.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/time/time.h"
-#include "services/metrics/public/cpp/ukm_builders.h"
-
-// Tabs can be kept in the background for a long time, metrics show 75th
-// percentile of time spent in background is 2.5 hours, and the 95th is 24 hour.
-// In order to guide the selection of an appropriate observation window we are
-// proposing using a CUSTOM_TIMES histogram from 1s to 48h, with 100 buckets.
-#define HEURISTICS_HISTOGRAM(name, sample)                                  \
-  UMA_HISTOGRAM_CUSTOM_TIMES(name, sample, base::TimeDelta::FromSeconds(1), \
-                             base::TimeDelta::FromHours(48), 100)
-
-namespace ukm {
-class MojoUkmRecorder;
-}  // namespace ukm
-
-namespace resource_coordinator {
-
-namespace internal {
-
-enum UKMFrameReportType : uint8_t {
-  kMainFrameOnly = 0,
-  kMainFrameAndChildFrame
-};
-
-template <class UKMBuilderClass,
-          internal::UKMFrameReportType kShouldReportChildFrameUkm>
-class UKMReportDelegate {};
-
-template <class UKMBuilderClass>
-class UKMReportDelegate<UKMBuilderClass, internal::kMainFrameOnly> {
- public:
-  void ReportUKM(int64_t ukm_source_id,
-                 bool is_main_frame,
-                 int64_t duration_in_ms,
-                 ukm::MojoUkmRecorder* ukm_recorder) {
-    UKMBuilderClass ukm_builder(ukm_source_id);
-    ukm_builder.SetTimeFromBackgrounded(duration_in_ms).Record(ukm_recorder);
-  }
-};
-
-template <class UKMBuilderClass>
-class UKMReportDelegate<UKMBuilderClass, internal::kMainFrameAndChildFrame> {
- public:
-  void ReportUKM(int64_t ukm_source_id,
-                 bool is_main_frame,
-                 int64_t duration_in_ms,
-                 ukm::MojoUkmRecorder* ukm_recorder) {
-    UKMBuilderClass ukm_builder(ukm_source_id);
-    ukm_builder.SetIsMainFrame(is_main_frame)
-        .SetTimeFromBackgrounded(duration_in_ms)
-        .Record(ukm_recorder);
-  }
-};
-
-}  // namespace internal
-
-template <class UKMBuilderClass,
-          const char* kMetricName,
-          internal::UKMFrameReportType kShouldReportChildFrameUkm>
-class BackgroundMetricsReporter {
- public:
-  BackgroundMetricsReporter()
-      : ukm_source_id_(-1),
-        uma_reported_(false),
-        ukm_reported_(false),
-        child_frame_ukm_reported_(false) {}
-
-  void Reset() {
-    uma_reported_ = false;
-    ukm_reported_ = false;
-    child_frame_ukm_reported_ = false;
-  }
-
-  void SetUKMSourceID(int64_t ukm_source_id) { ukm_source_id_ = ukm_source_id; }
-
-  void OnSignalReceived(bool is_main_frame,
-                        base::TimeDelta duration,
-                        ukm::MojoUkmRecorder* ukm_recorder) {
-    if (!uma_reported_) {
-      uma_reported_ = true;
-      HEURISTICS_HISTOGRAM(kMetricName, duration);
-    }
-
-    ReportUKMIfNeeded(is_main_frame, duration, ukm_recorder);
-  }
-
- private:
-  void ReportUKMIfNeeded(bool is_main_frame,
-                         base::TimeDelta duration,
-                         ukm::MojoUkmRecorder* ukm_recorder) {
-    if (ukm_source_id_ == -1 ||
-        (!kShouldReportChildFrameUkm && ukm_reported_) ||
-        (kShouldReportChildFrameUkm &&
-         !ShouldReportMainFrameUKM(is_main_frame) &&
-         !ShouldReportChildFrameUKM(is_main_frame))) {
-      return;
-    }
-
-    ukm_reporter_.ReportUKM(ukm_source_id_, is_main_frame,
-                            duration.InMilliseconds(), ukm_recorder);
-
-    if (is_main_frame) {
-      ukm_reported_ = true;
-    } else {
-      child_frame_ukm_reported_ = true;
-    }
-  }
-
-  bool ShouldReportMainFrameUKM(bool is_main_frame) const {
-    return is_main_frame && !ukm_reported_;
-  }
-
-  bool ShouldReportChildFrameUKM(bool is_main_frame) const {
-    return !is_main_frame && !child_frame_ukm_reported_;
-  }
-
-  int64_t ukm_source_id_;
-  bool uma_reported_;
-  bool ukm_reported_;
-  bool child_frame_ukm_reported_;
-  internal::UKMReportDelegate<UKMBuilderClass, kShouldReportChildFrameUkm>
-      ukm_reporter_;
-};
-
-}  // namespace resource_coordinator
-
-#endif  // SERVICES_RESOURCE_COORDINATOR_COORDINATION_UNIT_BACKGROUND_METRICS_REPORTER_H_
diff --git a/services/resource_coordinator/coordination_unit/coordination_unit_impl.cc b/services/resource_coordinator/coordination_unit/coordination_unit_impl.cc
index f1a61a1d..69c2385 100644
--- a/services/resource_coordinator/coordination_unit/coordination_unit_impl.cc
+++ b/services/resource_coordinator/coordination_unit/coordination_unit_impl.cc
@@ -44,14 +44,6 @@
 }
 
 // static
-const WebContentsCoordinationUnitImpl*
-CoordinationUnitImpl::ToWebContentsCoordinationUnit(
-    const CoordinationUnitImpl* cu) {
-  DCHECK(cu->id().type == CoordinationUnitType::kWebContents);
-  return static_cast<const WebContentsCoordinationUnitImpl*>(cu);
-}
-
-// static
 std::vector<CoordinationUnitImpl*>
 CoordinationUnitImpl::GetCoordinationUnitsOfType(CoordinationUnitType type) {
   std::vector<CoordinationUnitImpl*> results;
diff --git a/services/resource_coordinator/coordination_unit/coordination_unit_impl.h b/services/resource_coordinator/coordination_unit/coordination_unit_impl.h
index 4bac3b5..b12959c 100644
--- a/services/resource_coordinator/coordination_unit/coordination_unit_impl.h
+++ b/services/resource_coordinator/coordination_unit/coordination_unit_impl.h
@@ -38,8 +38,6 @@
       const CoordinationUnitImpl* coordination_unit);
   static WebContentsCoordinationUnitImpl* ToWebContentsCoordinationUnit(
       CoordinationUnitImpl* coordination_unit);
-  static const WebContentsCoordinationUnitImpl* ToWebContentsCoordinationUnit(
-      const CoordinationUnitImpl* coordination_unit);
 
   static std::vector<CoordinationUnitImpl*> GetCoordinationUnitsOfType(
       CoordinationUnitType type);
diff --git a/services/resource_coordinator/coordination_unit/metrics_collector.cc b/services/resource_coordinator/coordination_unit/metrics_collector.cc
index d0ec87e5..155d436 100644
--- a/services/resource_coordinator/coordination_unit/metrics_collector.cc
+++ b/services/resource_coordinator/coordination_unit/metrics_collector.cc
@@ -5,6 +5,7 @@
 #include "services/resource_coordinator/coordination_unit/metrics_collector.h"
 
 #include "base/metrics/histogram_macros.h"
+#include "base/strings/string_number_conversions.h"
 #include "services/resource_coordinator/coordination_unit/coordination_unit_impl.h"
 #include "services/resource_coordinator/coordination_unit/coordination_unit_manager.h"
 #include "services/resource_coordinator/coordination_unit/frame_coordination_unit_impl.h"
@@ -24,13 +25,7 @@
 
 const size_t kDefaultMaxCPUUsageMeasurements = 30u;
 
-// Audio is considered to have started playing if the tab has never
-// previously played audio, or has been silent for at least one minute.
-const base::TimeDelta kMaxAudioSlientTimeout = base::TimeDelta::FromMinutes(1);
-// Delay the metrics report from GRC to UMA/UKM for 5 minutes from when the main
-// frame navigation is committed.
-const base::TimeDelta kMetricsReportDelayTimeout =
-    base::TimeDelta::FromMinutes(5);
+constexpr base::TimeDelta kMaxAudioSlientTime = base::TimeDelta::FromMinutes(1);
 
 const char kTabFromBackgroundedToFirstAlertFiredUMA[] =
     "TabManager.Heuristics.FromBackgroundedToFirstAlertFired";
@@ -76,14 +71,6 @@
          coordination_unit->id().type == CoordinationUnitType::kWebContents;
 }
 
-void MetricsCollector::OnCoordinationUnitCreated(
-    const CoordinationUnitImpl* coordination_unit) {
-  if (coordination_unit->id().type == CoordinationUnitType::kWebContents) {
-    metrics_report_record_map_.emplace(coordination_unit->id(),
-                                       MetricsReportRecord());
-  }
-}
-
 void MetricsCollector::OnBeforeCoordinationUnitDestroyed(
     const CoordinationUnitImpl* coordination_unit) {
   if (coordination_unit->id().type == CoordinationUnitType::kFrame) {
@@ -109,22 +96,31 @@
     }
     auto* web_contents_cu = frame_cu->GetWebContentsCoordinationUnit();
     // Only record metrics while it is backgrounded.
-    if (!web_contents_cu || web_contents_cu->IsVisible() ||
-        !ShouldReportMetrics(web_contents_cu)) {
+    if (!web_contents_cu || web_contents_cu->IsVisible())
       return;
-    }
     // Audio is considered to have started playing if the tab has never
     // previously played audio, or has been silent for at least one minute.
     auto now = clock_->NowTicks();
-    if (frame_data.last_audible_time + kMaxAudioSlientTimeout < now) {
+    if (frame_data.last_audible_time + kMaxAudioSlientTime < now) {
       MetricsReportRecord& record =
-          metrics_report_record_map_.find(web_contents_cu->id())->second;
+          metrics_report_record_map_[web_contents_cu->id()];
       auto duration =
           now -
           web_contents_data_map_[web_contents_cu->id()].last_invisible_time;
-      record.first_audible.OnSignalReceived(
-          frame_cu->IsMainFrame(), duration,
-          coordination_unit_manager().ukm_recorder());
+
+      if (!record.first_audible_after_backgrounded_reported) {
+        HEURISTICS_HISTOGRAM(kTabFromBackgroundedToFirstAudioStartsUMA,
+                             duration);
+        record.first_audible_after_backgrounded_reported = true;
+      }
+
+      bool is_main_frame = frame_cu->IsMainFrame();
+      ReportAudibilityUKMIfNeeded(
+          web_contents_cu,
+          is_main_frame
+              ? &record.main_frame_first_audible_after_backgrounded_reported
+              : &record.child_frame_first_audible_after_backgrounded_reported,
+          is_main_frame, duration);
     }
   }
 }
@@ -151,10 +147,8 @@
     }
   } else if (property_type == mojom::PropertyType::kUKMSourceId) {
     ukm::SourceId ukm_source_id = value;
+
     UpdateUkmSourceIdForWebContents(web_contents_cu_id, ukm_source_id);
-    MetricsReportRecord& record =
-        metrics_report_record_map_.find(web_contents_cu_id)->second;
-    record.UpdateUKMSourceID(ukm_source_id);
   }
 }
 
@@ -164,33 +158,37 @@
   if (event == mojom::Event::kAlertFired) {
     auto* web_contents_cu = frame_cu->GetWebContentsCoordinationUnit();
     // Only record metrics while it is backgrounded.
-    if (!web_contents_cu || web_contents_cu->IsVisible() ||
-        !ShouldReportMetrics(web_contents_cu)) {
+    if (!web_contents_cu || web_contents_cu->IsVisible())
       return;
-    }
-    auto duration =
-        clock_->NowTicks() -
-        web_contents_data_map_[web_contents_cu->id()].last_invisible_time;
+    auto now = clock_->NowTicks();
     MetricsReportRecord& record =
-        metrics_report_record_map_.find(web_contents_cu->id())->second;
-    record.first_alert_fired.OnSignalReceived(
-        frame_cu->IsMainFrame(), duration,
-        coordination_unit_manager().ukm_recorder());
+        metrics_report_record_map_[web_contents_cu->id()];
+    if (!record.first_alert_fired_after_backgrounded_reported) {
+      const WebContentsData& web_contents_data =
+          web_contents_data_map_[web_contents_cu->id()];
+      HEURISTICS_HISTOGRAM(kTabFromBackgroundedToFirstAlertFiredUMA,
+                           now - web_contents_data.last_invisible_time);
+      record.first_alert_fired_after_backgrounded_reported = true;
+    }
   } else if (event == mojom::Event::kNonPersistentNotificationCreated) {
     auto* web_contents_cu = frame_cu->GetWebContentsCoordinationUnit();
     // Only record metrics while it is backgrounded.
-    if (!web_contents_cu || web_contents_cu->IsVisible() ||
-        !ShouldReportMetrics(web_contents_cu)) {
+    if (!web_contents_cu || web_contents_cu->IsVisible())
       return;
-    }
-    auto duration =
-        clock_->NowTicks() -
-        web_contents_data_map_[web_contents_cu->id()].last_invisible_time;
+    auto now = clock_->NowTicks();
     MetricsReportRecord& record =
-        metrics_report_record_map_.find(web_contents_cu->id())->second;
-    record.first_non_persistent_notification_created.OnSignalReceived(
-        frame_cu->IsMainFrame(), duration,
-        coordination_unit_manager().ukm_recorder());
+        metrics_report_record_map_[web_contents_cu->id()];
+    if (!record
+             .first_non_persistent_notification_created_after_backgrounded_reported) {
+      const WebContentsData web_contents_data =
+          web_contents_data_map_[web_contents_cu->id()];
+      HEURISTICS_HISTOGRAM(
+          kTabFromBackgroundedToFirstNonPersistentNotificationCreatedUMA,
+          now - web_contents_data.last_invisible_time);
+      record
+          .first_non_persistent_notification_created_after_backgrounded_reported =
+          true;
+    }
   }
 }
 
@@ -199,39 +197,35 @@
     const mojom::Event event) {
   if (event == mojom::Event::kTitleUpdated) {
     // Only record metrics while it is backgrounded.
-    if (web_contents_cu->IsVisible() || !ShouldReportMetrics(web_contents_cu))
+    if (web_contents_cu->IsVisible())
       return;
-    auto duration =
-        clock_->NowTicks() -
-        web_contents_data_map_[web_contents_cu->id()].last_invisible_time;
+    auto now = clock_->NowTicks();
     MetricsReportRecord& record =
-        metrics_report_record_map_.find(web_contents_cu->id())->second;
-    record.first_title_updated.OnSignalReceived(
-        true, duration, coordination_unit_manager().ukm_recorder());
+        metrics_report_record_map_[web_contents_cu->id()];
+    if (!record.first_title_updated_after_backgrounded_reported) {
+      const WebContentsData& web_contents_data =
+          web_contents_data_map_[web_contents_cu->id()];
+      HEURISTICS_HISTOGRAM(kTabFromBackgroundedToFirstTitleUpdatedUMA,
+                           now - web_contents_data.last_invisible_time);
+      record.first_title_updated_after_backgrounded_reported = true;
+    }
   } else if (event == mojom::Event::kFaviconUpdated) {
     // Only record metrics while it is backgrounded.
-    if (web_contents_cu->IsVisible() || !ShouldReportMetrics(web_contents_cu))
+    if (web_contents_cu->IsVisible())
       return;
-    auto duration =
-        clock_->NowTicks() -
-        web_contents_data_map_[web_contents_cu->id()].last_invisible_time;
+    auto now = clock_->NowTicks();
     MetricsReportRecord& record =
-        metrics_report_record_map_.find(web_contents_cu->id())->second;
-    record.first_favicon_updated.OnSignalReceived(
-        true, duration, coordination_unit_manager().ukm_recorder());
-  } else if (event == mojom::Event::kNavigationCommitted) {
-    web_contents_data_map_[web_contents_cu->id()].navigation_finished_time =
-        clock_->NowTicks();
+        metrics_report_record_map_[web_contents_cu->id()];
+    if (!record.first_favicon_updated_after_backgrounded_reported) {
+      const WebContentsData& web_contents_data =
+          web_contents_data_map_[web_contents_cu->id()];
+      HEURISTICS_HISTOGRAM(kTabFromBackgroundedToFirstFaviconUpdatedUMA,
+                           now - web_contents_data.last_invisible_time);
+      record.first_favicon_updated_after_backgrounded_reported = true;
+    }
   }
 }
 
-bool MetricsCollector::ShouldReportMetrics(
-    const WebContentsCoordinationUnitImpl* web_contents_cu) {
-  return clock_->NowTicks() - web_contents_data_map_[web_contents_cu->id()]
-                                  .navigation_finished_time >
-         kMetricsReportDelayTimeout;
-}
-
 bool MetricsCollector::IsCollectingCPUUsageForUkm(
     const CoordinationUnitID& web_contents_cu_id) {
   UkmCPUUsageCollectionState& state =
@@ -255,6 +249,25 @@
       .Record(coordination_unit_manager().ukm_recorder());
 }
 
+void MetricsCollector::ReportAudibilityUKMIfNeeded(
+    const WebContentsCoordinationUnitImpl* web_contents_cu,
+    bool* reported,
+    bool is_main_frame,
+    base::TimeDelta duration) {
+  if (*reported)
+    return;
+  int64_t ukm_source_id = -1;
+  if (!web_contents_cu->GetProperty(mojom::PropertyType::kUKMSourceId,
+                                    &ukm_source_id)) {
+    return;
+  }
+  ukm::builders::TabManager_Background_FirstAudioStarts(ukm_source_id)
+      .SetIsMainFrame(is_main_frame)
+      .SetTimeFromBackgrounded(duration.InMilliseconds())
+      .Record(coordination_unit_manager().ukm_recorder());
+  *reported = true;
+}
+
 void MetricsCollector::UpdateUkmSourceIdForWebContents(
     const CoordinationUnitID& web_contents_cu_id,
     ukm::SourceId ukm_source_id) {
@@ -277,31 +290,30 @@
 }
 
 void MetricsCollector::ResetMetricsReportRecord(CoordinationUnitID cu_id) {
-  DCHECK(metrics_report_record_map_.find(cu_id) !=
-         metrics_report_record_map_.end());
-  metrics_report_record_map_.find(cu_id)->second.Reset();
+  auto metrics_report_record_iter = metrics_report_record_map_.find(cu_id);
+  if (metrics_report_record_iter == metrics_report_record_map_.end())
+    return;
+  metrics_report_record_iter->second.Reset();
 }
 
-MetricsCollector::MetricsReportRecord::MetricsReportRecord() = default;
-
-MetricsCollector::MetricsReportRecord::MetricsReportRecord(
-    const MetricsReportRecord& other) = default;
-
-void MetricsCollector::MetricsReportRecord::UpdateUKMSourceID(
-    int64_t ukm_source_id) {
-  first_alert_fired.SetUKMSourceID(ukm_source_id);
-  first_audible.SetUKMSourceID(ukm_source_id);
-  first_favicon_updated.SetUKMSourceID(ukm_source_id);
-  first_non_persistent_notification_created.SetUKMSourceID(ukm_source_id);
-  first_title_updated.SetUKMSourceID(ukm_source_id);
-}
+MetricsCollector::MetricsReportRecord::MetricsReportRecord()
+    : first_alert_fired_after_backgrounded_reported(false),
+      first_audible_after_backgrounded_reported(false),
+      first_favicon_updated_after_backgrounded_reported(false),
+      first_non_persistent_notification_created_after_backgrounded_reported(
+          false),
+      first_title_updated_after_backgrounded_reported(false),
+      main_frame_first_audible_after_backgrounded_reported(false),
+      child_frame_first_audible_after_backgrounded_reported(false) {}
 
 void MetricsCollector::MetricsReportRecord::Reset() {
-  first_alert_fired.Reset();
-  first_audible.Reset();
-  first_favicon_updated.Reset();
-  first_non_persistent_notification_created.Reset();
-  first_title_updated.Reset();
+  first_alert_fired_after_backgrounded_reported = false;
+  first_audible_after_backgrounded_reported = false;
+  first_favicon_updated_after_backgrounded_reported = false;
+  first_non_persistent_notification_created_after_backgrounded_reported = false;
+  first_title_updated_after_backgrounded_reported = false;
+  main_frame_first_audible_after_backgrounded_reported = false;
+  child_frame_first_audible_after_backgrounded_reported = false;
 }
 
 }  // namespace resource_coordinator
diff --git a/services/resource_coordinator/coordination_unit/metrics_collector.h b/services/resource_coordinator/coordination_unit/metrics_collector.h
index 16c6eed..d9a11a5 100644
--- a/services/resource_coordinator/coordination_unit/metrics_collector.h
+++ b/services/resource_coordinator/coordination_unit/metrics_collector.h
@@ -6,11 +6,9 @@
 #define SERVICES_RESOURCE_COORDINATOR_COORDINATION_UNIT_METRICS_COLLECTOR_H_
 
 #include "base/macros.h"
-#include "base/metrics/histogram_macros.h"
 #include "base/time/default_tick_clock.h"
 #include "base/time/time.h"
 #include "services/metrics/public/cpp/ukm_builders.h"
-#include "services/resource_coordinator/coordination_unit/background_metrics_reporter.h"
 #include "services/resource_coordinator/coordination_unit/coordination_unit_graph_observer.h"
 
 namespace resource_coordinator {
@@ -25,8 +23,6 @@
 extern const char kTabFromBackgroundedToFirstTitleUpdatedUMA[];
 extern const char
     kTabFromBackgroundedToFirstNonPersistentNotificationCreatedUMA[];
-extern const base::TimeDelta kMaxAudioSlientTimeout;
-extern const base::TimeDelta kMetricsReportDelayTimeout;
 
 // A MetricsCollector observes changes happened inside CoordinationUnit Graph,
 // and reports UMA/UKM.
@@ -37,8 +33,6 @@
 
   // CoordinationUnitGraphObserver implementation.
   bool ShouldObserve(const CoordinationUnitImpl* coordination_unit) override;
-  void OnCoordinationUnitCreated(
-      const CoordinationUnitImpl* coordination_unit) override;
   void OnBeforeCoordinationUnitDestroyed(
       const CoordinationUnitImpl* coordination_unit) override;
   void OnFramePropertyChanged(const FrameCoordinationUnitImpl* frame_cu,
@@ -59,35 +53,17 @@
 
   struct MetricsReportRecord {
     MetricsReportRecord();
-    MetricsReportRecord(const MetricsReportRecord& other);
-    void UpdateUKMSourceID(int64_t ukm_source_id);
     void Reset();
-    BackgroundMetricsReporter<
-        ukm::builders::TabManager_Background_FirstAlertFired,
-        kTabFromBackgroundedToFirstAlertFiredUMA,
-        internal::UKMFrameReportType::kMainFrameAndChildFrame>
-        first_alert_fired;
-    BackgroundMetricsReporter<
-        ukm::builders::TabManager_Background_FirstAudioStarts,
-        kTabFromBackgroundedToFirstAudioStartsUMA,
-        internal::UKMFrameReportType::kMainFrameAndChildFrame>
-        first_audible;
-    BackgroundMetricsReporter<
-        ukm::builders::TabManager_Background_FirstFaviconUpdated,
-        kTabFromBackgroundedToFirstFaviconUpdatedUMA,
-        internal::UKMFrameReportType::kMainFrameOnly>
-        first_favicon_updated;
-    BackgroundMetricsReporter<
-        ukm::builders::
-            TabManager_Background_FirstNonPersistentNotificationCreated,
-        kTabFromBackgroundedToFirstNonPersistentNotificationCreatedUMA,
-        internal::UKMFrameReportType::kMainFrameAndChildFrame>
-        first_non_persistent_notification_created;
-    BackgroundMetricsReporter<
-        ukm::builders::TabManager_Background_FirstTitleUpdated,
-        kTabFromBackgroundedToFirstTitleUpdatedUMA,
-        internal::UKMFrameReportType::kMainFrameOnly>
-        first_title_updated;
+    // UMA histograms report.
+    bool first_alert_fired_after_backgrounded_reported;
+    bool first_audible_after_backgrounded_reported;
+    bool first_favicon_updated_after_backgrounded_reported;
+    bool first_non_persistent_notification_created_after_backgrounded_reported;
+    bool first_title_updated_after_backgrounded_reported;
+
+    // UKM collection report.
+    bool main_frame_first_audible_after_backgrounded_reported;
+    bool child_frame_first_audible_after_backgrounded_reported;
   };
 
   struct FrameData {
@@ -96,7 +72,6 @@
 
   struct WebContentsData {
     base::TimeTicks last_invisible_time;
-    base::TimeTicks navigation_finished_time;
   };
 
   struct UkmCPUUsageCollectionState {
@@ -106,12 +81,15 @@
     ukm::SourceId ukm_source_id = -1;
   };
 
-  bool ShouldReportMetrics(
-      const WebContentsCoordinationUnitImpl* web_contents_cu);
   bool IsCollectingCPUUsageForUkm(const CoordinationUnitID& web_contents_cu_id);
   void RecordCPUUsageForUkm(const CoordinationUnitID& web_contents_cu_id,
                             double cpu_usage,
                             size_t num_coresident_tabs);
+  void ReportAudibilityUKMIfNeeded(
+      const WebContentsCoordinationUnitImpl* web_contents_cu,
+      bool* reported,
+      bool is_main_frame,
+      base::TimeDelta duration);
   void UpdateUkmSourceIdForWebContents(
       const CoordinationUnitID& web_contents_cu_id,
       ukm::SourceId ukm_source_id);
diff --git a/services/resource_coordinator/coordination_unit/metrics_collector_unittest.cc b/services/resource_coordinator/coordination_unit/metrics_collector_unittest.cc
index f980f73c..1dca002 100644
--- a/services/resource_coordinator/coordination_unit/metrics_collector_unittest.cc
+++ b/services/resource_coordinator/coordination_unit/metrics_collector_unittest.cc
@@ -12,15 +12,8 @@
 
 namespace resource_coordinator {
 
-const base::TimeDelta kTestMetricsReportDelayTimeout =
-    kMetricsReportDelayTimeout + base::TimeDelta::FromSeconds(1);
-const base::TimeDelta kTestMaxAudioSlientTimeout =
-    kMaxAudioSlientTimeout + base::TimeDelta::FromSeconds(1);
-
 class MetricsCollectorTest : public CoordinationUnitImplTestBase {
  public:
-  MetricsCollectorTest() : CoordinationUnitImplTestBase() {}
-
   void SetUp() override {
     MetricsCollector* metrics_collector = new MetricsCollector();
     const_cast<base::TickClock*&>(metrics_collector->clock_) = &clock_;
@@ -33,9 +26,6 @@
 
   base::HistogramTester histogram_tester_;
   base::SimpleTestTickClock clock_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(MetricsCollectorTest);
 };
 
 TEST_F(MetricsCollectorTest, FromBackgroundedToFirstAudioStartsUMA) {
@@ -50,9 +40,6 @@
 
   web_contents_cu->AddChild(frame_cu->id());
 
-  web_contents_cu->SendEvent(mojom::Event::kNavigationCommitted);
-  AdvanceClock(kTestMetricsReportDelayTimeout);
-
   web_contents_cu->SetProperty(mojom::PropertyType::kVisible, true);
   frame_cu->SetProperty(mojom::PropertyType::kAudible, true);
   // The tab is not backgrounded, thus no metrics recorded.
@@ -67,7 +54,7 @@
                                      0);
   frame_cu->SetProperty(mojom::PropertyType::kAudible, false);
 
-  AdvanceClock(kTestMaxAudioSlientTimeout);
+  AdvanceClock(base::TimeDelta::FromMinutes(1));
   web_contents_cu->SetProperty(mojom::PropertyType::kVisible, true);
   frame_cu->SetProperty(mojom::PropertyType::kAudible, true);
   // The tab was not recently audible but it is not backgrounded, thus no
@@ -77,25 +64,15 @@
   frame_cu->SetProperty(mojom::PropertyType::kAudible, false);
 
   web_contents_cu->SetProperty(mojom::PropertyType::kVisible, false);
-  AdvanceClock(kTestMaxAudioSlientTimeout);
+  AdvanceClock(base::TimeDelta::FromSeconds(61));
   frame_cu->SetProperty(mojom::PropertyType::kAudible, true);
   // The tab was not recently audible and it is backgrounded, thus metrics
   // recorded.
   histogram_tester_.ExpectTotalCount(kTabFromBackgroundedToFirstAudioStartsUMA,
                                      1);
-  frame_cu->SetProperty(mojom::PropertyType::kAudible, false);
-
-  web_contents_cu->SetProperty(mojom::PropertyType::kVisible, true);
-  web_contents_cu->SetProperty(mojom::PropertyType::kVisible, false);
-  AdvanceClock(kTestMaxAudioSlientTimeout);
-  frame_cu->SetProperty(mojom::PropertyType::kAudible, true);
-  // The tab becomes visible and then invisible again, thus metrics recorded.
-  histogram_tester_.ExpectTotalCount(kTabFromBackgroundedToFirstAudioStartsUMA,
-                                     2);
 }
 
-TEST_F(MetricsCollectorTest,
-       FromBackgroundedToFirstAudioStartsUMA5MinutesTimeout) {
+TEST_F(MetricsCollectorTest, ReportMetricsOneTimeOnlyPerBackgrounded) {
   CoordinationUnitID tab_cu_id(CoordinationUnitType::kWebContents,
                                std::string());
   CoordinationUnitID frame_cu_id(CoordinationUnitType::kFrame, std::string());
@@ -108,17 +85,30 @@
   web_contents_cu->AddChild(frame_cu->id());
 
   web_contents_cu->SetProperty(mojom::PropertyType::kVisible, false);
-  web_contents_cu->SendEvent(mojom::Event::kNavigationCommitted);
-  frame_cu->SetProperty(mojom::PropertyType::kAudible, true);
-  // The tab is within 5 minutes after main frame navigation was committed, thus
-  // no metrics recorded.
-  histogram_tester_.ExpectTotalCount(kTabFromBackgroundedToFirstAudioStartsUMA,
-                                     0);
+
   frame_cu->SetProperty(mojom::PropertyType::kAudible, false);
-  AdvanceClock(kTestMetricsReportDelayTimeout);
+  AdvanceClock(base::TimeDelta::FromSeconds(61));
   frame_cu->SetProperty(mojom::PropertyType::kAudible, true);
+  // The tab was not recently audible and it is backgrounded, thus metrics
+  // recorded.
   histogram_tester_.ExpectTotalCount(kTabFromBackgroundedToFirstAudioStartsUMA,
                                      1);
+
+  frame_cu->SetProperty(mojom::PropertyType::kAudible, false);
+  AdvanceClock(base::TimeDelta::FromSeconds(61));
+  frame_cu->SetProperty(mojom::PropertyType::kAudible, true);
+  // Only record the metrics once.
+  histogram_tester_.ExpectTotalCount(kTabFromBackgroundedToFirstAudioStartsUMA,
+                                     1);
+
+  web_contents_cu->SetProperty(mojom::PropertyType::kVisible, true);
+  web_contents_cu->SetProperty(mojom::PropertyType::kVisible, false);
+  frame_cu->SetProperty(mojom::PropertyType::kAudible, false);
+  AdvanceClock(base::TimeDelta::FromSeconds(61));
+  frame_cu->SetProperty(mojom::PropertyType::kAudible, true);
+  // The tab becomes visible and then invisible again, thus metrics recorded.
+  histogram_tester_.ExpectTotalCount(kTabFromBackgroundedToFirstAudioStartsUMA,
+                                     2);
 }
 
 TEST_F(MetricsCollectorTest, FromBackgroundedToFirstTitleUpdatedUMA) {
@@ -128,9 +118,6 @@
   auto web_contents_cu = CreateCoordinationUnit(tab_cu_id);
   coordination_unit_manager().OnCoordinationUnitCreated(web_contents_cu.get());
 
-  web_contents_cu->SendEvent(mojom::Event::kNavigationCommitted);
-  AdvanceClock(kTestMetricsReportDelayTimeout);
-
   web_contents_cu->SetProperty(mojom::PropertyType::kVisible, true);
   web_contents_cu->SendEvent(mojom::Event::kTitleUpdated);
   // The tab is not backgrounded, thus no metrics recorded.
@@ -156,27 +143,6 @@
                                      2);
 }
 
-TEST_F(MetricsCollectorTest,
-       FromBackgroundedToFirstTitleUpdatedUMA5MinutesTimeout) {
-  CoordinationUnitID tab_cu_id(CoordinationUnitType::kWebContents,
-                               std::string());
-
-  auto web_contents_cu = CreateCoordinationUnit(tab_cu_id);
-  coordination_unit_manager().OnCoordinationUnitCreated(web_contents_cu.get());
-
-  web_contents_cu->SendEvent(mojom::Event::kNavigationCommitted);
-  web_contents_cu->SetProperty(mojom::PropertyType::kVisible, false);
-  web_contents_cu->SendEvent(mojom::Event::kTitleUpdated);
-  // The tab is within 5 minutes after main frame navigation was committed, thus
-  // no metrics recorded.
-  histogram_tester_.ExpectTotalCount(kTabFromBackgroundedToFirstTitleUpdatedUMA,
-                                     0);
-  AdvanceClock(kTestMetricsReportDelayTimeout);
-  web_contents_cu->SendEvent(mojom::Event::kTitleUpdated);
-  histogram_tester_.ExpectTotalCount(kTabFromBackgroundedToFirstTitleUpdatedUMA,
-                                     1);
-}
-
 TEST_F(MetricsCollectorTest, FromBackgroundedToFirstAlertFiredUMA) {
   CoordinationUnitID tab_cu_id(CoordinationUnitType::kWebContents,
                                std::string());
@@ -188,9 +154,6 @@
   coordination_unit_manager().OnCoordinationUnitCreated(frame_cu.get());
   web_contents_cu->AddChild(frame_cu->id());
 
-  web_contents_cu->SendEvent(mojom::Event::kNavigationCommitted);
-  AdvanceClock(kTestMetricsReportDelayTimeout);
-
   web_contents_cu->SetProperty(mojom::PropertyType::kVisible, true);
   frame_cu->SendEvent(mojom::Event::kAlertFired);
   // The tab is not backgrounded, thus no metrics recorded.
@@ -217,31 +180,6 @@
 }
 
 TEST_F(MetricsCollectorTest,
-       FromBackgroundedToFirstAlertFiredUMA5MinutesTimeout) {
-  CoordinationUnitID tab_cu_id(CoordinationUnitType::kWebContents,
-                               std::string());
-  CoordinationUnitID frame_cu_id(CoordinationUnitType::kFrame, std::string());
-
-  auto web_contents_cu = CreateCoordinationUnit(tab_cu_id);
-  auto frame_cu = CreateCoordinationUnit(frame_cu_id);
-  coordination_unit_manager().OnCoordinationUnitCreated(web_contents_cu.get());
-  coordination_unit_manager().OnCoordinationUnitCreated(frame_cu.get());
-  web_contents_cu->AddChild(frame_cu->id());
-
-  web_contents_cu->SendEvent(mojom::Event::kNavigationCommitted);
-  web_contents_cu->SetProperty(mojom::PropertyType::kVisible, false);
-  frame_cu->SendEvent(mojom::Event::kAlertFired);
-  // The tab is within 5 minutes after main frame navigation was committed, thus
-  // no metrics recorded.
-  histogram_tester_.ExpectTotalCount(kTabFromBackgroundedToFirstAlertFiredUMA,
-                                     0);
-  AdvanceClock(kTestMetricsReportDelayTimeout);
-  frame_cu->SendEvent(mojom::Event::kAlertFired);
-  histogram_tester_.ExpectTotalCount(kTabFromBackgroundedToFirstAlertFiredUMA,
-                                     1);
-}
-
-TEST_F(MetricsCollectorTest,
        FromBackgroundedToFirstNonPersistentNotificationCreatedUMA) {
   CoordinationUnitID tab_cu_id(CoordinationUnitType::kWebContents,
                                std::string());
@@ -253,9 +191,6 @@
   coordination_unit_manager().OnCoordinationUnitCreated(frame_cu.get());
   web_contents_cu->AddChild(frame_cu->id());
 
-  web_contents_cu->SendEvent(mojom::Event::kNavigationCommitted);
-  AdvanceClock(kTestMetricsReportDelayTimeout);
-
   web_contents_cu->SetProperty(mojom::PropertyType::kVisible, true);
   frame_cu->SendEvent(mojom::Event::kNonPersistentNotificationCreated);
   // The tab is not backgrounded, thus no metrics recorded.
@@ -281,32 +216,6 @@
       kTabFromBackgroundedToFirstNonPersistentNotificationCreatedUMA, 2);
 }
 
-TEST_F(
-    MetricsCollectorTest,
-    FromBackgroundedToFirstNonPersistentNotificationCreatedUMA5MinutesTimeout) {
-  CoordinationUnitID tab_cu_id(CoordinationUnitType::kWebContents,
-                               std::string());
-  CoordinationUnitID frame_cu_id(CoordinationUnitType::kFrame, std::string());
-
-  auto web_contents_cu = CreateCoordinationUnit(tab_cu_id);
-  auto frame_cu = CreateCoordinationUnit(frame_cu_id);
-  coordination_unit_manager().OnCoordinationUnitCreated(web_contents_cu.get());
-  coordination_unit_manager().OnCoordinationUnitCreated(frame_cu.get());
-  web_contents_cu->AddChild(frame_cu->id());
-
-  web_contents_cu->SendEvent(mojom::Event::kNavigationCommitted);
-  web_contents_cu->SetProperty(mojom::PropertyType::kVisible, false);
-  frame_cu->SendEvent(mojom::Event::kNonPersistentNotificationCreated);
-  // The tab is within 5 minutes after main frame navigation was committed, thus
-  // no metrics recorded.
-  histogram_tester_.ExpectTotalCount(
-      kTabFromBackgroundedToFirstNonPersistentNotificationCreatedUMA, 0);
-  AdvanceClock(kTestMetricsReportDelayTimeout);
-  frame_cu->SendEvent(mojom::Event::kNonPersistentNotificationCreated);
-  histogram_tester_.ExpectTotalCount(
-      kTabFromBackgroundedToFirstNonPersistentNotificationCreatedUMA, 1);
-}
-
 TEST_F(MetricsCollectorTest, FromBackgroundedToFirstFaviconUpdatedUMA) {
   CoordinationUnitID tab_cu_id(CoordinationUnitType::kWebContents,
                                std::string());
@@ -314,9 +223,6 @@
   auto web_contents_cu = CreateCoordinationUnit(tab_cu_id);
   coordination_unit_manager().OnCoordinationUnitCreated(web_contents_cu.get());
 
-  web_contents_cu->SendEvent(mojom::Event::kNavigationCommitted);
-  AdvanceClock(kTestMetricsReportDelayTimeout);
-
   web_contents_cu->SetProperty(mojom::PropertyType::kVisible, true);
   web_contents_cu->SendEvent(mojom::Event::kFaviconUpdated);
   // The tab is not backgrounded, thus no metrics recorded.
@@ -342,25 +248,4 @@
       kTabFromBackgroundedToFirstFaviconUpdatedUMA, 2);
 }
 
-TEST_F(MetricsCollectorTest,
-       FromBackgroundedToFirstFaviconUpdatedUMA5MinutesTimeout) {
-  CoordinationUnitID tab_cu_id(CoordinationUnitType::kWebContents,
-                               std::string());
-
-  auto web_contents_cu = CreateCoordinationUnit(tab_cu_id);
-  coordination_unit_manager().OnCoordinationUnitCreated(web_contents_cu.get());
-
-  web_contents_cu->SendEvent(mojom::Event::kNavigationCommitted);
-  web_contents_cu->SetProperty(mojom::PropertyType::kVisible, false);
-  web_contents_cu->SendEvent(mojom::Event::kFaviconUpdated);
-  // The tab is within 5 minutes after main frame navigation was committed, thus
-  // no metrics recorded.
-  histogram_tester_.ExpectTotalCount(
-      kTabFromBackgroundedToFirstFaviconUpdatedUMA, 0);
-  AdvanceClock(kTestMetricsReportDelayTimeout);
-  web_contents_cu->SendEvent(mojom::Event::kFaviconUpdated);
-  histogram_tester_.ExpectTotalCount(
-      kTabFromBackgroundedToFirstFaviconUpdatedUMA, 1);
-}
-
 }  // namespace resource_coordinator
diff --git a/services/resource_coordinator/public/interfaces/signals.mojom b/services/resource_coordinator/public/interfaces/signals.mojom
index bf8aec8..295d4b6 100644
--- a/services/resource_coordinator/public/interfaces/signals.mojom
+++ b/services/resource_coordinator/public/interfaces/signals.mojom
@@ -8,8 +8,6 @@
   kTestEvent,
   kAlertFired,
   kFaviconUpdated,
-  // This event signal is received when main frame navigation is committed.
-  kNavigationCommitted,
   // Only care about non-persistent notifications, notifications launched from
   // ServiceWorker are persistent and compatible with LifeCycle.
   kNonPersistentNotificationCreated,
diff --git a/testing/buildbot/filters/mojo.fyi.network_content_browsertests.filter b/testing/buildbot/filters/mojo.fyi.network_content_browsertests.filter
index 096a7c2..68861a2 100644
--- a/testing/buildbot/filters/mojo.fyi.network_content_browsertests.filter
+++ b/testing/buildbot/filters/mojo.fyi.network_content_browsertests.filter
@@ -133,6 +133,10 @@
 -WebContentsImplBrowserTest.UserAgentOverride
 -WorkerFetchTest.*
 
+# crbug.com/760581
+-ResourceFetcherTests.ResourceFetcherTimeout
+-ResourceFetcherTests.ResourceFetcherDeletedInCallback
+
 # content/network/url_loader_impl.cc should handle failure in
 # URLLoaderImpl::OnResponseBodyStreamRead(). Note this is flaky, so it will pass
 # sometimes.
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index d7b522d4..ba4d78b 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -3605,9 +3605,11 @@
 crbug.com/757955 [ Win7 Debug ] storage/indexeddb/mozilla/cursors.html [ Pass Timeout ]
 crbug.com/757955 [ Win7 Debug ] storage/indexeddb/objectstore-cursor.html [ Pass Timeout ]
 crbug.com/757955 [ Win7 Debug ] http/tests/devtools/tracing/timeline-paint/layer-tree.html [ Pass Timeout ]
-crbug.com/667560 [ Win7 Debug ] virtual/mojo-loading/http/tests/devtools/tracing/timeline-paint/layer-tree.html [ Pass Timeout ]
 crbug.com/757955 [ Win7 Debug ] virtual/threaded/transitions/transition-end-event-transform.html [ Pass Failure ]
 
+# Tests failing on WebKit Win7 (dbg), disable for now
+crbug.com/760546 [ Win7 Debug ] virtual/mojo-loading/http/tests/devtools/tracing/timeline-paint/layer-tree.html [ Skip ]
+
 # Tests flakely timing out on WebKit Linux Trusty dbg builder
 crbug.com/758109 [ Linux Debug ] fast/workers/worker-multi-startup.html [ Pass Timeout ]
 
diff --git a/third_party/WebKit/Source/core/dom/TaskRunnerHelper.cpp b/third_party/WebKit/Source/core/dom/TaskRunnerHelper.cpp
index bf4fc7b..d891ac58 100644
--- a/third_party/WebKit/Source/core/dom/TaskRunnerHelper.cpp
+++ b/third_party/WebKit/Source/core/dom/TaskRunnerHelper.cpp
@@ -21,7 +21,7 @@
   // TODO(haraken): Optimize the mapping from TaskTypes to task runners.
   switch (type) {
     case TaskType::kTimer:
-      return frame ? frame->FrameScheduler()->TimerTaskRunner()
+      return frame ? frame->FrameScheduler()->ThrottleableTaskRunner()
                    : Platform::Current()->CurrentThread()->GetWebTaskRunner();
     case TaskType::kUnspecedLoading:
     case TaskType::kNetworking:
@@ -36,8 +36,6 @@
     // or provide a mechanism that web pages can opt-out it if throttling is not
     // desirable.
     case TaskType::kDatabaseAccess:
-      return frame ? frame->FrameScheduler()->SuspendableTaskRunner()
-                   : Platform::Current()->CurrentThread()->GetWebTaskRunner();
     case TaskType::kDOMManipulation:
     case TaskType::kHistoryTraversal:
     case TaskType::kEmbed:
@@ -54,18 +52,18 @@
     case TaskType::kWebGL:
     case TaskType::kUnspecedTimer:
     case TaskType::kMiscPlatformAPI:
-      // TODO(altimin): Move all these tasks to suspendable or unthrottled
-      // task runner.
-      return frame
-                 ? frame->FrameScheduler()->UnthrottledButBlockableTaskRunner()
-                 : Platform::Current()->CurrentThread()->GetWebTaskRunner();
-    // PostedMessage can be used for navigation, so we shouldn't block it
+      // TODO(altimin): Move appropriate tasks to throttleable task queue.
+      return frame ? frame->FrameScheduler()->DeferrableTaskRunner()
+                   : Platform::Current()->CurrentThread()->GetWebTaskRunner();
+    // PostedMessage can be used for navigation, so we shouldn't defer it
     // when expecting a user gesture.
     case TaskType::kPostedMessage:
     // UserInteraction tasks should be run even when expecting a user gesture.
     case TaskType::kUserInteraction:
+      return frame ? frame->FrameScheduler()->PausableTaskRunner()
+                   : Platform::Current()->CurrentThread()->GetWebTaskRunner();
     case TaskType::kUnthrottled:
-      return frame ? frame->FrameScheduler()->UnthrottledTaskRunner()
+      return frame ? frame->FrameScheduler()->UnpausableTaskRunner()
                    : Platform::Current()->CurrentThread()->GetWebTaskRunner();
   }
   NOTREACHED();
diff --git a/third_party/WebKit/Source/core/frame/WebLocalFrameImpl.cpp b/third_party/WebKit/Source/core/frame/WebLocalFrameImpl.cpp
index 1616d30..cb39dc87 100644
--- a/third_party/WebKit/Source/core/frame/WebLocalFrameImpl.cpp
+++ b/third_party/WebKit/Source/core/frame/WebLocalFrameImpl.cpp
@@ -2431,7 +2431,7 @@
 SingleThreadTaskRunner* WebLocalFrameImpl::TimerTaskRunner() {
   return GetFrame()
       ->FrameScheduler()
-      ->TimerTaskRunner()
+      ->ThrottleableTaskRunner()
       ->ToSingleThreadTaskRunner();
 }
 
@@ -2445,7 +2445,7 @@
 SingleThreadTaskRunner* WebLocalFrameImpl::UnthrottledTaskRunner() {
   return GetFrame()
       ->FrameScheduler()
-      ->UnthrottledTaskRunner()
+      ->PausableTaskRunner()
       ->ToSingleThreadTaskRunner();
 }
 
diff --git a/third_party/WebKit/Source/core/loader/EmptyClients.cpp b/third_party/WebKit/Source/core/loader/EmptyClients.cpp
index 4f034592..ad449af 100644
--- a/third_party/WebKit/Source/core/loader/EmptyClients.cpp
+++ b/third_party/WebKit/Source/core/loader/EmptyClients.cpp
@@ -76,10 +76,10 @@
   void SetFrameVisible(bool) override {}
   RefPtr<WebTaskRunner> LoadingTaskRunner() override;
   RefPtr<WebTaskRunner> LoadingControlTaskRunner() override;
-  RefPtr<WebTaskRunner> TimerTaskRunner() override;
-  RefPtr<WebTaskRunner> UnthrottledTaskRunner() override;
-  RefPtr<WebTaskRunner> SuspendableTaskRunner() override;
-  RefPtr<WebTaskRunner> UnthrottledButBlockableTaskRunner() override;
+  RefPtr<WebTaskRunner> ThrottleableTaskRunner() override;
+  RefPtr<WebTaskRunner> DeferrableTaskRunner() override;
+  RefPtr<WebTaskRunner> PausableTaskRunner() override;
+  RefPtr<WebTaskRunner> UnpausableTaskRunner() override;
 };
 
 RefPtr<WebTaskRunner> EmptyFrameScheduler::LoadingTaskRunner() {
@@ -90,19 +90,19 @@
   return Platform::Current()->MainThread()->GetWebTaskRunner();
 }
 
-RefPtr<WebTaskRunner> EmptyFrameScheduler::TimerTaskRunner() {
+RefPtr<WebTaskRunner> EmptyFrameScheduler::ThrottleableTaskRunner() {
   return Platform::Current()->MainThread()->GetWebTaskRunner();
 }
 
-RefPtr<WebTaskRunner> EmptyFrameScheduler::UnthrottledTaskRunner() {
+RefPtr<WebTaskRunner> EmptyFrameScheduler::DeferrableTaskRunner() {
   return Platform::Current()->MainThread()->GetWebTaskRunner();
 }
 
-RefPtr<WebTaskRunner> EmptyFrameScheduler::SuspendableTaskRunner() {
+RefPtr<WebTaskRunner> EmptyFrameScheduler::PausableTaskRunner() {
   return Platform::Current()->MainThread()->GetWebTaskRunner();
 }
 
-RefPtr<WebTaskRunner> EmptyFrameScheduler::UnthrottledButBlockableTaskRunner() {
+RefPtr<WebTaskRunner> EmptyFrameScheduler::UnpausableTaskRunner() {
   return Platform::Current()->MainThread()->GetWebTaskRunner();
 }
 
diff --git a/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.h b/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.h
index 66a83ed2..72f7d7d2 100644
--- a/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.h
+++ b/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.h
@@ -122,7 +122,13 @@
       bool is_left_side_vertical_scrollbar);
 
   void WillDestroyScrollableArea(ScrollableArea*);
-  // Returns true if the coordinator handled this change.
+  // Updates the compositor layers and returns true if the scrolling coordinator
+  // handled this change.
+  // TODO(pdr): Factor the container bounds change out of this function. The
+  // compositor tracks scroll container bounds on the scroll layer whereas
+  // blink uses a separate layer. To ensure the compositor scroll layer has the
+  // updated scroll container bounds, this needs to be called when the scrolling
+  // contents layer is resized.
   bool ScrollableAreaScrollLayerDidChange(ScrollableArea*);
   void ScrollableAreaScrollbarLayerDidChange(ScrollableArea*,
                                              ScrollbarOrientation);
diff --git a/third_party/WebKit/Source/core/paint/compositing/CompositedLayerMapping.cpp b/third_party/WebKit/Source/core/paint/compositing/CompositedLayerMapping.cpp
index b20ee3c..28e45ab 100644
--- a/third_party/WebKit/Source/core/paint/compositing/CompositedLayerMapping.cpp
+++ b/third_party/WebKit/Source/core/paint/compositing/CompositedLayerMapping.cpp
@@ -1541,7 +1541,11 @@
   }
   scrolling_layer_->SetPosition(
       FloatPoint(overflow_clip_rect.Location() + local_content_offset));
+
+  FloatSize old_scroll_container_size = scrolling_layer_->Size();
   scrolling_layer_->SetSize(FloatSize(overflow_clip_rect.Size()));
+  bool scroll_container_size_changed =
+      old_scroll_container_size != scrolling_layer_->Size();
 
   IntSize old_scrolling_layer_offset =
       scrolling_layer_->OffsetFromLayoutObject();
@@ -1571,7 +1575,8 @@
   // The scroll offset change is compared using floating point so that
   // fractional scroll offset change can be propagated to compositor.
   if (scrolling_contents_offset != scrolling_contents_offset_ ||
-      scroll_size != scrolling_contents_layer_->Size()) {
+      scroll_size != scrolling_contents_layer_->Size() ||
+      scroll_container_size_changed) {
     bool coordinator_handles_offset = false;
     auto scrolling_coordinator = owning_layer_.GetScrollingCoordinator();
     auto* scrollable_area = owning_layer_.GetScrollableArea();
diff --git a/third_party/WebKit/Source/core/paint/compositing/CompositedLayerMappingTest.cpp b/third_party/WebKit/Source/core/paint/compositing/CompositedLayerMappingTest.cpp
index 1ed52f4..6df8ae1 100644
--- a/third_party/WebKit/Source/core/paint/compositing/CompositedLayerMappingTest.cpp
+++ b/third_party/WebKit/Source/core/paint/compositing/CompositedLayerMappingTest.cpp
@@ -2278,4 +2278,49 @@
                   .is_sticky);
 }
 
+TEST_P(CompositedLayerMappingTest, ScrollingContainerBoundsChange) {
+  GetDocument().GetFrame()->GetSettings()->SetPreferCompositingToLCDTextEnabled(
+      true);
+  SetBodyInnerHTML(
+      "<style>"
+      "  ::-webkit-scrollbar { width: 0; height: 0; }"
+      "  body { margin: 0; }"
+      "  #scroller { overflow-y: scroll; }"
+      "  #content {"
+      "    width: 100px;"
+      "    height: 100px;"
+      "    margin-top: 50px;"
+      "    margin-bottom: -50px;"
+      "  }"
+      "</style>"
+      "<div id='scroller'>"
+      "  <div id='content'></div>"
+      "</div");
+
+  GetDocument().View()->UpdateAllLifecyclePhases();
+  Element* scrollerElement = GetDocument().getElementById("scroller");
+  LayoutBoxModelObject* scroller =
+      ToLayoutBoxModelObject(GetLayoutObjectByElementId("scroller"));
+  PaintLayerScrollableArea* scrollable_area = scroller->GetScrollableArea();
+
+  WebLayer* scrolling_layer =
+      scrollable_area->LayerForScrolling()->PlatformLayer();
+  EXPECT_EQ(0, scrolling_layer->ScrollPosition().y);
+  EXPECT_EQ(150, scrolling_layer->Bounds().height);
+  EXPECT_EQ(100, scrolling_layer->ScrollContainerBoundsForTesting().height);
+
+  scrollerElement->setScrollTop(300);
+  scrollerElement->setAttribute(HTMLNames::styleAttr, "max-height: 25px;");
+  GetDocument().View()->UpdateAllLifecyclePhases();
+  EXPECT_EQ(50, scrolling_layer->ScrollPosition().y);
+  EXPECT_EQ(150, scrolling_layer->Bounds().height);
+  EXPECT_EQ(25, scrolling_layer->ScrollContainerBoundsForTesting().height);
+
+  scrollerElement->setAttribute(HTMLNames::styleAttr, "max-height: 300px;");
+  GetDocument().View()->UpdateAllLifecyclePhases();
+  EXPECT_EQ(50, scrolling_layer->ScrollPosition().y);
+  EXPECT_EQ(150, scrolling_layer->Bounds().height);
+  EXPECT_EQ(100, scrolling_layer->ScrollContainerBoundsForTesting().height);
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/modules/fetch/FetchHeaderList.h b/third_party/WebKit/Source/modules/fetch/FetchHeaderList.h
index afec7f70..9d1e41b 100644
--- a/third_party/WebKit/Source/modules/fetch/FetchHeaderList.h
+++ b/third_party/WebKit/Source/modules/fetch/FetchHeaderList.h
@@ -14,8 +14,6 @@
 
 namespace blink {
 
-class Header;
-
 // http://fetch.spec.whatwg.org/#terminology-headers
 class MODULES_EXPORT FetchHeaderList final
     : public GarbageCollectedFinalized<FetchHeaderList> {
diff --git a/third_party/WebKit/Source/modules/webaudio/BaseAudioContextTest.cpp b/third_party/WebKit/Source/modules/webaudio/BaseAudioContextTest.cpp
index 4ed07b29..1394a47e 100644
--- a/third_party/WebKit/Source/modules/webaudio/BaseAudioContextTest.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/BaseAudioContextTest.cpp
@@ -96,7 +96,7 @@
 }  // anonymous namespace
 
 #if defined(OS_ANDROID)
-// Often times out with Android ASAN: https://crbug.com/758934.
+// Often times out on Android: https://crbug.com/752511.
 #define MAYBE_TEST_P(test_case_name, test_name) \
   TEST_P(test_case_name, DISABLED_##test_name)
 #else
diff --git a/third_party/WebKit/Source/platform/BUILD.gn b/third_party/WebKit/Source/platform/BUILD.gn
index 2a96530..5a9dc70 100644
--- a/third_party/WebKit/Source/platform/BUILD.gn
+++ b/third_party/WebKit/Source/platform/BUILD.gn
@@ -946,8 +946,6 @@
     "graphics/ImageOrientation.h",
     "graphics/ImagePattern.cpp",
     "graphics/ImagePattern.h",
-    "graphics/ImageSource.cpp",
-    "graphics/ImageSource.h",
     "graphics/InterceptingCanvas.cpp",
     "graphics/InterceptingCanvas.h",
     "graphics/InterpolationSpace.cpp",
diff --git a/third_party/WebKit/Source/platform/TimerTest.cpp b/third_party/WebKit/Source/platform/TimerTest.cpp
index 4fc596d..e024dac8 100644
--- a/third_party/WebKit/Source/platform/TimerTest.cpp
+++ b/third_party/WebKit/Source/platform/TimerTest.cpp
@@ -539,7 +539,7 @@
 TEST_F(TimerTest, UserSuppliedWebTaskRunner) {
   scoped_refptr<scheduler::TaskQueue> task_runner(
       platform_->GetRendererScheduler()->NewTimerTaskQueue(
-          scheduler::MainThreadTaskQueue::QueueType::FRAME_TIMER));
+          scheduler::MainThreadTaskQueue::QueueType::FRAME_THROTTLEABLE));
   RefPtr<scheduler::WebTaskRunnerImpl> web_task_runner =
       scheduler::WebTaskRunnerImpl::Create(task_runner);
   TimerForTest<TimerTest> timer(web_task_runner, this,
@@ -627,7 +627,7 @@
 
   scoped_refptr<scheduler::TaskQueue> task_runner1(
       platform_->GetRendererScheduler()->NewTimerTaskQueue(
-          scheduler::MainThreadTaskQueue::QueueType::FRAME_TIMER));
+          scheduler::MainThreadTaskQueue::QueueType::FRAME_THROTTLEABLE));
   RefPtr<scheduler::WebTaskRunnerImpl> web_task_runner1 =
       scheduler::WebTaskRunnerImpl::Create(task_runner1);
   TaskObserver task_observer1(web_task_runner1, &run_order);
@@ -635,7 +635,7 @@
 
   scoped_refptr<scheduler::TaskQueue> task_runner2(
       platform_->GetRendererScheduler()->NewTimerTaskQueue(
-          scheduler::MainThreadTaskQueue::QueueType::FRAME_TIMER));
+          scheduler::MainThreadTaskQueue::QueueType::FRAME_THROTTLEABLE));
   RefPtr<scheduler::WebTaskRunnerImpl> web_task_runner2 =
       scheduler::WebTaskRunnerImpl::Create(task_runner2);
   TaskObserver task_observer2(web_task_runner2, &run_order);
@@ -667,7 +667,7 @@
 
   scoped_refptr<scheduler::TaskQueue> task_runner1(
       platform_->GetRendererScheduler()->NewTimerTaskQueue(
-          scheduler::MainThreadTaskQueue::QueueType::FRAME_TIMER));
+          scheduler::MainThreadTaskQueue::QueueType::FRAME_THROTTLEABLE));
   RefPtr<scheduler::WebTaskRunnerImpl> web_task_runner1 =
       scheduler::WebTaskRunnerImpl::Create(task_runner1);
   TaskObserver task_observer1(web_task_runner1, &run_order);
@@ -675,7 +675,7 @@
 
   scoped_refptr<scheduler::TaskQueue> task_runner2(
       platform_->GetRendererScheduler()->NewTimerTaskQueue(
-          scheduler::MainThreadTaskQueue::QueueType::FRAME_TIMER));
+          scheduler::MainThreadTaskQueue::QueueType::FRAME_THROTTLEABLE));
   RefPtr<scheduler::WebTaskRunnerImpl> web_task_runner2 =
       scheduler::WebTaskRunnerImpl::Create(task_runner2);
   TaskObserver task_observer2(web_task_runner2, &run_order);
@@ -709,13 +709,13 @@
 TEST_F(TimerTest, MoveToNewTaskRunnerWithoutTasks) {
   scoped_refptr<scheduler::TaskQueue> task_runner1(
       platform_->GetRendererScheduler()->NewTimerTaskQueue(
-          scheduler::MainThreadTaskQueue::QueueType::FRAME_TIMER));
+          scheduler::MainThreadTaskQueue::QueueType::FRAME_THROTTLEABLE));
   RefPtr<scheduler::WebTaskRunnerImpl> web_task_runner1 =
       scheduler::WebTaskRunnerImpl::Create(task_runner1);
 
   scoped_refptr<scheduler::TaskQueue> task_runner2(
       platform_->GetRendererScheduler()->NewTimerTaskQueue(
-          scheduler::MainThreadTaskQueue::QueueType::FRAME_TIMER));
+          scheduler::MainThreadTaskQueue::QueueType::FRAME_THROTTLEABLE));
   RefPtr<scheduler::WebTaskRunnerImpl> web_task_runner2 =
       scheduler::WebTaskRunnerImpl::Create(task_runner2);
 
diff --git a/third_party/WebKit/Source/platform/WebFrameScheduler.h b/third_party/WebKit/Source/platform/WebFrameScheduler.h
index a08537f4..237a9dc 100644
--- a/third_party/WebKit/Source/platform/WebFrameScheduler.h
+++ b/third_party/WebKit/Source/platform/WebFrameScheduler.h
@@ -69,21 +69,53 @@
   virtual void SetCrossOrigin(bool) {}
 
   // The tasks runners below are listed in increasing QoS order.
-  // - timer task queue. Designed for custom user-provided javascript tasks.
-  //   Lowest guarantees. Can be suspended, blocked during user gesture or
-  //   throttled when backgrounded.
-  // - loading task queue. Can be suspended or blocked during user gesture.
-  //   Throttling might be considered in the future.
-  // - suspendable task queue. Can be suspended and blocked during user gesture,
-  //   can't be throttled.
-  // - unthrottled-but-blockable task queue. Can't be throttled, can't
-  //   be suspended but can be blocked during user gesture.
-  //   NOTE: existence of this queue is a temporary fix for scroll latency
-  //   regression. All tasks should be moved from this queue to suspendable
-  //   or unthrottled queues and it should be deleted.
-  // - unthrottled task queue. Highest guarantees. Can't be throttled,
-  //   suspended or blocked. Should be used only when necessary after
-  //   consulting scheduler-dev@.
+  // - throttleable task queue. Designed for custom user-provided javascript
+  //   tasks. Lowest guarantees. Can be paused, blocked during user gesture,
+  //   throttled when backgrounded or stopped completely after some time in
+  //   background.
+  // - deferrable task queue. These tasks can be deferred for a small period
+  //   (several seconds) when high-priority work is anticipated. These tasks
+  //   can be paused.
+  // - pausable task queue. Default queue for high-priority javascript tasks.
+  //   They can be paused according to the spec during javascript alert
+  //   dialogs, printing windows and devtools debugging. Otherwise scheduler
+  //   does not tamper with their execution.
+  // - unpausable task queue. Should be used for control tasks which should
+  //   run when the context is paused. Usage should be extremely rare.
+  //   Please consult scheduler-dev@ before using it. Running javascript
+  //   on it is strictly verboten and can lead to hard-to-diagnose errors.
+  //
+  //
+  // These queues below are separate due to special handling for their
+  // priorities.
+  // - loading task queue. Similar to deferrable task queue. Throttling might
+  //   be considered in the future.
+  // - loading control task queue. Loading task queue with increased priority
+  //   to run small loading tasks which schedule other loading tasks.
+
+  // Note: old-style timer task runner corresponds to throttleable task runner
+  // and unthrottled task runner corresponds to pausable task runner.
+
+  // Returns a WebTaskRunner for throtteable tasks, e.g. javascript timers.
+  // WebFrameScheduler owns the returned WebTaskRunner.
+  virtual RefPtr<WebTaskRunner> ThrottleableTaskRunner() = 0;
+
+  // Returns a WebTaskRunner for tasks which can be deferred for several
+  // seconds due to anticipated high-priority work like user gesture.
+  virtual RefPtr<WebTaskRunner> DeferrableTaskRunner() = 0;
+
+  // Returns a WebTaskRunner for high-priority javascript tasks. They run
+  // unrestricted in most cases except context pausing (e.g. alert dialog).
+  virtual RefPtr<WebTaskRunner> PausableTaskRunner() = 0;
+
+  // Returns a WebTaskRunner for tasks which should run during context pausing.
+  // The usage should be rare and limited to tasks controlling context pausing
+  // and unpausing.
+  virtual RefPtr<WebTaskRunner> UnpausableTaskRunner() = 0;
+
+  // Returns the WebTaskRunner for loading tasks.
+  // WebFrameScheduler owns the returned WebTaskRunner.
+  virtual RefPtr<WebTaskRunner> LoadingTaskRunner() = 0;
 
   // Return a WebTaskRunner for very short control messages between loading
   // tasks. Caution is needed when posting tasks to this WebTaskRunner because
@@ -91,36 +123,6 @@
   // WebFrameScheduler owns the returned WebTaskRunner.
   virtual RefPtr<WebTaskRunner> LoadingControlTaskRunner() = 0;
 
-  // Returns the WebTaskRunner for timer tasks.
-  // WebFrameScheduler owns the returned WebTaskRunner.
-  virtual RefPtr<WebTaskRunner> TimerTaskRunner() = 0;
-
-  // Returns the WebTaskRunner for loading tasks.
-  // WebFrameScheduler owns the returned WebTaskRunner.
-  virtual RefPtr<WebTaskRunner> LoadingTaskRunner() = 0;
-
-  // Returns the WebTaskRunner for tasks which shouldn't get throttled,
-  // but can be suspended.
-  // TODO(altimin): This is a transitional task runner. Unthrottled task runner
-  // would become suspendable in the nearest future and a new unsuspended
-  // task runner will be added.
-  virtual RefPtr<WebTaskRunner> SuspendableTaskRunner() = 0;
-
-  // Retuns the WebTaskRunner for tasks which should not be suspended or
-  // throttled, but should be blocked during user gesture.
-  // This is a temporary task runner needed for a fix for touch latency
-  // regression. All tasks from it should be moved to suspendable or
-  // unthrottled task runner.
-  virtual RefPtr<WebTaskRunner> UnthrottledButBlockableTaskRunner() = 0;
-
-  // Returns the WebTaskRunner for tasks which should never get throttled.
-  // This is generally used for executing internal browser tasks which should
-  // never be throttled. Ideally only tasks whose performance characteristics
-  // are known should be posted to this task runner; for example user
-  // JavaScript is discouraged. WebFrameScheduler owns the returned
-  // WebTaskRunner.
-  virtual RefPtr<WebTaskRunner> UnthrottledTaskRunner() = 0;
-
   // Returns the parent WebViewScheduler.
   virtual WebViewScheduler* GetWebViewScheduler() { return nullptr; }
 
diff --git a/third_party/WebKit/Source/platform/exported/WebImageGenerator.cpp b/third_party/WebKit/Source/platform/exported/WebImageGenerator.cpp
index 8954baea..de0c1eb6 100644
--- a/third_party/WebKit/Source/platform/exported/WebImageGenerator.cpp
+++ b/third_party/WebKit/Source/platform/exported/WebImageGenerator.cpp
@@ -30,13 +30,14 @@
 
 #include "public/platform/WebImageGenerator.h"
 
+#include <utility>
 #include "platform/graphics/DecodingImageGenerator.h"
 
 namespace blink {
 
-std::unique_ptr<SkImageGenerator> WebImageGenerator::Create(
+std::unique_ptr<SkImageGenerator> WebImageGenerator::CreateAsSkImageGenerator(
     sk_sp<SkData> data) {
-  return DecodingImageGenerator::Create(data.get());
+  return DecodingImageGenerator::CreateAsSkImageGenerator(std::move(data));
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/graphics/BitmapImage.cpp b/third_party/WebKit/Source/platform/graphics/BitmapImage.cpp
index 31e2194a..0144b30e 100644
--- a/third_party/WebKit/Source/platform/graphics/BitmapImage.cpp
+++ b/third_party/WebKit/Source/platform/graphics/BitmapImage.cpp
@@ -26,6 +26,7 @@
 
 #include "platform/graphics/BitmapImage.h"
 
+#include "platform/RuntimeEnabledFeatures.h"
 #include "platform/Timer.h"
 #include "platform/geometry/FloatRect.h"
 #include "platform/graphics/BitmapImageMetrics.h"
@@ -79,12 +80,13 @@
   cached_frame_ = PaintImage();
   for (size_t i = 0; i < frames_.size(); ++i)
     frames_[i].Clear(true);
-  source_.ClearCacheExceptFrame(kNotFound);
+  if (decoder_)
+    decoder_->ClearCacheExceptFrame(kNotFound);
   NotifyMemoryChanged();
 }
 
 PassRefPtr<SharedBuffer> BitmapImage::Data() {
-  return source_.Data();
+  return decoder_ ? decoder_->Data() : nullptr;
 }
 
 void BitmapImage::NotifyMemoryChanged() {
@@ -93,15 +95,19 @@
 }
 
 size_t BitmapImage::TotalFrameBytes() {
+  if (!decoder_)
+    return 0u;
+
   const size_t num_frames = FrameCount();
   size_t total_bytes = 0;
   for (size_t i = 0; i < num_frames; ++i)
-    total_bytes += source_.FrameBytesAtIndex(i);
+    total_bytes += decoder_->FrameBytesAtIndex(i);
   return total_bytes;
 }
 
 PaintImage BitmapImage::CreateAndCacheFrame(size_t index) {
-  sk_sp<PaintImageGenerator> generator = source_.CreateGeneratorAtIndex(index);
+  sk_sp<PaintImageGenerator> generator =
+      decoder_ ? decoder_->CreateGeneratorAtIndex(index) : nullptr;
   if (!generator)
     return PaintImage();
 
@@ -109,13 +115,13 @@
   if (frames_.size() < num_frames)
     frames_.Grow(num_frames);
 
-  frames_[index].orientation_ = source_.OrientationAtIndex(index);
+  frames_[index].orientation_ = decoder_->OrientationAtIndex(index);
   frames_[index].have_metadata_ = true;
-  frames_[index].is_complete_ = source_.FrameIsReceivedAtIndex(index);
+  frames_[index].is_complete_ = decoder_->FrameIsReceivedAtIndex(index);
   if (RepetitionCount(false) != kAnimationNone)
-    frames_[index].duration_ = source_.FrameDurationAtIndex(index);
-  frames_[index].has_alpha_ = source_.FrameHasAlphaAtIndex(index);
-  frames_[index].frame_bytes_ = source_.FrameBytesAtIndex(index);
+    frames_[index].duration_ = decoder_->FrameDurationAtIndex(index);
+  frames_[index].has_alpha_ = decoder_->FrameHasAlphaAtIndex(index);
+  frames_[index].frame_bytes_ = decoder_->FrameBytesAtIndex(index);
 
   PaintImageBuilder builder;
   InitPaintImageBuilder(builder);
@@ -164,11 +170,14 @@
 }
 
 void BitmapImage::UpdateSize() const {
-  if (!size_available_ || have_size_)
+  if (!size_available_ || have_size_ || !decoder_)
     return;
 
-  size_ = source_.size();
-  size_respecting_orientation_ = source_.size(kRespectImageOrientation);
+  size_ = decoder_->FrameSizeAtIndex(0);
+  if (decoder_->OrientationAtIndex(0).UsesWidthAsHeight())
+    size_respecting_orientation_ = size_.TransposedSize();
+  else
+    size_respecting_orientation_ = size_;
   have_size_ = true;
 }
 
@@ -183,7 +192,7 @@
 }
 
 bool BitmapImage::GetHotSpot(IntPoint& hot_spot) const {
-  return source_.GetHotSpot(hot_spot);
+  return decoder_ && decoder_->HotSpot(hot_spot);
 }
 
 Image::SizeAvailability BitmapImage::SetData(RefPtr<SharedBuffer> data,
@@ -195,12 +204,23 @@
   if (!length)
     return kSizeAvailable;
 
-  // If ImageSource::setData() fails, we know that this is a decode error.
-  // Report size available so that it gets registered as such in
-  // ImageResourceContent.
-  if (!source_.SetData(std::move(data), all_data_received))
-    return kSizeAvailable;
+  if (decoder_) {
+    decoder_->SetData(std::move(data), all_data_received);
+    return DataChanged(all_data_received);
+  }
 
+  ColorBehavior color_behavior =
+      RuntimeEnabledFeatures::ColorCorrectRenderingEnabled()
+          ? ColorBehavior::Tag()
+          : ColorBehavior::TransformToGlobalTarget();
+  bool has_enough_data = ImageDecoder::HasSufficientDataToSniffImageType(*data);
+  decoder_ = DeferredImageDecoder::Create(std::move(data), all_data_received,
+                                          ImageDecoder::kAlphaPremultiplied,
+                                          color_behavior);
+  // If we had enough data but couldn't create a decoder, it implies a decode
+  // failure.
+  if (has_enough_data && !decoder_)
+    return kSizeAvailable;
   return DataChanged(all_data_received);
 }
 
@@ -243,11 +263,11 @@
 }
 
 bool BitmapImage::HasColorProfile() const {
-  return source_.HasColorProfile();
+  return decoder_ && decoder_->HasEmbeddedColorSpace();
 }
 
 String BitmapImage::FilenameExtension() const {
-  return source_.FilenameExtension();
+  return decoder_ ? decoder_->FilenameExtension() : String();
 }
 
 void BitmapImage::Draw(
@@ -309,12 +329,9 @@
 
 size_t BitmapImage::FrameCount() {
   if (!have_frame_count_) {
-    frame_count_ = source_.FrameCount();
-    // If decoder is not initialized yet, m_source.frameCount() returns 0.
-    if (frame_count_)
-      have_frame_count_ = true;
+    frame_count_ = decoder_ ? decoder_->FrameCount() : 0;
+    have_frame_count_ = frame_count_ > 0;
   }
-
   return frame_count_;
 }
 
@@ -326,13 +343,13 @@
   if (size_available_)
     return true;
 
-  size_available_ = source_.IsSizeAvailable();
-
+  size_available_ = decoder_ && decoder_->IsSizeAvailable();
   if (size_available_ && HasVisibleImageSize(Size())) {
-    BitmapImageMetrics::CountDecodedImageType(source_.FilenameExtension());
-    if (source_.FilenameExtension() == "jpg")
+    BitmapImageMetrics::CountDecodedImageType(decoder_->FilenameExtension());
+    if (decoder_->FilenameExtension() == "jpg") {
       BitmapImageMetrics::CountImageOrientation(
-          source_.OrientationAtIndex(0).Orientation());
+          decoder_->OrientationAtIndex(0).Orientation());
+    }
   }
 
   return size_available_;
@@ -353,14 +370,16 @@
       frames_[index].is_complete_)
     return true;
 
-  return source_.FrameIsReceivedAtIndex(index);
+  return decoder_ && decoder_->FrameIsReceivedAtIndex(index);
 }
 
 float BitmapImage::FrameDurationAtIndex(size_t index) const {
   if (index < frames_.size() && frames_[index].have_metadata_)
     return frames_[index].duration_;
 
-  return source_.FrameDurationAtIndex(index);
+  if (!decoder_)
+    return 0.f;
+  return decoder_->FrameDurationAtIndex(index);
 }
 
 PaintImage BitmapImage::PaintImageForCurrentFrame() {
@@ -382,9 +401,9 @@
   if (frames_[index].have_metadata_ && !frames_[index].has_alpha_)
     return false;
 
-  // m_hasAlpha may change after m_haveMetadata is set to true, so always ask
-  // ImageSource for the value if the cached value is the default value.
-  bool has_alpha = source_.FrameHasAlphaAtIndex(index);
+  // has_alpha may change after have_metadata_ is set to true, so always ask
+  // |decoder_| for the value if the cached value is the default value.
+  bool has_alpha = !decoder_ || decoder_->FrameHasAlphaAtIndex(index);
 
   if (frames_[index].have_metadata_)
     frames_[index].has_alpha_ = has_alpha;
@@ -416,13 +435,13 @@
 }
 
 ImageOrientation BitmapImage::FrameOrientationAtIndex(size_t index) {
-  if (frames_.size() <= index)
+  if (!decoder_ || frames_.size() <= index)
     return kDefaultImageOrientation;
 
   if (frames_[index].have_metadata_)
     return frames_[index].orientation_;
 
-  return source_.OrientationAtIndex(index);
+  return decoder_->OrientationAtIndex(index);
 }
 
 int BitmapImage::RepetitionCount(bool image_known_to_be_complete) {
@@ -433,7 +452,7 @@
     // repetition count may not be accurate yet for GIFs; in this case the
     // decoder will default to cAnimationLoopOnce, and we'll try and read
     // the count again once the whole image is decoded.
-    repetition_count_ = source_.RepetitionCount();
+    repetition_count_ = decoder_ ? decoder_->RepetitionCount() : kAnimationNone;
     repetition_count_status_ =
         (image_known_to_be_complete || repetition_count_ == kAnimationNone)
             ? kCertain
@@ -562,7 +581,7 @@
   if (FrameCount() > 1)
     return true;
 
-  return source_.RepetitionCount() != kAnimationNone;
+  return decoder_ && decoder_->RepetitionCount() != kAnimationNone;
 }
 
 void BitmapImage::AdvanceTime(double delta_time_in_seconds) {
diff --git a/third_party/WebKit/Source/platform/graphics/BitmapImage.h b/third_party/WebKit/Source/platform/graphics/BitmapImage.h
index 09535d8..e7bbe39 100644
--- a/third_party/WebKit/Source/platform/graphics/BitmapImage.h
+++ b/third_party/WebKit/Source/platform/graphics/BitmapImage.h
@@ -32,11 +32,11 @@
 #include "platform/Timer.h"
 #include "platform/geometry/IntSize.h"
 #include "platform/graphics/Color.h"
+#include "platform/graphics/DeferredImageDecoder.h"
 #include "platform/graphics/FrameData.h"
 #include "platform/graphics/Image.h"
 #include "platform/graphics/ImageAnimationPolicy.h"
 #include "platform/graphics/ImageOrientation.h"
-#include "platform/graphics/ImageSource.h"
 #include "platform/image-decoders/ImageAnimation.h"
 #include "platform/wtf/Forward.h"
 #include "third_party/skia/include/core/SkRefCnt.h"
@@ -174,7 +174,7 @@
 
   void NotifyObserversOfAnimationAdvance(TimerBase*);
 
-  ImageSource source_;
+  std::unique_ptr<DeferredImageDecoder> decoder_;
   mutable IntSize size_;  // The size to use for the overall image (will just
                           // be the size of the first image).
   mutable IntSize size_respecting_orientation_;
@@ -201,7 +201,7 @@
                                 // final overall image size yet.
   bool size_available_ : 1;     // Whether we can obtain the size of the first
                                 // image frame from ImageIO yet.
-  mutable bool have_frame_count_ : 1;
+  bool have_frame_count_ : 1;
 
   RepetitionCountStatus repetition_count_status_;
   int repetition_count_;  // How many total animation loops we should do.  This
diff --git a/third_party/WebKit/Source/platform/graphics/DecodingImageGenerator.cpp b/third_party/WebKit/Source/platform/graphics/DecodingImageGenerator.cpp
index c81218f..4d32c67 100644
--- a/third_party/WebKit/Source/platform/graphics/DecodingImageGenerator.cpp
+++ b/third_party/WebKit/Source/platform/graphics/DecodingImageGenerator.cpp
@@ -36,6 +36,48 @@
 
 namespace blink {
 
+// static
+std::unique_ptr<SkImageGenerator>
+DecodingImageGenerator::CreateAsSkImageGenerator(sk_sp<SkData> data) {
+  RefPtr<SegmentReader> segment_reader =
+      SegmentReader::CreateFromSkData(std::move(data));
+  // We just need the size of the image, so we have to temporarily create an
+  // ImageDecoder. Since we only need the size, the premul and gamma settings
+  // don't really matter.
+  std::unique_ptr<ImageDecoder> decoder = ImageDecoder::Create(
+      segment_reader, true, ImageDecoder::kAlphaPremultiplied,
+      ColorBehavior::TransformToGlobalTarget());
+  if (!decoder || !decoder->IsSizeAvailable())
+    return nullptr;
+
+  const IntSize size = decoder->Size();
+  const SkImageInfo info =
+      SkImageInfo::MakeN32(size.Width(), size.Height(), kPremul_SkAlphaType,
+                           decoder->ColorSpaceForSkImages());
+
+  RefPtr<ImageFrameGenerator> frame =
+      ImageFrameGenerator::Create(SkISize::Make(size.Width(), size.Height()),
+                                  false, decoder->GetColorBehavior());
+  if (!frame)
+    return nullptr;
+
+  auto generator = DecodingImageGenerator::Create(
+      std::move(frame), info, std::move(segment_reader), true, 0);
+  return WTF::WrapUnique(new SkiaPaintImageGenerator(std::move(generator)));
+}
+
+// static
+sk_sp<DecodingImageGenerator> DecodingImageGenerator::Create(
+    PassRefPtr<ImageFrameGenerator> frame_generator,
+    const SkImageInfo& info,
+    PassRefPtr<SegmentReader> data,
+    bool all_data_received,
+    size_t index) {
+  return sk_sp<DecodingImageGenerator>(
+      new DecodingImageGenerator(std::move(frame_generator), info,
+                                 std::move(data), all_data_received, index));
+}
+
 DecodingImageGenerator::DecodingImageGenerator(
     PassRefPtr<ImageFrameGenerator> frame_generator,
     const SkImageInfo& info,
@@ -154,32 +196,4 @@
   return decoded;
 }
 
-std::unique_ptr<SkImageGenerator> DecodingImageGenerator::Create(SkData* data) {
-  RefPtr<SegmentReader> segment_reader =
-      SegmentReader::CreateFromSkData(sk_ref_sp(data));
-  // We just need the size of the image, so we have to temporarily create an
-  // ImageDecoder. Since we only need the size, the premul and gamma settings
-  // don't really matter.
-  std::unique_ptr<ImageDecoder> decoder = ImageDecoder::Create(
-      segment_reader, true, ImageDecoder::kAlphaPremultiplied,
-      ColorBehavior::TransformToGlobalTarget());
-  if (!decoder || !decoder->IsSizeAvailable())
-    return nullptr;
-
-  const IntSize size = decoder->Size();
-  const SkImageInfo info =
-      SkImageInfo::MakeN32(size.Width(), size.Height(), kPremul_SkAlphaType,
-                           decoder->ColorSpaceForSkImages());
-
-  RefPtr<ImageFrameGenerator> frame =
-      ImageFrameGenerator::Create(SkISize::Make(size.Width(), size.Height()),
-                                  false, decoder->GetColorBehavior());
-  if (!frame)
-    return nullptr;
-
-  sk_sp<DecodingImageGenerator> generator = sk_make_sp<DecodingImageGenerator>(
-      frame, info, std::move(segment_reader), true, 0);
-  return WTF::WrapUnique(new SkiaPaintImageGenerator(std::move(generator)));
-}
-
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/graphics/DecodingImageGenerator.h b/third_party/WebKit/Source/platform/graphics/DecodingImageGenerator.h
index bfeb7a7..80a9c73 100644
--- a/third_party/WebKit/Source/platform/graphics/DecodingImageGenerator.h
+++ b/third_party/WebKit/Source/platform/graphics/DecodingImageGenerator.h
@@ -50,13 +50,18 @@
   WTF_MAKE_NONCOPYABLE(DecodingImageGenerator);
 
  public:
-  static std::unique_ptr<SkImageGenerator> Create(SkData*);
+  // Aside from tests, this is used to create a decoder from SkData in Skia
+  // (exported via WebImageGenerator and set via
+  // SkGraphics::SetImageGeneratorFromEncodedDataFactory)
+  static std::unique_ptr<SkImageGenerator> CreateAsSkImageGenerator(
+      sk_sp<SkData>);
 
-  DecodingImageGenerator(PassRefPtr<ImageFrameGenerator>,
-                         const SkImageInfo&,
-                         PassRefPtr<SegmentReader>,
-                         bool all_data_received,
-                         size_t index);
+  static sk_sp<DecodingImageGenerator> Create(PassRefPtr<ImageFrameGenerator>,
+                                              const SkImageInfo&,
+                                              PassRefPtr<SegmentReader>,
+                                              bool all_data_received,
+                                              size_t index);
+
   ~DecodingImageGenerator() override;
 
   void SetCanYUVDecode(bool yes) { can_yuv_decode_ = yes; }
@@ -73,6 +78,12 @@
                      uint32_t lazy_pixel_ref) override;
 
  private:
+  DecodingImageGenerator(PassRefPtr<ImageFrameGenerator>,
+                         const SkImageInfo&,
+                         PassRefPtr<SegmentReader>,
+                         bool all_data_received,
+                         size_t index);
+
   RefPtr<ImageFrameGenerator> frame_generator_;
   const RefPtr<SegmentReader> data_;  // Data source.
   const bool all_data_received_;
diff --git a/third_party/WebKit/Source/platform/graphics/DecodingImageGeneratorTest.cpp b/third_party/WebKit/Source/platform/graphics/DecodingImageGeneratorTest.cpp
index 4c55454..12606979 100644
--- a/third_party/WebKit/Source/platform/graphics/DecodingImageGeneratorTest.cpp
+++ b/third_party/WebKit/Source/platform/graphics/DecodingImageGeneratorTest.cpp
@@ -38,7 +38,7 @@
   RefPtr<SegmentReader> reader =
       SegmentReader::CreateFromSharedBuffer(std::move(reference_data));
   std::unique_ptr<SkImageGenerator> generator =
-      DecodingImageGenerator::Create(reader->GetAsSkData().get());
+      DecodingImageGenerator::CreateAsSkImageGenerator(reader->GetAsSkData());
   // Sanity-check the image to make sure it was loaded.
   EXPECT_EQ(generator->getInfo().width(), 32);
   EXPECT_EQ(generator->getInfo().height(), 32);
@@ -48,10 +48,9 @@
   // Construct dummy image data that produces no valid size from the
   // ImageDecoder.
   char reference_data[kDefaultTestSize];
-  EXPECT_EQ(nullptr, DecodingImageGenerator::Create(
+  EXPECT_EQ(nullptr, DecodingImageGenerator::CreateAsSkImageGenerator(
                          CreateSegmentReader(reference_data, kDefaultTestSize)
-                             ->GetAsSkData()
-                             .get()));
+                             ->GetAsSkData()));
 }
 
 TEST_F(DecodingImageGeneratorTest, CreateWithNullImageDecoder) {
@@ -59,10 +58,9 @@
   // due to data being too short for a signature.
   char reference_data[kTooShortForSignature];
   EXPECT_EQ(nullptr,
-            DecodingImageGenerator::Create(
+            DecodingImageGenerator::CreateAsSkImageGenerator(
                 CreateSegmentReader(reference_data, kTooShortForSignature)
-                    ->GetAsSkData()
-                    .get()));
+                    ->GetAsSkData()));
 }
 
 // TODO(wkorman): Test Create with a null ImageFrameGenerator. We'd
diff --git a/third_party/WebKit/Source/platform/graphics/DeferredImageDecoder.cpp b/third_party/WebKit/Source/platform/graphics/DeferredImageDecoder.cpp
index b2eb794b..5c6c679 100644
--- a/third_party/WebKit/Source/platform/graphics/DeferredImageDecoder.cpp
+++ b/third_party/WebKit/Source/platform/graphics/DeferredImageDecoder.cpp
@@ -60,13 +60,13 @@
     bool data_complete,
     ImageDecoder::AlphaOption alpha_option,
     const ColorBehavior& color_behavior) {
-  std::unique_ptr<ImageDecoder> actual_decoder =
+  std::unique_ptr<ImageDecoder> metadata_decoder =
       ImageDecoder::Create(data, data_complete, alpha_option, color_behavior);
-  if (!actual_decoder)
+  if (!metadata_decoder)
     return nullptr;
 
   std::unique_ptr<DeferredImageDecoder> decoder(
-      new DeferredImageDecoder(std::move(actual_decoder)));
+      new DeferredImageDecoder(std::move(metadata_decoder)));
 
   // Since we've just instantiated a fresh decoder, there's no need to reset its
   // data.
@@ -76,13 +76,13 @@
 }
 
 std::unique_ptr<DeferredImageDecoder> DeferredImageDecoder::CreateForTesting(
-    std::unique_ptr<ImageDecoder> actual_decoder) {
-  return WTF::WrapUnique(new DeferredImageDecoder(std::move(actual_decoder)));
+    std::unique_ptr<ImageDecoder> metadata_decoder) {
+  return WTF::WrapUnique(new DeferredImageDecoder(std::move(metadata_decoder)));
 }
 
 DeferredImageDecoder::DeferredImageDecoder(
-    std::unique_ptr<ImageDecoder> actual_decoder)
-    : actual_decoder_(std::move(actual_decoder)),
+    std::unique_ptr<ImageDecoder> metadata_decoder)
+    : metadata_decoder_(std::move(metadata_decoder)),
       repetition_count_(kAnimationNone),
       all_data_received_(false),
       can_yuv_decode_(false),
@@ -91,8 +91,8 @@
 DeferredImageDecoder::~DeferredImageDecoder() {}
 
 String DeferredImageDecoder::FilenameExtension() const {
-  return actual_decoder_ ? actual_decoder_->FilenameExtension()
-                         : filename_extension_;
+  return metadata_decoder_ ? metadata_decoder_->FilenameExtension()
+                           : filename_extension_;
 }
 
 sk_sp<PaintImageGenerator> DeferredImageDecoder::CreateGeneratorAtIndex(
@@ -108,8 +108,8 @@
     return nullptr;
 
   DeferredFrameData* frame_data = &frame_data_[index];
-  if (actual_decoder_)
-    frame_data->frame_bytes_ = actual_decoder_->FrameBytesAtIndex(index);
+  if (metadata_decoder_)
+    frame_data->frame_bytes_ = metadata_decoder_->FrameBytesAtIndex(index);
   else
     frame_data->frame_bytes_ = size_.Area() * sizeof(ImageFrame::PixelData);
 
@@ -130,9 +130,9 @@
       known_to_be_opaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType,
       color_space_for_sk_images_);
 
-  auto generator = sk_make_sp<DecodingImageGenerator>(
-      frame_generator_, info, std::move(segment_reader), all_data_received_,
-      index);
+  auto generator = DecodingImageGenerator::Create(frame_generator_, info,
+                                                  std::move(segment_reader),
+                                                  all_data_received_, index);
   generator->SetCanYUVDecode(can_yuv_decode_);
 
   return generator;
@@ -158,10 +158,10 @@
 void DeferredImageDecoder::SetDataInternal(RefPtr<SharedBuffer> data,
                                            bool all_data_received,
                                            bool push_data_to_decoder) {
-  if (actual_decoder_) {
+  if (metadata_decoder_) {
     all_data_received_ = all_data_received;
     if (push_data_to_decoder)
-      actual_decoder_->SetData(data, all_data_received);
+      metadata_decoder_->SetData(data, all_data_received);
     PrepareLazyDecodedFrames();
   }
 
@@ -182,36 +182,37 @@
 bool DeferredImageDecoder::IsSizeAvailable() {
   // m_actualDecoder is 0 only if image decoding is deferred and that means
   // the image header decoded successfully and the size is available.
-  return actual_decoder_ ? actual_decoder_->IsSizeAvailable() : true;
+  return metadata_decoder_ ? metadata_decoder_->IsSizeAvailable() : true;
 }
 
 bool DeferredImageDecoder::HasEmbeddedColorSpace() const {
-  return actual_decoder_ ? actual_decoder_->HasEmbeddedColorSpace()
-                         : has_embedded_color_space_;
+  return metadata_decoder_ ? metadata_decoder_->HasEmbeddedColorSpace()
+                           : has_embedded_color_space_;
 }
 
 IntSize DeferredImageDecoder::Size() const {
-  return actual_decoder_ ? actual_decoder_->Size() : size_;
+  return metadata_decoder_ ? metadata_decoder_->Size() : size_;
 }
 
 IntSize DeferredImageDecoder::FrameSizeAtIndex(size_t index) const {
   // FIXME: LocalFrame size is assumed to be uniform. This might not be true for
   // future supported codecs.
-  return actual_decoder_ ? actual_decoder_->FrameSizeAtIndex(index) : size_;
+  return metadata_decoder_ ? metadata_decoder_->FrameSizeAtIndex(index) : size_;
 }
 
 size_t DeferredImageDecoder::FrameCount() {
-  return actual_decoder_ ? actual_decoder_->FrameCount() : frame_data_.size();
+  return metadata_decoder_ ? metadata_decoder_->FrameCount()
+                           : frame_data_.size();
 }
 
 int DeferredImageDecoder::RepetitionCount() const {
-  return actual_decoder_ ? actual_decoder_->RepetitionCount()
-                         : repetition_count_;
+  return metadata_decoder_ ? metadata_decoder_->RepetitionCount()
+                           : repetition_count_;
 }
 
 size_t DeferredImageDecoder::ClearCacheExceptFrame(size_t clear_except_frame) {
-  if (actual_decoder_)
-    return actual_decoder_->ClearCacheExceptFrame(clear_except_frame);
+  if (metadata_decoder_)
+    return metadata_decoder_->ClearCacheExceptFrame(clear_except_frame);
   size_t frame_bytes_cleared = 0;
   for (size_t i = 0; i < frame_data_.size(); ++i) {
     if (i != clear_except_frame) {
@@ -223,40 +224,49 @@
 }
 
 bool DeferredImageDecoder::FrameHasAlphaAtIndex(size_t index) const {
-  if (actual_decoder_)
-    return actual_decoder_->FrameHasAlphaAtIndex(index);
+  if (metadata_decoder_)
+    return metadata_decoder_->FrameHasAlphaAtIndex(index);
   if (!frame_generator_->IsMultiFrame())
     return frame_generator_->HasAlpha(index);
   return true;
 }
 
 bool DeferredImageDecoder::FrameIsReceivedAtIndex(size_t index) const {
-  if (actual_decoder_)
-    return actual_decoder_->FrameIsReceivedAtIndex(index);
+  if (metadata_decoder_)
+    return metadata_decoder_->FrameIsReceivedAtIndex(index);
   if (index < frame_data_.size())
     return frame_data_[index].is_received_;
   return false;
 }
 
 float DeferredImageDecoder::FrameDurationAtIndex(size_t index) const {
-  if (actual_decoder_)
-    return actual_decoder_->FrameDurationAtIndex(index);
+  float duration_ms = 0.f;
+  if (metadata_decoder_)
+    duration_ms = metadata_decoder_->FrameDurationAtIndex(index);
   if (index < frame_data_.size())
-    return frame_data_[index].duration_;
-  return 0;
+    duration_ms = frame_data_[index].duration_;
+
+  // Many annoying ads specify a 0 duration to make an image flash as quickly as
+  // possible. We follow Firefox's behavior and use a duration of 100 ms for any
+  // frames that specify a duration of <= 10 ms. See <rdar://problem/7689300>
+  // and <http://webkit.org/b/36082> for more information.
+  const float duration_sec = duration_ms / 1000.f;
+  if (duration_sec < 0.011f)
+    return 0.100f;
+  return duration_sec;
 }
 
 size_t DeferredImageDecoder::FrameBytesAtIndex(size_t index) const {
-  if (actual_decoder_)
-    return actual_decoder_->FrameBytesAtIndex(index);
+  if (metadata_decoder_)
+    return metadata_decoder_->FrameBytesAtIndex(index);
   if (index < frame_data_.size())
     return frame_data_[index].frame_bytes_;
   return 0;
 }
 
 ImageOrientation DeferredImageDecoder::OrientationAtIndex(size_t index) const {
-  if (actual_decoder_)
-    return actual_decoder_->Orientation();
+  if (metadata_decoder_)
+    return metadata_decoder_->Orientation();
   if (index < frame_data_.size())
     return frame_data_[index].orientation_;
   return kDefaultImageOrientation;
@@ -266,43 +276,43 @@
   if (frame_generator_)
     return;
 
-  size_ = actual_decoder_->Size();
-  has_hot_spot_ = actual_decoder_->HotSpot(hot_spot_);
-  filename_extension_ = actual_decoder_->FilenameExtension();
+  size_ = metadata_decoder_->Size();
+  has_hot_spot_ = metadata_decoder_->HotSpot(hot_spot_);
+  filename_extension_ = metadata_decoder_->FilenameExtension();
   // JPEG images support YUV decoding; other decoders do not. (WebP could in the
   // future.)
   can_yuv_decode_ = RuntimeEnabledFeatures::DecodeToYUVEnabled() &&
                     (filename_extension_ == "jpg");
-  has_embedded_color_space_ = actual_decoder_->HasEmbeddedColorSpace();
-  color_space_for_sk_images_ = actual_decoder_->ColorSpaceForSkImages();
+  has_embedded_color_space_ = metadata_decoder_->HasEmbeddedColorSpace();
+  color_space_for_sk_images_ = metadata_decoder_->ColorSpaceForSkImages();
 
   const bool is_single_frame =
-      actual_decoder_->RepetitionCount() == kAnimationNone ||
-      (all_data_received_ && actual_decoder_->FrameCount() == 1u);
+      metadata_decoder_->RepetitionCount() == kAnimationNone ||
+      (all_data_received_ && metadata_decoder_->FrameCount() == 1u);
   const SkISize decoded_size =
-      SkISize::Make(actual_decoder_->DecodedSize().Width(),
-                    actual_decoder_->DecodedSize().Height());
+      SkISize::Make(metadata_decoder_->DecodedSize().Width(),
+                    metadata_decoder_->DecodedSize().Height());
   frame_generator_ = ImageFrameGenerator::Create(
-      decoded_size, !is_single_frame, actual_decoder_->GetColorBehavior());
+      decoded_size, !is_single_frame, metadata_decoder_->GetColorBehavior());
 }
 
 void DeferredImageDecoder::PrepareLazyDecodedFrames() {
-  if (!actual_decoder_ || !actual_decoder_->IsSizeAvailable())
+  if (!metadata_decoder_ || !metadata_decoder_->IsSizeAvailable())
     return;
 
   ActivateLazyDecoding();
 
   const size_t previous_size = frame_data_.size();
-  frame_data_.resize(actual_decoder_->FrameCount());
+  frame_data_.resize(metadata_decoder_->FrameCount());
 
   // We have encountered a broken image file. Simply bail.
   if (frame_data_.size() < previous_size)
     return;
 
   for (size_t i = previous_size; i < frame_data_.size(); ++i) {
-    frame_data_[i].duration_ = actual_decoder_->FrameDurationAtIndex(i);
-    frame_data_[i].orientation_ = actual_decoder_->Orientation();
-    frame_data_[i].is_received_ = actual_decoder_->FrameIsReceivedAtIndex(i);
+    frame_data_[i].duration_ = metadata_decoder_->FrameDurationAtIndex(i);
+    frame_data_[i].orientation_ = metadata_decoder_->Orientation();
+    frame_data_[i].is_received_ = metadata_decoder_->FrameIsReceivedAtIndex(i);
   }
 
   // The last lazy decoded frame created from previous call might be
@@ -310,19 +320,21 @@
   if (previous_size) {
     const size_t last_frame = previous_size - 1;
     frame_data_[last_frame].is_received_ =
-        actual_decoder_->FrameIsReceivedAtIndex(last_frame);
+        metadata_decoder_->FrameIsReceivedAtIndex(last_frame);
   }
 
+  // If we've received all of the data, then we can reset the metadata decoder,
+  // since everything we care about should now be stored in |frame_data_|.
   if (all_data_received_) {
-    repetition_count_ = actual_decoder_->RepetitionCount();
-    actual_decoder_.reset();
+    repetition_count_ = metadata_decoder_->RepetitionCount();
+    metadata_decoder_.reset();
     // Hold on to m_rwBuffer, which is still needed by createFrameAtIndex.
   }
 }
 
 bool DeferredImageDecoder::HotSpot(IntPoint& hot_spot) const {
-  if (actual_decoder_)
-    return actual_decoder_->HotSpot(hot_spot);
+  if (metadata_decoder_)
+    return metadata_decoder_->HotSpot(hot_spot);
   if (has_hot_spot_)
     hot_spot = hot_spot_;
   return has_hot_spot_;
diff --git a/third_party/WebKit/Source/platform/graphics/DeferredImageDecoder.h b/third_party/WebKit/Source/platform/graphics/DeferredImageDecoder.h
index 0062f274..b56aaff 100644
--- a/third_party/WebKit/Source/platform/graphics/DeferredImageDecoder.h
+++ b/third_party/WebKit/Source/platform/graphics/DeferredImageDecoder.h
@@ -74,13 +74,15 @@
   size_t ClearCacheExceptFrame(size_t index);
   bool FrameHasAlphaAtIndex(size_t index) const;
   bool FrameIsReceivedAtIndex(size_t index) const;
+  // Duration is reported in seconds.
+  // TODO(vmpstr): Use something like TimeDelta here.
   float FrameDurationAtIndex(size_t index) const;
   size_t FrameBytesAtIndex(size_t index) const;
   ImageOrientation OrientationAtIndex(size_t index) const;
   bool HotSpot(IntPoint&) const;
 
  private:
-  explicit DeferredImageDecoder(std::unique_ptr<ImageDecoder> actual_decoder);
+  explicit DeferredImageDecoder(std::unique_ptr<ImageDecoder> metadata_decoder);
 
   friend class DeferredImageDecoderTest;
   ImageFrameGenerator* FrameGenerator() { return frame_generator_.Get(); }
@@ -95,7 +97,7 @@
   // Copy of the data that is passed in, used by deferred decoding.
   // Allows creating readonly snapshots that may be read in another thread.
   std::unique_ptr<SkRWBuffer> rw_buffer_;
-  std::unique_ptr<ImageDecoder> actual_decoder_;
+  std::unique_ptr<ImageDecoder> metadata_decoder_;
 
   String filename_extension_;
   IntSize size_;
diff --git a/third_party/WebKit/Source/platform/graphics/DeferredImageDecoderTest.cpp b/third_party/WebKit/Source/platform/graphics/DeferredImageDecoderTest.cpp
index eb6dd8c..c2dba01 100644
--- a/third_party/WebKit/Source/platform/graphics/DeferredImageDecoderTest.cpp
+++ b/third_party/WebKit/Source/platform/graphics/DeferredImageDecoderTest.cpp
@@ -271,7 +271,9 @@
   PaintImage image = CreatePaintImageAtIndex(0);
   ASSERT_TRUE(image);
   EXPECT_FALSE(lazy_decoder_->FrameIsReceivedAtIndex(0));
-  EXPECT_EQ(10.0f, lazy_decoder_->FrameDurationAtIndex(0));
+  // Anything below .011f seconds is rounded to 0.1f seconds.
+  // See the implementaiton for details.
+  EXPECT_FLOAT_EQ(0.1f, lazy_decoder_->FrameDurationAtIndex(0));
 
   frame_count_ = 2;
   frame_duration_ = 20;
@@ -283,7 +285,7 @@
   ASSERT_TRUE(image);
   EXPECT_TRUE(lazy_decoder_->FrameIsReceivedAtIndex(0));
   EXPECT_TRUE(lazy_decoder_->FrameIsReceivedAtIndex(1));
-  EXPECT_EQ(20.0f, lazy_decoder_->FrameDurationAtIndex(1));
+  EXPECT_FLOAT_EQ(0.02f, lazy_decoder_->FrameDurationAtIndex(1));
   EXPECT_TRUE(actual_decoder_);
 
   frame_count_ = 3;
@@ -294,9 +296,9 @@
   EXPECT_TRUE(lazy_decoder_->FrameIsReceivedAtIndex(0));
   EXPECT_TRUE(lazy_decoder_->FrameIsReceivedAtIndex(1));
   EXPECT_TRUE(lazy_decoder_->FrameIsReceivedAtIndex(2));
-  EXPECT_EQ(10.0f, lazy_decoder_->FrameDurationAtIndex(0));
-  EXPECT_EQ(20.0f, lazy_decoder_->FrameDurationAtIndex(1));
-  EXPECT_EQ(30.0f, lazy_decoder_->FrameDurationAtIndex(2));
+  EXPECT_FLOAT_EQ(0.1f, lazy_decoder_->FrameDurationAtIndex(0));
+  EXPECT_FLOAT_EQ(0.02f, lazy_decoder_->FrameDurationAtIndex(1));
+  EXPECT_FLOAT_EQ(0.03f, lazy_decoder_->FrameDurationAtIndex(2));
   EXPECT_EQ(10, lazy_decoder_->RepetitionCount());
 }
 
diff --git a/third_party/WebKit/Source/platform/graphics/ImageSource.cpp b/third_party/WebKit/Source/platform/graphics/ImageSource.cpp
deleted file mode 100644
index 5d8cf99..0000000
--- a/third_party/WebKit/Source/platform/graphics/ImageSource.cpp
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright (C) 2006 Apple Computer, Inc.  All rights reserved.
- * Copyright (C) 2007 Alp Toker <alp.toker@collabora.co.uk>
- * Copyright (C) 2008, Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "platform/graphics/ImageSource.h"
-
-#include "platform/RuntimeEnabledFeatures.h"
-#include "platform/graphics/DeferredImageDecoder.h"
-#include "platform/image-decoders/ImageDecoder.h"
-#include "third_party/skia/include/core/SkImage.h"
-
-namespace blink {
-
-ImageSource::ImageSource() {}
-
-ImageSource::~ImageSource() {}
-
-size_t ImageSource::ClearCacheExceptFrame(size_t clear_except_frame) {
-  return decoder_ ? decoder_->ClearCacheExceptFrame(clear_except_frame) : 0;
-}
-
-PassRefPtr<SharedBuffer> ImageSource::Data() {
-  return decoder_ ? decoder_->Data() : nullptr;
-}
-
-bool ImageSource::SetData(RefPtr<SharedBuffer> data, bool all_data_received) {
-  all_data_received_ = all_data_received;
-
-  if (decoder_) {
-    decoder_->SetData(std::move(data), all_data_received);
-    // If the decoder is pre-instantiated, it means we've already validated the
-    // data/signature at some point.
-    return true;
-  }
-
-  ColorBehavior color_behavior =
-      RuntimeEnabledFeatures::ColorCorrectRenderingEnabled()
-          ? ColorBehavior::Tag()
-          : ColorBehavior::TransformToGlobalTarget();
-  decoder_ = DeferredImageDecoder::Create(data, all_data_received,
-                                          ImageDecoder::kAlphaPremultiplied,
-                                          color_behavior);
-
-  // Insufficient data is not a failure.
-  return decoder_ || !ImageDecoder::HasSufficientDataToSniffImageType(*data);
-}
-
-String ImageSource::FilenameExtension() const {
-  return decoder_ ? decoder_->FilenameExtension() : String();
-}
-
-bool ImageSource::IsSizeAvailable() {
-  return decoder_ && decoder_->IsSizeAvailable();
-}
-
-bool ImageSource::HasColorProfile() const {
-  return decoder_ && decoder_->HasEmbeddedColorSpace();
-}
-
-IntSize ImageSource::size(
-    RespectImageOrientationEnum should_respect_orientation) const {
-  return FrameSizeAtIndex(0, should_respect_orientation);
-}
-
-IntSize ImageSource::FrameSizeAtIndex(
-    size_t index,
-    RespectImageOrientationEnum should_respect_orientation) const {
-  if (!decoder_)
-    return IntSize();
-
-  IntSize size = decoder_->FrameSizeAtIndex(index);
-  if ((should_respect_orientation == kRespectImageOrientation) &&
-      decoder_->OrientationAtIndex(index).UsesWidthAsHeight())
-    return size.TransposedSize();
-
-  return size;
-}
-
-bool ImageSource::GetHotSpot(IntPoint& hot_spot) const {
-  return decoder_ ? decoder_->HotSpot(hot_spot) : false;
-}
-
-int ImageSource::RepetitionCount() {
-  return decoder_ ? decoder_->RepetitionCount() : kAnimationNone;
-}
-
-size_t ImageSource::FrameCount() const {
-  return decoder_ ? decoder_->FrameCount() : 0;
-}
-
-sk_sp<PaintImageGenerator> ImageSource::CreateGeneratorAtIndex(size_t index) {
-  if (!decoder_)
-    return nullptr;
-
-  return decoder_->CreateGeneratorAtIndex(index);
-}
-
-float ImageSource::FrameDurationAtIndex(size_t index) const {
-  if (!decoder_)
-    return 0;
-
-  // Many annoying ads specify a 0 duration to make an image flash as quickly as
-  // possible. We follow Firefox's behavior and use a duration of 100 ms for any
-  // frames that specify a duration of <= 10 ms. See <rdar://problem/7689300>
-  // and <http://webkit.org/b/36082> for more information.
-  const float duration = decoder_->FrameDurationAtIndex(index) / 1000.0f;
-  if (duration < 0.011f)
-    return 0.100f;
-  return duration;
-}
-
-ImageOrientation ImageSource::OrientationAtIndex(size_t index) const {
-  return decoder_ ? decoder_->OrientationAtIndex(index)
-                  : kDefaultImageOrientation;
-}
-
-bool ImageSource::FrameHasAlphaAtIndex(size_t index) const {
-  return !decoder_ || decoder_->FrameHasAlphaAtIndex(index);
-}
-
-bool ImageSource::FrameIsReceivedAtIndex(size_t index) const {
-  return decoder_ && decoder_->FrameIsReceivedAtIndex(index);
-}
-
-size_t ImageSource::FrameBytesAtIndex(size_t index) const {
-  return decoder_ ? decoder_->FrameBytesAtIndex(index) : 0;
-}
-
-}  // namespace blink
diff --git a/third_party/WebKit/Source/platform/graphics/ImageSource.h b/third_party/WebKit/Source/platform/graphics/ImageSource.h
deleted file mode 100644
index aca0dc54..0000000
--- a/third_party/WebKit/Source/platform/graphics/ImageSource.h
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef ImageSource_h
-#define ImageSource_h
-
-#include <memory>
-#include "platform/PlatformExport.h"
-#include "platform/graphics/ColorBehavior.h"
-#include "platform/graphics/DeferredImageDecoder.h"
-#include "platform/graphics/ImageOrientation.h"
-#include "platform/wtf/Forward.h"
-#include "platform/wtf/Noncopyable.h"
-#include "third_party/skia/include/core/SkRefCnt.h"
-
-namespace blink {
-
-class ImageOrientation;
-class IntPoint;
-class IntSize;
-class SharedBuffer;
-
-class PLATFORM_EXPORT ImageSource final {
-  USING_FAST_MALLOC(ImageSource);
-  WTF_MAKE_NONCOPYABLE(ImageSource);
-
- public:
-  ImageSource();
-  ~ImageSource();
-
-  // Tells the ImageSource that the Image no longer cares about decoded frame
-  // data except for the specified frame. Callers may pass WTF::kNotFound to
-  // clear all frames.
-  //
-  // In response, the ImageSource should delete cached decoded data for other
-  // frames where possible to keep memory use low. The expectation is that in
-  // the future, the caller may call createFrameAtIndex() with an index larger
-  // than the one passed to this function, and the implementation may then
-  // make use of the preserved frame data here in decoding that frame.
-  // By contrast, callers who call this function and then later ask for an
-  // earlier frame may require more work to be done, e.g. redecoding the image
-  // from the beginning.
-  //
-  // Implementations may elect to preserve more frames than the one requested
-  // here if doing so is likely to save CPU time in the future, but will pay
-  // an increased memory cost to do so.
-  //
-  // Returns the number of bytes of frame data actually cleared.
-  size_t ClearCacheExceptFrame(size_t);
-
-  PassRefPtr<SharedBuffer> Data();
-  // Returns false when the decoder layer rejects the data.
-  bool SetData(RefPtr<SharedBuffer> data, bool all_data_received);
-  String FilenameExtension() const;
-
-  bool IsSizeAvailable();
-  bool HasColorProfile() const;
-  IntSize size(
-      RespectImageOrientationEnum = kDoNotRespectImageOrientation) const;
-  IntSize FrameSizeAtIndex(
-      size_t,
-      RespectImageOrientationEnum = kDoNotRespectImageOrientation) const;
-
-  bool GetHotSpot(IntPoint&) const;
-  int RepetitionCount();
-
-  size_t FrameCount() const;
-
-  // Attempts to create the requested frame.
-  sk_sp<PaintImageGenerator> CreateGeneratorAtIndex(size_t);
-
-  float FrameDurationAtIndex(size_t) const;
-  bool FrameHasAlphaAtIndex(
-      size_t) const;  // Whether or not the frame actually used any alpha.
-  bool FrameIsReceivedAtIndex(
-      size_t) const;  // Whether or not the frame is fully received.
-  ImageOrientation OrientationAtIndex(size_t) const;  // EXIF image orientation
-
-  // Returns the number of bytes in the decoded frame. May return 0 if the
-  // frame has not yet begun to decode.
-  size_t FrameBytesAtIndex(size_t) const;
-
- private:
-  std::unique_ptr<DeferredImageDecoder> decoder_;
-  bool all_data_received_ = false;
-};
-
-}  // namespace blink
-
-#endif
diff --git a/third_party/WebKit/Source/platform/loader/testing/MockFetchContext.h b/third_party/WebKit/Source/platform/loader/testing/MockFetchContext.h
index d30afd3..e5c9802 100644
--- a/third_party/WebKit/Source/platform/loader/testing/MockFetchContext.h
+++ b/third_party/WebKit/Source/platform/loader/testing/MockFetchContext.h
@@ -96,16 +96,14 @@
         : runner_(std::move(runner)) {}
     void AddThrottlingObserver(ObserverType, Observer*) override {}
     void RemoveThrottlingObserver(ObserverType, Observer*) override {}
-    RefPtr<WebTaskRunner> TimerTaskRunner() override { return runner_; }
     RefPtr<WebTaskRunner> LoadingTaskRunner() override { return runner_; }
     RefPtr<WebTaskRunner> LoadingControlTaskRunner() override {
       return runner_;
     }
-    RefPtr<WebTaskRunner> SuspendableTaskRunner() override { return runner_; }
-    RefPtr<WebTaskRunner> UnthrottledTaskRunner() override { return runner_; }
-    RefPtr<WebTaskRunner> UnthrottledButBlockableTaskRunner() override {
-      return runner_;
-    }
+    RefPtr<WebTaskRunner> ThrottleableTaskRunner() override { return runner_; }
+    RefPtr<WebTaskRunner> DeferrableTaskRunner() override { return runner_; }
+    RefPtr<WebTaskRunner> PausableTaskRunner() override { return runner_; }
+    RefPtr<WebTaskRunner> UnpausableTaskRunner() override { return runner_; }
 
    private:
     RefPtr<WebTaskRunner> runner_;
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/budget_pool_unittest.cc b/third_party/WebKit/Source/platform/scheduler/renderer/budget_pool_unittest.cc
index e2fd7ddc..ade141c 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/budget_pool_unittest.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/budget_pool_unittest.cc
@@ -134,7 +134,7 @@
       task_queue_throttler_->CreateWakeUpBudgetPool("test");
 
   scoped_refptr<TaskQueue> queue = scheduler_->NewTimerTaskQueue(
-      MainThreadTaskQueue::QueueType::FRAME_TIMER);
+      MainThreadTaskQueue::QueueType::FRAME_THROTTLEABLE);
 
   pool->SetWakeUpRate(0.1);
   pool->SetWakeUpDuration(base::TimeDelta::FromMilliseconds(10));
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/main_thread_task_queue.cc b/third_party/WebKit/Source/platform/scheduler/renderer/main_thread_task_queue.cc
index ac3c659a..e3a7de42 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/main_thread_task_queue.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/main_thread_task_queue.cc
@@ -26,10 +26,14 @@
       return "unthrottled_tq";
     case MainThreadTaskQueue::QueueType::FRAME_LOADING:
       return "frame_loading_tq";
-    case MainThreadTaskQueue::QueueType::FRAME_TIMER:
-      return "frame_timer_tq";
-    case MainThreadTaskQueue::QueueType::FRAME_UNTHROTTLED:
-      return "frame_unthrottled_tq";
+    case MainThreadTaskQueue::QueueType::FRAME_THROTTLEABLE:
+      return "frame_throttleable_tq";
+    case MainThreadTaskQueue::QueueType::FRAME_DEFERRABLE:
+      return "frame_deferrable_tq";
+    case MainThreadTaskQueue::QueueType::FRAME_PAUSABLE:
+      return "frame_pausable_tq";
+    case MainThreadTaskQueue::QueueType::FRAME_UNPAUSABLE:
+      return "frame_unpausable_tq";
     case MainThreadTaskQueue::QueueType::COMPOSITOR:
       return "compositor_tq";
     case MainThreadTaskQueue::QueueType::IDLE:
@@ -59,11 +63,11 @@
     case QueueType::FRAME_LOADING_CONTROL:
       return QueueClass::LOADING;
     case QueueType::DEFAULT_TIMER:
-    case QueueType::FRAME_TIMER:
-    // Unthrottled tasks are considered timers which can't be throttled and
-    // fall into TIMER class.
-    case QueueType::FRAME_UNTHROTTLED:
     case QueueType::UNTHROTTLED:
+    case QueueType::FRAME_THROTTLEABLE:
+    case QueueType::FRAME_DEFERRABLE:
+    case QueueType::FRAME_PAUSABLE:
+    case QueueType::FRAME_UNPAUSABLE:
       return QueueClass::TIMER;
     case QueueType::COMPOSITOR:
       return QueueClass::COMPOSITOR;
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/main_thread_task_queue.h b/third_party/WebKit/Source/platform/scheduler/renderer/main_thread_task_queue.h
index b014ee9e..21d90ae8 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/main_thread_task_queue.h
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/main_thread_task_queue.h
@@ -20,20 +20,28 @@
   enum class QueueType {
     // Keep MainThreadTaskQueue::NameForQueueType in sync.
     // This enum is used for a histogram and it should not be re-numbered.
+    // TODO(altimin): Clean up obsolete names and use a new histogram when
+    // the situation settles.
     CONTROL = 0,
     DEFAULT = 1,
     DEFAULT_LOADING = 2,
+    // DEFAULT_TIMER is deprecated and should be replaced with appropriate
+    // per-frame task queues.
     DEFAULT_TIMER = 3,
     UNTHROTTLED = 4,
     FRAME_LOADING = 5,
-    FRAME_TIMER = 6,
-    FRAME_UNTHROTTLED = 7,
+    // 6 : FRAME_THROTTLEABLE, replaced with FRAME_THROTTLEABLE.
+    // 7 : FRAME_PAUSABLE, replaced with FRAME_PAUSABLE
     COMPOSITOR = 8,
     IDLE = 9,
     TEST = 10,
     FRAME_LOADING_CONTROL = 11,
+    FRAME_THROTTLEABLE = 12,
+    FRAME_DEFERRABLE = 13,
+    FRAME_PAUSABLE = 14,
+    FRAME_UNPAUSABLE = 15,
 
-    COUNT = 12
+    COUNT = 16
   };
 
   // Returns name of the given queue type. Returned string has application
@@ -62,7 +70,7 @@
           can_be_stopped(false),
           used_for_control_tasks(false) {}
 
-    QueueCreationParams SetCanBeBlocked(bool value) {
+    QueueCreationParams SetCanBeDeferred(bool value) {
       can_be_blocked = value;
       return *this;
     }
@@ -126,7 +134,7 @@
 
   QueueClass queue_class() const { return queue_class_; }
 
-  bool CanBeBlocked() const { return can_be_blocked_; }
+  bool CanBeDeferred() const { return can_be_blocked_; }
 
   bool CanBeThrottled() const { return can_be_throttled_; }
 
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_metrics_helper_unittest.cc b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_metrics_helper_unittest.cc
index 18e7557..bfeb1562 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_metrics_helper_unittest.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_metrics_helper_unittest.cc
@@ -20,6 +20,7 @@
 
 using QueueType = MainThreadTaskQueue::QueueType;
 using testing::ElementsAre;
+using testing::UnorderedElementsAre;
 using base::Bucket;
 
 class RendererMetricsHelperTest : public ::testing::Test {
@@ -88,7 +89,7 @@
           base::TimeDelta::FromMilliseconds(5));
   RunTask(QueueType::FRAME_LOADING, Milliseconds(800),
           base::TimeDelta::FromMilliseconds(70));
-  RunTask(QueueType::FRAME_UNTHROTTLED, Milliseconds(1000),
+  RunTask(QueueType::FRAME_PAUSABLE, Milliseconds(1000),
           base::TimeDelta::FromMilliseconds(20));
   RunTask(QueueType::COMPOSITOR, Milliseconds(1200),
           base::TimeDelta::FromMilliseconds(25));
@@ -99,13 +100,13 @@
 
   RunTask(QueueType::CONTROL, Milliseconds(2000),
           base::TimeDelta::FromMilliseconds(25));
-  RunTask(QueueType::FRAME_TIMER, Milliseconds(2600),
+  RunTask(QueueType::FRAME_THROTTLEABLE, Milliseconds(2600),
           base::TimeDelta::FromMilliseconds(175));
   RunTask(QueueType::UNTHROTTLED, Milliseconds(2800),
           base::TimeDelta::FromMilliseconds(25));
   RunTask(QueueType::FRAME_LOADING, Milliseconds(3000),
           base::TimeDelta::FromMilliseconds(35));
-  RunTask(QueueType::FRAME_TIMER, Milliseconds(3200),
+  RunTask(QueueType::FRAME_THROTTLEABLE, Milliseconds(3200),
           base::TimeDelta::FromMilliseconds(5));
   RunTask(QueueType::COMPOSITOR, Milliseconds(3400),
           base::TimeDelta::FromMilliseconds(20));
@@ -115,9 +116,9 @@
           base::TimeDelta::FromMilliseconds(5));
   RunTask(QueueType::CONTROL, Milliseconds(4200),
           base::TimeDelta::FromMilliseconds(20));
-  RunTask(QueueType::FRAME_TIMER, Milliseconds(4400),
+  RunTask(QueueType::FRAME_THROTTLEABLE, Milliseconds(4400),
           base::TimeDelta::FromMilliseconds(115));
-  RunTask(QueueType::FRAME_UNTHROTTLED, Milliseconds(4600),
+  RunTask(QueueType::FRAME_PAUSABLE, Milliseconds(4600),
           base::TimeDelta::FromMilliseconds(175));
   RunTask(QueueType::IDLE, Milliseconds(5000),
           base::TimeDelta::FromMilliseconds(1600));
@@ -129,37 +130,37 @@
       {static_cast<int>(QueueType::DEFAULT_TIMER), 5},
       {static_cast<int>(QueueType::UNTHROTTLED), 25},
       {static_cast<int>(QueueType::FRAME_LOADING), 105},
-      {static_cast<int>(QueueType::FRAME_TIMER), 295},
-      {static_cast<int>(QueueType::FRAME_UNTHROTTLED), 195},
       {static_cast<int>(QueueType::COMPOSITOR), 45},
       {static_cast<int>(QueueType::IDLE), 1650},
       {static_cast<int>(QueueType::TEST), 85},
-      {static_cast<int>(QueueType::FRAME_LOADING_CONTROL), 5}};
+      {static_cast<int>(QueueType::FRAME_LOADING_CONTROL), 5},
+      {static_cast<int>(QueueType::FRAME_THROTTLEABLE), 295},
+      {static_cast<int>(QueueType::FRAME_PAUSABLE), 195}};
   EXPECT_THAT(histogram_tester_->GetAllSamples(
                   "RendererScheduler.TaskDurationPerQueueType2"),
               testing::ContainerEq(expected_samples));
 
-  EXPECT_THAT(
-      histogram_tester_->GetAllSamples(
-          "RendererScheduler.TaskDurationPerQueueType2.Foreground"),
-      ElementsAre(Bucket(static_cast<int>(QueueType::CONTROL), 30),
+  EXPECT_THAT(histogram_tester_->GetAllSamples(
+                  "RendererScheduler.TaskDurationPerQueueType2.Foreground"),
+              UnorderedElementsAre(
+                  Bucket(static_cast<int>(QueueType::CONTROL), 30),
                   Bucket(static_cast<int>(QueueType::DEFAULT), 2),
                   Bucket(static_cast<int>(QueueType::DEFAULT_LOADING), 20),
                   Bucket(static_cast<int>(QueueType::DEFAULT_TIMER), 5),
                   Bucket(static_cast<int>(QueueType::FRAME_LOADING), 70),
-                  Bucket(static_cast<int>(QueueType::FRAME_UNTHROTTLED), 20),
                   Bucket(static_cast<int>(QueueType::COMPOSITOR), 25),
-                  Bucket(static_cast<int>(QueueType::TEST), 85)));
+                  Bucket(static_cast<int>(QueueType::TEST), 85),
+                  Bucket(static_cast<int>(QueueType::FRAME_PAUSABLE), 20)));
 
   EXPECT_THAT(
       histogram_tester_->GetAllSamples(
           "RendererScheduler.TaskDurationPerQueueType2.Background"),
-      ElementsAre(
+      UnorderedElementsAre(
           Bucket(static_cast<int>(QueueType::CONTROL), 45),
           Bucket(static_cast<int>(QueueType::UNTHROTTLED), 25),
           Bucket(static_cast<int>(QueueType::FRAME_LOADING), 35),
-          Bucket(static_cast<int>(QueueType::FRAME_TIMER), 295),
-          Bucket(static_cast<int>(QueueType::FRAME_UNTHROTTLED), 175),
+          Bucket(static_cast<int>(QueueType::FRAME_THROTTLEABLE), 295),
+          Bucket(static_cast<int>(QueueType::FRAME_PAUSABLE), 175),
           Bucket(static_cast<int>(QueueType::COMPOSITOR), 20),
           Bucket(static_cast<int>(QueueType::IDLE), 1650),
           Bucket(static_cast<int>(QueueType::FRAME_LOADING_CONTROL), 5)));
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc
index 74dbd2d..c099903 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc
@@ -319,6 +319,11 @@
   if (task_queue->CanBeThrottled())
     AddQueueToWakeUpBudgetPool(task_queue.get());
 
+  if (queue_class == MainThreadTaskQueue::QueueClass::TIMER) {
+    if (main_thread_only().virtual_time_stopped)
+      task_queue->InsertFence(TaskQueue::InsertFencePosition::NOW);
+  }
+
   return task_queue;
 }
 
@@ -329,7 +334,7 @@
   return NewTaskQueue(
       MainThreadTaskQueue::QueueCreationParams(queue_type)
           .SetCanBePaused(true)
-          .SetCanBeBlocked(true)
+          .SetCanBeDeferred(true)
           .SetUsedForControlTasks(
               queue_type ==
               MainThreadTaskQueue::QueueType::FRAME_LOADING_CONTROL));
@@ -339,16 +344,12 @@
     MainThreadTaskQueue::QueueType queue_type) {
   DCHECK_EQ(MainThreadTaskQueue::QueueClassForQueueType(queue_type),
             MainThreadTaskQueue::QueueClass::TIMER);
-  auto timer_task_queue =
-      NewTaskQueue(MainThreadTaskQueue::QueueCreationParams(queue_type)
-                       .SetShouldReportWhenExecutionBlocked(true)
-                       .SetCanBePaused(true)
-                       .SetCanBeStopped(true)
-                       .SetCanBeBlocked(true)
-                       .SetCanBeThrottled(true));
-  if (main_thread_only().virtual_time_stopped)
-    timer_task_queue->InsertFence(TaskQueue::InsertFencePosition::NOW);
-  return timer_task_queue;
+  return NewTaskQueue(MainThreadTaskQueue::QueueCreationParams(queue_type)
+                          .SetShouldReportWhenExecutionBlocked(true)
+                          .SetCanBePaused(true)
+                          .SetCanBeStopped(true)
+                          .SetCanBeDeferred(true)
+                          .SetCanBeThrottled(true));
 }
 
 std::unique_ptr<RenderWidgetSchedulingState>
@@ -1573,7 +1574,7 @@
     return false;
   if (is_paused && task_queue->CanBePaused())
     return false;
-  if (is_blocked && task_queue->CanBeBlocked())
+  if (is_blocked && task_queue->CanBeDeferred())
     return false;
   if (is_stopped && task_queue->CanBeStopped())
     return false;
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl_unittest.cc b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl_unittest.cc
index eb6f4fc..f650780 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl_unittest.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl_unittest.cc
@@ -3769,7 +3769,7 @@
   scoped_refptr<TaskQueue> loading_control_tq = scheduler_->NewLoadingTaskQueue(
       MainThreadTaskQueue::QueueType::FRAME_LOADING_CONTROL);
   scoped_refptr<MainThreadTaskQueue> timer_tq = scheduler_->NewTimerTaskQueue(
-      MainThreadTaskQueue::QueueType::FRAME_TIMER);
+      MainThreadTaskQueue::QueueType::FRAME_THROTTLEABLE);
   scoped_refptr<MainThreadTaskQueue> unthrottled_tq =
       scheduler_->NewTaskQueue(MainThreadTaskQueue::QueueCreationParams(
           MainThreadTaskQueue::QueueType::UNTHROTTLED));
@@ -3801,10 +3801,11 @@
           ->NewLoadingTaskQueue(MainThreadTaskQueue::QueueType::FRAME_LOADING)
           ->GetTimeDomain(),
       scheduler_->GetVirtualTimeDomain());
-  EXPECT_EQ(
-      scheduler_->NewTimerTaskQueue(MainThreadTaskQueue::QueueType::FRAME_TIMER)
-          ->GetTimeDomain(),
-      scheduler_->GetVirtualTimeDomain());
+  EXPECT_EQ(scheduler_
+                ->NewTimerTaskQueue(
+                    MainThreadTaskQueue::QueueType::FRAME_THROTTLEABLE)
+                ->GetTimeDomain(),
+            scheduler_->GetVirtualTimeDomain());
   EXPECT_EQ(scheduler_
                 ->NewTaskQueue(MainThreadTaskQueue::QueueCreationParams(
                     MainThreadTaskQueue::QueueType::UNTHROTTLED))
@@ -3821,7 +3822,7 @@
   scheduler_->EnableVirtualTime();
 
   scoped_refptr<MainThreadTaskQueue> timer_tq = scheduler_->NewTimerTaskQueue(
-      MainThreadTaskQueue::QueueType::FRAME_TIMER);
+      MainThreadTaskQueue::QueueType::FRAME_THROTTLEABLE);
   scoped_refptr<MainThreadTaskQueue> unthrottled_tq =
       scheduler_->NewTaskQueue(MainThreadTaskQueue::QueueCreationParams(
           MainThreadTaskQueue::QueueType::UNTHROTTLED));
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/task_queue_throttler_unittest.cc b/third_party/WebKit/Source/platform/scheduler/renderer/task_queue_throttler_unittest.cc
index 84f6234..9533f3d 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/task_queue_throttler_unittest.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/task_queue_throttler_unittest.cc
@@ -90,7 +90,7 @@
     scheduler_.reset(new RendererSchedulerImpl(delegate_));
     task_queue_throttler_ = scheduler_->task_queue_throttler();
     timer_queue_ = scheduler_->NewTimerTaskQueue(
-        MainThreadTaskQueue::QueueType::FRAME_TIMER);
+        MainThreadTaskQueue::QueueType::FRAME_THROTTLEABLE);
   }
 
   void TearDown() override {
@@ -745,7 +745,7 @@
   std::vector<base::TimeTicks> run_times;
 
   scoped_refptr<TaskQueue> second_queue = scheduler_->NewTimerTaskQueue(
-      MainThreadTaskQueue::QueueType::FRAME_TIMER);
+      MainThreadTaskQueue::QueueType::FRAME_THROTTLEABLE);
 
   CPUTimeBudgetPool* pool =
       task_queue_throttler_->CreateCPUTimeBudgetPool("test");
@@ -1071,7 +1071,7 @@
 
   scoped_refptr<MainThreadTaskQueue> second_queue =
       scheduler_->NewTimerTaskQueue(
-          MainThreadTaskQueue::QueueType::FRAME_TIMER);
+          MainThreadTaskQueue::QueueType::FRAME_THROTTLEABLE);
 
   task_queue_throttler_->IncreaseThrottleRefCount(timer_queue_.get());
   task_queue_throttler_->IncreaseThrottleRefCount(second_queue.get());
@@ -1107,7 +1107,7 @@
   std::vector<base::TimeTicks> run_times;
 
   scoped_refptr<TaskQueue> second_queue = scheduler_->NewTimerTaskQueue(
-      MainThreadTaskQueue::QueueType::FRAME_TIMER);
+      MainThreadTaskQueue::QueueType::FRAME_THROTTLEABLE);
 
   CPUTimeBudgetPool* pool1 =
       task_queue_throttler_->CreateCPUTimeBudgetPool("test");
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/web_frame_scheduler_impl.cc b/third_party/WebKit/Source/platform/scheduler/renderer/web_frame_scheduler_impl.cc
index d56d3dec..e51dbc3f9d 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/web_frame_scheduler_impl.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/web_frame_scheduler_impl.cc
@@ -46,45 +46,29 @@
       active_connection_count_(0),
       weak_factory_(this) {}
 
+namespace {
+
+void CleanUpQueue(MainThreadTaskQueue* queue) {
+  if (!queue)
+    return;
+  queue->UnregisterTaskQueue();
+  queue->SetFrameScheduler(nullptr);
+  queue->SetBlameContext(nullptr);
+}
+
+}  // namespace
+
 WebFrameSchedulerImpl::~WebFrameSchedulerImpl() {
   weak_factory_.InvalidateWeakPtrs();
 
-  if (loading_task_queue_) {
-    loading_task_queue_->UnregisterTaskQueue();
-    loading_task_queue_->SetFrameScheduler(nullptr);
-    loading_task_queue_->SetBlameContext(nullptr);
-  }
+  RemoveThrottleableQueueFromBackgroundCPUTimeBudgetPool();
 
-  if (loading_control_task_queue_) {
-    loading_control_task_queue_->UnregisterTaskQueue();
-    loading_control_task_queue_->SetFrameScheduler(nullptr);
-    loading_control_task_queue_->SetBlameContext(nullptr);
-  }
-
-  if (timer_task_queue_) {
-    RemoveTimerQueueFromBackgroundCPUTimeBudgetPool();
-    timer_task_queue_->UnregisterTaskQueue();
-    timer_task_queue_->SetFrameScheduler(nullptr);
-    timer_task_queue_->SetBlameContext(nullptr);
-  }
-
-  if (unthrottled_task_queue_) {
-    unthrottled_task_queue_->UnregisterTaskQueue();
-    unthrottled_task_queue_->SetFrameScheduler(nullptr);
-    unthrottled_task_queue_->SetBlameContext(nullptr);
-  }
-
-  if (suspendable_task_queue_) {
-    suspendable_task_queue_->UnregisterTaskQueue();
-    suspendable_task_queue_->SetFrameScheduler(nullptr);
-    suspendable_task_queue_->SetBlameContext(nullptr);
-  }
-
-  if (unthrottled_but_blockable_task_queue_) {
-    unthrottled_but_blockable_task_queue_->UnregisterTaskQueue();
-    unthrottled_but_blockable_task_queue_->SetFrameScheduler(nullptr);
-    unthrottled_but_blockable_task_queue_->SetBlameContext(nullptr);
-  }
+  CleanUpQueue(loading_task_queue_.get());
+  CleanUpQueue(loading_control_task_queue_.get());
+  CleanUpQueue(throttleable_task_queue_.get());
+  CleanUpQueue(deferrable_task_queue_.get());
+  CleanUpQueue(pausable_task_queue_.get());
+  CleanUpQueue(unpausable_task_queue_.get());
 
   if (parent_web_view_scheduler_) {
     parent_web_view_scheduler_->Unregister(this);
@@ -95,13 +79,14 @@
 }
 
 void WebFrameSchedulerImpl::DetachFromWebViewScheduler() {
-  RemoveTimerQueueFromBackgroundCPUTimeBudgetPool();
+  RemoveThrottleableQueueFromBackgroundCPUTimeBudgetPool();
 
   parent_web_view_scheduler_ = nullptr;
 }
 
-void WebFrameSchedulerImpl::RemoveTimerQueueFromBackgroundCPUTimeBudgetPool() {
-  if (!timer_task_queue_)
+void WebFrameSchedulerImpl::
+    RemoveThrottleableQueueFromBackgroundCPUTimeBudgetPool() {
+  if (!throttleable_task_queue_)
     return;
 
   if (!parent_web_view_scheduler_)
@@ -114,7 +99,7 @@
     return;
 
   time_budget_pool->RemoveQueue(renderer_scheduler_->tick_clock()->NowTicks(),
-                                timer_task_queue_.get());
+                                throttleable_task_queue_.get());
 }
 
 void WebFrameSchedulerImpl::AddThrottlingObserver(ObserverType type,
@@ -142,7 +127,7 @@
     return;
   bool was_throttled = ShouldThrottleTimers();
   frame_visible_ = frame_visible;
-  UpdateTimerThrottling(was_throttled);
+  UpdateThrottling(was_throttled);
 }
 
 void WebFrameSchedulerImpl::SetCrossOrigin(bool cross_origin) {
@@ -151,7 +136,7 @@
     return;
   bool was_throttled = ShouldThrottleTimers();
   cross_origin_ = cross_origin;
-  UpdateTimerThrottling(was_throttled);
+  UpdateThrottling(was_throttled);
 }
 
 RefPtr<blink::WebTaskRunner> WebFrameSchedulerImpl::LoadingTaskRunner() {
@@ -159,8 +144,8 @@
   if (!loading_web_task_runner_) {
     loading_task_queue_ = renderer_scheduler_->NewLoadingTaskQueue(
         MainThreadTaskQueue::QueueType::FRAME_LOADING);
-    loading_task_queue_->SetFrameScheduler(this);
     loading_task_queue_->SetBlameContext(blame_context_);
+    loading_task_queue_->SetFrameScheduler(this);
     loading_queue_enabled_voter_ =
         loading_task_queue_->CreateQueueEnabledVoter();
     loading_queue_enabled_voter_->SetQueueEnabled(!frame_paused_);
@@ -174,8 +159,8 @@
   if (!loading_control_web_task_runner_) {
     loading_control_task_queue_ = renderer_scheduler_->NewLoadingTaskQueue(
         MainThreadTaskQueue::QueueType::FRAME_LOADING_CONTROL);
-    loading_control_task_queue_->SetFrameScheduler(this);
     loading_control_task_queue_->SetBlameContext(blame_context_);
+    loading_control_task_queue_->SetFrameScheduler(this);
     loading_control_queue_enabled_voter_ =
         loading_control_task_queue_->CreateQueueEnabledVoter();
     loading_control_queue_enabled_voter_->SetQueueEnabled(!frame_paused_);
@@ -185,81 +170,90 @@
   return loading_control_web_task_runner_;
 }
 
-RefPtr<blink::WebTaskRunner> WebFrameSchedulerImpl::TimerTaskRunner() {
+RefPtr<blink::WebTaskRunner> WebFrameSchedulerImpl::ThrottleableTaskRunner() {
   DCHECK(parent_web_view_scheduler_);
-  if (!timer_web_task_runner_) {
-    timer_task_queue_ = renderer_scheduler_->NewTimerTaskQueue(
-        MainThreadTaskQueue::QueueType::FRAME_TIMER);
-    timer_task_queue_->SetFrameScheduler(this);
-    timer_task_queue_->SetBlameContext(blame_context_);
-    timer_queue_enabled_voter_ = timer_task_queue_->CreateQueueEnabledVoter();
-    timer_queue_enabled_voter_->SetQueueEnabled(!frame_paused_);
+  if (!throttleable_web_task_runner_) {
+    throttleable_task_queue_ = renderer_scheduler_->NewTaskQueue(
+        MainThreadTaskQueue::QueueCreationParams(
+            MainThreadTaskQueue::QueueType::FRAME_THROTTLEABLE)
+            .SetShouldReportWhenExecutionBlocked(true)
+            .SetCanBeThrottled(true)
+            .SetCanBeStopped(true)
+            .SetCanBeDeferred(true)
+            .SetCanBePaused(true));
+    throttleable_task_queue_->SetBlameContext(blame_context_);
+    throttleable_task_queue_->SetFrameScheduler(this);
+    throttleable_queue_enabled_voter_ =
+        throttleable_task_queue_->CreateQueueEnabledVoter();
+    throttleable_queue_enabled_voter_->SetQueueEnabled(!frame_paused_);
 
     CPUTimeBudgetPool* time_budget_pool =
         parent_web_view_scheduler_->BackgroundCPUTimeBudgetPool();
     if (time_budget_pool) {
       time_budget_pool->AddQueue(renderer_scheduler_->tick_clock()->NowTicks(),
-                                 timer_task_queue_.get());
+                                 throttleable_task_queue_.get());
     }
 
     if (ShouldThrottleTimers()) {
       renderer_scheduler_->task_queue_throttler()->IncreaseThrottleRefCount(
-          timer_task_queue_.get());
+          throttleable_task_queue_.get());
     }
-    timer_web_task_runner_ = WebTaskRunnerImpl::Create(timer_task_queue_);
+    throttleable_web_task_runner_ =
+        WebTaskRunnerImpl::Create(throttleable_task_queue_);
   }
-  return timer_web_task_runner_;
+  return throttleable_web_task_runner_;
 }
 
-RefPtr<blink::WebTaskRunner> WebFrameSchedulerImpl::SuspendableTaskRunner() {
+RefPtr<blink::WebTaskRunner> WebFrameSchedulerImpl::DeferrableTaskRunner() {
   DCHECK(parent_web_view_scheduler_);
-  if (!suspendable_web_task_runner_) {
-    // TODO(altimin): Split FRAME_UNTHROTTLED into FRAME_UNTHROTTLED and
-    // FRAME_UNSUSPENDED.
-    suspendable_task_queue_ = renderer_scheduler_->NewTaskQueue(
+  if (!deferrable_web_task_runner_) {
+    deferrable_task_queue_ = renderer_scheduler_->NewTaskQueue(
         MainThreadTaskQueue::QueueCreationParams(
-            MainThreadTaskQueue::QueueType::FRAME_UNTHROTTLED)
-            .SetCanBeBlocked(true)
+            MainThreadTaskQueue::QueueType::FRAME_THROTTLEABLE)
+            .SetShouldReportWhenExecutionBlocked(true)
+            .SetCanBeDeferred(true)
             .SetCanBePaused(true));
-    suspendable_task_queue_->SetFrameScheduler(this);
-    suspendable_task_queue_->SetBlameContext(blame_context_);
-    suspendable_web_task_runner_ =
-        WebTaskRunnerImpl::Create(suspendable_task_queue_);
-    suspendable_queue_enabled_voter_ =
-        suspendable_task_queue_->CreateQueueEnabledVoter();
-    suspendable_queue_enabled_voter_->SetQueueEnabled(!frame_paused_);
+    deferrable_task_queue_->SetBlameContext(blame_context_);
+    deferrable_task_queue_->SetFrameScheduler(this);
+    deferrable_web_task_runner_ =
+        WebTaskRunnerImpl::Create(deferrable_task_queue_);
+    deferrable_queue_enabled_voter_ =
+        deferrable_task_queue_->CreateQueueEnabledVoter();
+    deferrable_queue_enabled_voter_->SetQueueEnabled(!frame_paused_);
   }
-  return suspendable_web_task_runner_;
+  return deferrable_web_task_runner_;
 }
 
-RefPtr<blink::WebTaskRunner> WebFrameSchedulerImpl::UnthrottledTaskRunner() {
+RefPtr<blink::WebTaskRunner> WebFrameSchedulerImpl::PausableTaskRunner() {
   DCHECK(parent_web_view_scheduler_);
-  if (!unthrottled_web_task_runner_) {
-    unthrottled_task_queue_ = renderer_scheduler_->NewTaskQueue(
+  if (!pausable_web_task_runner_) {
+    pausable_task_queue_ = renderer_scheduler_->NewTaskQueue(
         MainThreadTaskQueue::QueueCreationParams(
-            MainThreadTaskQueue::QueueType::FRAME_UNTHROTTLED));
-    unthrottled_task_queue_->SetFrameScheduler(this);
-    unthrottled_task_queue_->SetBlameContext(blame_context_);
-    unthrottled_web_task_runner_ =
-        WebTaskRunnerImpl::Create(unthrottled_task_queue_);
+            MainThreadTaskQueue::QueueType::FRAME_PAUSABLE)
+            .SetShouldReportWhenExecutionBlocked(true)
+            .SetCanBePaused(true));
+    pausable_task_queue_->SetBlameContext(blame_context_);
+    pausable_task_queue_->SetFrameScheduler(this);
+    pausable_web_task_runner_ = WebTaskRunnerImpl::Create(pausable_task_queue_);
+    pausable_queue_enabled_voter_ =
+        pausable_task_queue_->CreateQueueEnabledVoter();
+    pausable_queue_enabled_voter_->SetQueueEnabled(!frame_paused_);
   }
-  return unthrottled_web_task_runner_;
+  return pausable_web_task_runner_;
 }
 
-RefPtr<blink::WebTaskRunner>
-WebFrameSchedulerImpl::UnthrottledButBlockableTaskRunner() {
+RefPtr<blink::WebTaskRunner> WebFrameSchedulerImpl::UnpausableTaskRunner() {
   DCHECK(parent_web_view_scheduler_);
-  if (!unthrottled_but_blockable_web_task_runner_) {
-    unthrottled_but_blockable_task_queue_ = renderer_scheduler_->NewTaskQueue(
+  if (!unpausable_web_task_runner_) {
+    unpausable_task_queue_ = renderer_scheduler_->NewTaskQueue(
         MainThreadTaskQueue::QueueCreationParams(
-            MainThreadTaskQueue::QueueType::FRAME_UNTHROTTLED)
-            .SetCanBeBlocked(true));
-    unthrottled_but_blockable_task_queue_->SetFrameScheduler(this);
-    unthrottled_but_blockable_task_queue_->SetBlameContext(blame_context_);
-    unthrottled_but_blockable_web_task_runner_ =
-        WebTaskRunnerImpl::Create(unthrottled_but_blockable_task_queue_);
+            MainThreadTaskQueue::QueueType::FRAME_UNPAUSABLE));
+    unpausable_task_queue_->SetBlameContext(blame_context_);
+    unpausable_task_queue_->SetFrameScheduler(this);
+    unpausable_web_task_runner_ =
+        WebTaskRunnerImpl::Create(unpausable_task_queue_);
   }
-  return unthrottled_but_blockable_web_task_runner_;
+  return unpausable_web_task_runner_;
 }
 
 blink::WebViewScheduler* WebFrameSchedulerImpl::GetWebViewScheduler() {
@@ -333,18 +327,23 @@
         "loading_control_task_queue",
         trace_helper::PointerToString(loading_control_task_queue_.get()));
   }
-  if (timer_task_queue_)
-    state->SetString("timer_task_queue",
-                     trace_helper::PointerToString(timer_task_queue_.get()));
-  if (unthrottled_task_queue_) {
+  if (throttleable_task_queue_)
     state->SetString(
-        "unthrottled_task_queue",
-        trace_helper::PointerToString(unthrottled_task_queue_.get()));
+        "throttleable_task_queue",
+        trace_helper::PointerToString(throttleable_task_queue_.get()));
+  if (deferrable_task_queue_) {
+    state->SetString(
+        "deferrable_task_queue",
+        trace_helper::PointerToString(deferrable_task_queue_.get()));
   }
-  if (suspendable_task_queue_) {
+  if (pausable_task_queue_) {
+    state->SetString("pausable_task_queue",
+                     trace_helper::PointerToString(pausable_task_queue_.get()));
+  }
+  if (unpausable_task_queue_) {
     state->SetString(
-        "suspendable_task_queue",
-        trace_helper::PointerToString(suspendable_task_queue_.get()));
+        "unpausable_task_queue",
+        trace_helper::PointerToString(unpausable_task_queue_.get()));
   }
   if (blame_context_) {
     state->BeginDictionary("blame_context");
@@ -362,7 +361,7 @@
     return;
   bool was_throttled = ShouldThrottleTimers();
   page_visible_ = page_visible;
-  UpdateTimerThrottling(was_throttled);
+  UpdateThrottling(was_throttled);
 
   for (auto observer : loader_observers_) {
     observer->OnThrottlingStateChanged(page_visible_
@@ -381,10 +380,12 @@
     loading_queue_enabled_voter_->SetQueueEnabled(!frame_paused);
   if (loading_control_queue_enabled_voter_)
     loading_control_queue_enabled_voter_->SetQueueEnabled(!frame_paused);
-  if (timer_queue_enabled_voter_)
-    timer_queue_enabled_voter_->SetQueueEnabled(!frame_paused);
-  if (suspendable_queue_enabled_voter_)
-    suspendable_queue_enabled_voter_->SetQueueEnabled(!frame_paused);
+  if (throttleable_queue_enabled_voter_)
+    throttleable_queue_enabled_voter_->SetQueueEnabled(!frame_paused);
+  if (deferrable_queue_enabled_voter_)
+    deferrable_queue_enabled_voter_->SetQueueEnabled(!frame_paused);
+  if (pausable_queue_enabled_voter_)
+    pausable_queue_enabled_voter_->SetQueueEnabled(!frame_paused);
 }
 
 void WebFrameSchedulerImpl::OnFirstMeaningfulPaint() {
@@ -404,16 +405,16 @@
          !frame_visible_ && cross_origin_;
 }
 
-void WebFrameSchedulerImpl::UpdateTimerThrottling(bool was_throttled) {
+void WebFrameSchedulerImpl::UpdateThrottling(bool was_throttled) {
   bool should_throttle = ShouldThrottleTimers();
-  if (was_throttled == should_throttle || !timer_web_task_runner_)
+  if (was_throttled == should_throttle || !throttleable_web_task_runner_)
     return;
   if (should_throttle) {
     renderer_scheduler_->task_queue_throttler()->IncreaseThrottleRefCount(
-        timer_task_queue_.get());
+        throttleable_task_queue_.get());
   } else {
     renderer_scheduler_->task_queue_throttler()->DecreaseThrottleRefCount(
-        timer_task_queue_.get());
+        throttleable_task_queue_.get());
   }
 }
 
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/web_frame_scheduler_impl.h b/third_party/WebKit/Source/platform/scheduler/renderer/web_frame_scheduler_impl.h
index b42f137..a746fd68 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/web_frame_scheduler_impl.h
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/web_frame_scheduler_impl.h
@@ -49,10 +49,10 @@
   void SetCrossOrigin(bool cross_origin) override;
   RefPtr<WebTaskRunner> LoadingTaskRunner() override;
   RefPtr<WebTaskRunner> LoadingControlTaskRunner() override;
-  RefPtr<WebTaskRunner> TimerTaskRunner() override;
-  RefPtr<WebTaskRunner> SuspendableTaskRunner() override;
-  RefPtr<WebTaskRunner> UnthrottledTaskRunner() override;
-  RefPtr<WebTaskRunner> UnthrottledButBlockableTaskRunner() override;
+  RefPtr<WebTaskRunner> ThrottleableTaskRunner() override;
+  RefPtr<WebTaskRunner> DeferrableTaskRunner() override;
+  RefPtr<WebTaskRunner> PausableTaskRunner() override;
+  RefPtr<WebTaskRunner> UnpausableTaskRunner() override;
   WebViewScheduler* GetWebViewScheduler() override;
   void WillNavigateBackForwardSoon() override;
   void DidStartProvisionalLoad(bool is_main_frame) override;
@@ -84,10 +84,10 @@
   };
 
   void DetachFromWebViewScheduler();
-  void RemoveTimerQueueFromBackgroundCPUTimeBudgetPool();
-  void ApplyPolicyToTimerQueue();
+  void RemoveThrottleableQueueFromBackgroundCPUTimeBudgetPool();
+  void ApplyPolicyToThrottleableQueue();
   bool ShouldThrottleTimers() const;
-  void UpdateTimerThrottling(bool was_throttled);
+  void UpdateThrottling(bool was_throttled);
 
   void DidOpenActiveConnection();
   void DidCloseActiveConnection();
@@ -96,22 +96,23 @@
 
   scoped_refptr<MainThreadTaskQueue> loading_task_queue_;
   scoped_refptr<MainThreadTaskQueue> loading_control_task_queue_;
-  scoped_refptr<MainThreadTaskQueue> timer_task_queue_;
-  scoped_refptr<MainThreadTaskQueue> unthrottled_task_queue_;
-  scoped_refptr<MainThreadTaskQueue> suspendable_task_queue_;
-  scoped_refptr<MainThreadTaskQueue> unthrottled_but_blockable_task_queue_;
+  scoped_refptr<MainThreadTaskQueue> throttleable_task_queue_;
+  scoped_refptr<MainThreadTaskQueue> deferrable_task_queue_;
+  scoped_refptr<MainThreadTaskQueue> pausable_task_queue_;
+  scoped_refptr<MainThreadTaskQueue> unpausable_task_queue_;
   std::unique_ptr<TaskQueue::QueueEnabledVoter> loading_queue_enabled_voter_;
   std::unique_ptr<TaskQueue::QueueEnabledVoter>
       loading_control_queue_enabled_voter_;
-  std::unique_ptr<TaskQueue::QueueEnabledVoter> timer_queue_enabled_voter_;
   std::unique_ptr<TaskQueue::QueueEnabledVoter>
-      suspendable_queue_enabled_voter_;
+      throttleable_queue_enabled_voter_;
+  std::unique_ptr<TaskQueue::QueueEnabledVoter> deferrable_queue_enabled_voter_;
+  std::unique_ptr<TaskQueue::QueueEnabledVoter> pausable_queue_enabled_voter_;
   RefPtr<WebTaskRunnerImpl> loading_web_task_runner_;
   RefPtr<WebTaskRunnerImpl> loading_control_web_task_runner_;
-  RefPtr<WebTaskRunnerImpl> timer_web_task_runner_;
-  RefPtr<WebTaskRunnerImpl> unthrottled_web_task_runner_;
-  RefPtr<WebTaskRunnerImpl> suspendable_web_task_runner_;
-  RefPtr<WebTaskRunnerImpl> unthrottled_but_blockable_web_task_runner_;
+  RefPtr<WebTaskRunnerImpl> throttleable_web_task_runner_;
+  RefPtr<WebTaskRunnerImpl> deferrable_web_task_runner_;
+  RefPtr<WebTaskRunnerImpl> pausable_web_task_runner_;
+  RefPtr<WebTaskRunnerImpl> unpausable_web_task_runner_;
   RendererSchedulerImpl* renderer_scheduler_;        // NOT OWNED
   WebViewSchedulerImpl* parent_web_view_scheduler_;  // NOT OWNED
   base::trace_event::BlameContext* blame_context_;   // NOT OWNED
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/web_frame_scheduler_impl_unittest.cc b/third_party/WebKit/Source/platform/scheduler/renderer/web_frame_scheduler_impl_unittest.cc
index 317cb4e..8d45dbd 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/web_frame_scheduler_impl_unittest.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/web_frame_scheduler_impl_unittest.cc
@@ -114,9 +114,10 @@
   RuntimeEnabledFeatures::SetTimerThrottlingForHiddenFramesEnabled(true);
 
   int run_count = 0;
-  web_frame_scheduler_->TimerTaskRunner()->PostDelayedTask(
+  web_frame_scheduler_->ThrottleableTaskRunner()->PostDelayedTask(
       BLINK_FROM_HERE,
-      MakeRepeatingTask(web_frame_scheduler_->TimerTaskRunner(), &run_count),
+      MakeRepeatingTask(web_frame_scheduler_->ThrottleableTaskRunner(),
+                        &run_count),
       TimeDelta::FromMilliseconds(1));
 
   mock_task_runner_->RunForPeriod(base::TimeDelta::FromSeconds(1));
@@ -128,9 +129,10 @@
   web_view_scheduler_->SetPageVisible(false);
 
   int run_count = 0;
-  web_frame_scheduler_->TimerTaskRunner()->PostDelayedTask(
+  web_frame_scheduler_->ThrottleableTaskRunner()->PostDelayedTask(
       BLINK_FROM_HERE,
-      MakeRepeatingTask(web_frame_scheduler_->TimerTaskRunner(), &run_count),
+      MakeRepeatingTask(web_frame_scheduler_->ThrottleableTaskRunner(),
+                        &run_count),
       TimeDelta::FromMilliseconds(1));
 
   mock_task_runner_->RunForPeriod(base::TimeDelta::FromSeconds(1));
@@ -142,9 +144,10 @@
   web_frame_scheduler_->SetFrameVisible(false);
 
   int run_count = 0;
-  web_frame_scheduler_->TimerTaskRunner()->PostDelayedTask(
+  web_frame_scheduler_->ThrottleableTaskRunner()->PostDelayedTask(
       BLINK_FROM_HERE,
-      MakeRepeatingTask(web_frame_scheduler_->TimerTaskRunner(), &run_count),
+      MakeRepeatingTask(web_frame_scheduler_->ThrottleableTaskRunner(),
+                        &run_count),
       TimeDelta::FromMilliseconds(1));
 
   mock_task_runner_->RunForPeriod(base::TimeDelta::FromSeconds(1));
@@ -157,9 +160,10 @@
   web_frame_scheduler_->SetCrossOrigin(true);
 
   int run_count = 0;
-  web_frame_scheduler_->TimerTaskRunner()->PostDelayedTask(
+  web_frame_scheduler_->ThrottleableTaskRunner()->PostDelayedTask(
       BLINK_FROM_HERE,
-      MakeRepeatingTask(web_frame_scheduler_->TimerTaskRunner(), &run_count),
+      MakeRepeatingTask(web_frame_scheduler_->ThrottleableTaskRunner(),
+                        &run_count),
       TimeDelta::FromMilliseconds(1));
 
   mock_task_runner_->RunForPeriod(base::TimeDelta::FromSeconds(1));
@@ -172,9 +176,10 @@
   web_frame_scheduler_->SetCrossOrigin(true);
 
   int run_count = 0;
-  web_frame_scheduler_->TimerTaskRunner()->PostDelayedTask(
+  web_frame_scheduler_->ThrottleableTaskRunner()->PostDelayedTask(
       BLINK_FROM_HERE,
-      MakeRepeatingTask(web_frame_scheduler_->TimerTaskRunner(), &run_count),
+      MakeRepeatingTask(web_frame_scheduler_->ThrottleableTaskRunner(),
+                        &run_count),
       TimeDelta::FromMilliseconds(1));
 
   mock_task_runner_->RunForPeriod(base::TimeDelta::FromSeconds(1));
@@ -186,9 +191,10 @@
   web_view_scheduler_->SetPageVisible(false);
 
   int run_count = 0;
-  web_frame_scheduler_->TimerTaskRunner()->PostDelayedTask(
+  web_frame_scheduler_->ThrottleableTaskRunner()->PostDelayedTask(
       BLINK_FROM_HERE,
-      MakeRepeatingTask(web_frame_scheduler_->TimerTaskRunner(), &run_count),
+      MakeRepeatingTask(web_frame_scheduler_->ThrottleableTaskRunner(),
+                        &run_count),
       TimeDelta::FromMilliseconds(1));
 
   mock_task_runner_->RunForPeriod(base::TimeDelta::FromSeconds(1));
@@ -202,9 +208,10 @@
   web_frame_scheduler_->SetCrossOrigin(true);
 
   int run_count = 0;
-  web_frame_scheduler_->TimerTaskRunner()->PostDelayedTask(
+  web_frame_scheduler_->ThrottleableTaskRunner()->PostDelayedTask(
       BLINK_FROM_HERE,
-      MakeRepeatingTask(web_frame_scheduler_->TimerTaskRunner(), &run_count),
+      MakeRepeatingTask(web_frame_scheduler_->ThrottleableTaskRunner(),
+                        &run_count),
       TimeDelta::FromMilliseconds(1));
 
   mock_task_runner_->RunForPeriod(base::TimeDelta::FromSeconds(1));
@@ -215,24 +222,24 @@
   int counter = 0;
   web_frame_scheduler_->LoadingTaskRunner()->PostTask(
       BLINK_FROM_HERE, WTF::Bind(&IncrementCounter, WTF::Unretained(&counter)));
-  web_frame_scheduler_->TimerTaskRunner()->PostTask(
+  web_frame_scheduler_->ThrottleableTaskRunner()->PostTask(
       BLINK_FROM_HERE, WTF::Bind(&IncrementCounter, WTF::Unretained(&counter)));
-  web_frame_scheduler_->UnthrottledTaskRunner()->PostTask(
+  web_frame_scheduler_->DeferrableTaskRunner()->PostTask(
       BLINK_FROM_HERE, WTF::Bind(&IncrementCounter, WTF::Unretained(&counter)));
-  web_frame_scheduler_->SuspendableTaskRunner()->PostTask(
+  web_frame_scheduler_->PausableTaskRunner()->PostTask(
       BLINK_FROM_HERE, WTF::Bind(&IncrementCounter, WTF::Unretained(&counter)));
-  web_frame_scheduler_->UnthrottledButBlockableTaskRunner()->PostTask(
+  web_frame_scheduler_->UnpausableTaskRunner()->PostTask(
       BLINK_FROM_HERE, WTF::Bind(&IncrementCounter, WTF::Unretained(&counter)));
 
   web_frame_scheduler_->SetPaused(true);
 
   EXPECT_EQ(0, counter);
   mock_task_runner_->RunUntilIdle();
-  EXPECT_EQ(2, counter);
+  EXPECT_EQ(1, counter);
 
   web_frame_scheduler_->SetPaused(false);
 
-  EXPECT_EQ(2, counter);
+  EXPECT_EQ(1, counter);
   mock_task_runner_->RunUntilIdle();
   EXPECT_EQ(5, counter);
 }
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler_impl_unittest.cc b/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler_impl_unittest.cc
index 740300a..e16411b8 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler_impl_unittest.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler_impl_unittest.cc
@@ -106,9 +106,10 @@
   web_view_scheduler_->SetPageVisible(true);
 
   int run_count = 0;
-  web_frame_scheduler_->TimerTaskRunner()->PostDelayedTask(
+  web_frame_scheduler_->ThrottleableTaskRunner()->PostDelayedTask(
       BLINK_FROM_HERE,
-      MakeRepeatingTask(web_frame_scheduler_->TimerTaskRunner(), &run_count),
+      MakeRepeatingTask(web_frame_scheduler_->ThrottleableTaskRunner(),
+                        &run_count),
       TimeDelta::FromMilliseconds(1));
 
   mock_task_runner_->RunForPeriod(base::TimeDelta::FromSeconds(1));
@@ -120,9 +121,10 @@
   web_view_scheduler_->SetPageVisible(false);
 
   int run_count = 0;
-  web_frame_scheduler_->TimerTaskRunner()->PostDelayedTask(
+  web_frame_scheduler_->ThrottleableTaskRunner()->PostDelayedTask(
       BLINK_FROM_HERE,
-      MakeRepeatingTask(web_frame_scheduler_->TimerTaskRunner(), &run_count),
+      MakeRepeatingTask(web_frame_scheduler_->ThrottleableTaskRunner(),
+                        &run_count),
       TimeDelta::FromMilliseconds(1));
 
   mock_task_runner_->RunForPeriod(base::TimeDelta::FromSeconds(1));
@@ -163,13 +165,15 @@
 
   int run_count1 = 0;
   int run_count2 = 0;
-  web_frame_scheduler_->TimerTaskRunner()->PostDelayedTask(
+  web_frame_scheduler_->ThrottleableTaskRunner()->PostDelayedTask(
       BLINK_FROM_HERE,
-      MakeRepeatingTask(web_frame_scheduler_->TimerTaskRunner(), &run_count1),
+      MakeRepeatingTask(web_frame_scheduler_->ThrottleableTaskRunner(),
+                        &run_count1),
       TimeDelta::FromMilliseconds(1));
-  web_frame_scheduler2->TimerTaskRunner()->PostDelayedTask(
+  web_frame_scheduler2->ThrottleableTaskRunner()->PostDelayedTask(
       BLINK_FROM_HERE,
-      MakeRepeatingTask(web_frame_scheduler2->TimerTaskRunner(), &run_count2),
+      MakeRepeatingTask(web_frame_scheduler2->ThrottleableTaskRunner(),
+                        &run_count2),
       TimeDelta::FromMilliseconds(1));
 
   mock_task_runner_->RunForPeriod(base::TimeDelta::FromSeconds(1));
@@ -205,31 +209,31 @@
   std::vector<size_t> virtual_times_ms;
   base::TimeTicks initial_real_time = scheduler_->tick_clock()->NowTicks();
   size_t initial_virtual_time_ms =
-      web_frame_scheduler_->TimerTaskRunner()
+      web_frame_scheduler_->ThrottleableTaskRunner()
           ->MonotonicallyIncreasingVirtualTimeSeconds() *
       1000.0;
 
   web_view_scheduler_->EnableVirtualTime();
 
-  web_frame_scheduler_->TimerTaskRunner()->PostDelayedTask(
+  web_frame_scheduler_->ThrottleableTaskRunner()->PostDelayedTask(
       BLINK_FROM_HERE,
-      MakeVirtualTimeRecorderTask(clock_.get(),
-                                  web_frame_scheduler_->TimerTaskRunner(),
-                                  &real_times, &virtual_times_ms),
+      MakeVirtualTimeRecorderTask(
+          clock_.get(), web_frame_scheduler_->ThrottleableTaskRunner(),
+          &real_times, &virtual_times_ms),
       TimeDelta::FromMilliseconds(2));
 
-  web_frame_scheduler_->TimerTaskRunner()->PostDelayedTask(
+  web_frame_scheduler_->ThrottleableTaskRunner()->PostDelayedTask(
       BLINK_FROM_HERE,
-      MakeVirtualTimeRecorderTask(clock_.get(),
-                                  web_frame_scheduler_->TimerTaskRunner(),
-                                  &real_times, &virtual_times_ms),
+      MakeVirtualTimeRecorderTask(
+          clock_.get(), web_frame_scheduler_->ThrottleableTaskRunner(),
+          &real_times, &virtual_times_ms),
       TimeDelta::FromMilliseconds(20));
 
-  web_frame_scheduler_->TimerTaskRunner()->PostDelayedTask(
+  web_frame_scheduler_->ThrottleableTaskRunner()->PostDelayedTask(
       BLINK_FROM_HERE,
-      MakeVirtualTimeRecorderTask(clock_.get(),
-                                  web_frame_scheduler_->TimerTaskRunner(),
-                                  &real_times, &virtual_times_ms),
+      MakeVirtualTimeRecorderTask(
+          clock_.get(), web_frame_scheduler_->ThrottleableTaskRunner(),
+          &real_times, &virtual_times_ms),
       TimeDelta::FromMilliseconds(200));
 
   mock_task_runner_->RunUntilIdle();
@@ -246,7 +250,7 @@
   std::vector<size_t> virtual_times_ms;
   base::TimeTicks initial_real_time = scheduler_->tick_clock()->NowTicks();
   size_t initial_virtual_time_ms =
-      web_frame_scheduler_->TimerTaskRunner()
+      web_frame_scheduler_->ThrottleableTaskRunner()
           ->MonotonicallyIncreasingVirtualTimeSeconds() *
       1000.0;
 
@@ -289,9 +293,10 @@
   base::TimeTicks initial_real_time = scheduler_->tick_clock()->NowTicks();
 
   int run_count = 0;
-  web_frame_scheduler_->TimerTaskRunner()->PostDelayedTask(
+  web_frame_scheduler_->ThrottleableTaskRunner()->PostDelayedTask(
       BLINK_FROM_HERE,
-      MakeRepeatingTask(web_frame_scheduler_->TimerTaskRunner(), &run_count),
+      MakeRepeatingTask(web_frame_scheduler_->ThrottleableTaskRunner(),
+                        &run_count),
       TimeDelta::FromMilliseconds(1));
 
   mock_task_runner_->RunTasksWhile(mock_task_runner_->TaskRunCountBelow(2000));
@@ -325,21 +330,21 @@
   web_view_scheduler_->SetVirtualTimePolicy(VirtualTimePolicy::PAUSE);
   web_view_scheduler_->EnableVirtualTime();
 
-  web_frame_scheduler_->TimerTaskRunner()->PostTask(
+  web_frame_scheduler_->ThrottleableTaskRunner()->PostTask(
       BLINK_FROM_HERE,
       WTF::Bind(&RunOrderTask, 0, WTF::Unretained(&run_order)));
 
-  web_frame_scheduler_->TimerTaskRunner()->PostDelayedTask(
+  web_frame_scheduler_->ThrottleableTaskRunner()->PostDelayedTask(
       BLINK_FROM_HERE,
       WTF::Bind(&DelayedRunOrderTask, 1,
-                WTF::Passed(web_frame_scheduler_->TimerTaskRunner()),
+                WTF::Passed(web_frame_scheduler_->ThrottleableTaskRunner()),
                 WTF::Unretained(&run_order)),
       TimeDelta::FromMilliseconds(2));
 
-  web_frame_scheduler_->TimerTaskRunner()->PostDelayedTask(
+  web_frame_scheduler_->ThrottleableTaskRunner()->PostDelayedTask(
       BLINK_FROM_HERE,
       WTF::Bind(&DelayedRunOrderTask, 3,
-                WTF::Passed(web_frame_scheduler_->TimerTaskRunner()),
+                WTF::Passed(web_frame_scheduler_->ThrottleableTaskRunner()),
                 WTF::Unretained(&run_order)),
       TimeDelta::FromMilliseconds(4));
 
@@ -355,21 +360,21 @@
   web_view_scheduler_->SetVirtualTimePolicy(VirtualTimePolicy::ADVANCE);
   web_view_scheduler_->EnableVirtualTime();
 
-  web_frame_scheduler_->TimerTaskRunner()->PostTask(
+  web_frame_scheduler_->ThrottleableTaskRunner()->PostTask(
       BLINK_FROM_HERE,
       WTF::Bind(&RunOrderTask, 0, WTF::Unretained(&run_order)));
 
-  web_frame_scheduler_->TimerTaskRunner()->PostDelayedTask(
+  web_frame_scheduler_->ThrottleableTaskRunner()->PostDelayedTask(
       BLINK_FROM_HERE,
       WTF::Bind(&DelayedRunOrderTask, 1,
-                WTF::Passed(web_frame_scheduler_->TimerTaskRunner()),
+                WTF::Passed(web_frame_scheduler_->ThrottleableTaskRunner()),
                 WTF::Unretained(&run_order)),
       TimeDelta::FromMilliseconds(2));
 
-  web_frame_scheduler_->TimerTaskRunner()->PostDelayedTask(
+  web_frame_scheduler_->ThrottleableTaskRunner()->PostDelayedTask(
       BLINK_FROM_HERE,
       WTF::Bind(&DelayedRunOrderTask, 3,
-                WTF::Passed(web_frame_scheduler_->TimerTaskRunner()),
+                WTF::Passed(web_frame_scheduler_->ThrottleableTaskRunner()),
                 WTF::Unretained(&run_order)),
       TimeDelta::FromMilliseconds(4));
 
@@ -392,9 +397,10 @@
   web_view_scheduler_->SetPageVisible(false);
 
   int run_count = 0;
-  web_frame_scheduler_->TimerTaskRunner()->PostDelayedTask(
+  web_frame_scheduler_->ThrottleableTaskRunner()->PostDelayedTask(
       BLINK_FROM_HERE,
-      MakeRepeatingTask(web_frame_scheduler_->TimerTaskRunner(), &run_count),
+      MakeRepeatingTask(web_frame_scheduler_->ThrottleableTaskRunner(),
+                        &run_count),
       TimeDelta::FromMilliseconds(1));
 
   mock_task_runner_->RunForPeriod(base::TimeDelta::FromSeconds(1));
@@ -410,7 +416,7 @@
   std::unique_ptr<WebFrameSchedulerImpl> web_frame_scheduler =
       web_view_scheduler_->CreateWebFrameSchedulerImpl(nullptr);
 
-  web_frame_scheduler->TimerTaskRunner()->PostDelayedTask(
+  web_frame_scheduler->ThrottleableTaskRunner()->PostDelayedTask(
       BLINK_FROM_HERE, WTF::Bind(&RunOrderTask, 1, WTF::Unretained(&run_order)),
       TimeDelta::FromMilliseconds(1));
 
@@ -436,7 +442,7 @@
   for (int i = 0; i < 10; i++) {
     WebFrameSchedulerImpl* web_frame_scheduler =
         web_view_scheduler_->CreateWebFrameSchedulerImpl(nullptr).release();
-    web_frame_scheduler->TimerTaskRunner()->PostDelayedTask(
+    web_frame_scheduler->ThrottleableTaskRunner()->PostDelayedTask(
         BLINK_FROM_HERE, MakeDeletionTask(web_frame_scheduler),
         TimeDelta::FromMilliseconds(1));
   }
@@ -444,7 +450,7 @@
 }
 
 TEST_F(WebViewSchedulerImplTest, DeleteWebViewScheduler_InTask) {
-  web_frame_scheduler_->TimerTaskRunner()->PostTask(
+  web_frame_scheduler_->ThrottleableTaskRunner()->PostTask(
       BLINK_FROM_HERE, MakeDeletionTask(web_view_scheduler_.release()));
   mock_task_runner_->RunUntilIdle();
 }
@@ -455,7 +461,7 @@
   WebFrameSchedulerImpl* web_frame_scheduler =
       web_view_scheduler_->CreateWebFrameSchedulerImpl(nullptr).release();
   RefPtr<blink::WebTaskRunner> timer_task_runner =
-      web_frame_scheduler->TimerTaskRunner();
+      web_frame_scheduler->ThrottleableTaskRunner();
 
   int run_count = 0;
   timer_task_runner->PostDelayedTask(
@@ -616,7 +622,7 @@
   web_view_scheduler_->SetVirtualTimePolicy(VirtualTimePolicy::PAUSE);
   web_view_scheduler_->EnableVirtualTime();
 
-  web_frame_scheduler->TimerTaskRunner()->PostTask(
+  web_frame_scheduler->ThrottleableTaskRunner()->PostTask(
       BLINK_FROM_HERE,
       WTF::Bind(&RunOrderTask, 1, WTF::Unretained(&run_order)));
 
@@ -634,38 +640,38 @@
   std::vector<size_t> virtual_times_ms;
   base::TimeTicks initial_real_time = scheduler_->tick_clock()->NowTicks();
   size_t initial_virtual_time_ms =
-      web_frame_scheduler_->TimerTaskRunner()
+      web_frame_scheduler_->ThrottleableTaskRunner()
           ->MonotonicallyIncreasingVirtualTimeSeconds() *
       1000.0;
 
   web_view_scheduler_->EnableVirtualTime();
 
-  web_frame_scheduler_->TimerTaskRunner()->PostDelayedTask(
+  web_frame_scheduler_->ThrottleableTaskRunner()->PostDelayedTask(
       BLINK_FROM_HERE,
-      MakeVirtualTimeRecorderTask(clock_.get(),
-                                  web_frame_scheduler_->TimerTaskRunner(),
-                                  &real_times, &virtual_times_ms),
+      MakeVirtualTimeRecorderTask(
+          clock_.get(), web_frame_scheduler_->ThrottleableTaskRunner(),
+          &real_times, &virtual_times_ms),
       TimeDelta::FromMilliseconds(1));
 
-  web_frame_scheduler_->TimerTaskRunner()->PostDelayedTask(
+  web_frame_scheduler_->ThrottleableTaskRunner()->PostDelayedTask(
       BLINK_FROM_HERE,
-      MakeVirtualTimeRecorderTask(clock_.get(),
-                                  web_frame_scheduler_->TimerTaskRunner(),
-                                  &real_times, &virtual_times_ms),
+      MakeVirtualTimeRecorderTask(
+          clock_.get(), web_frame_scheduler_->ThrottleableTaskRunner(),
+          &real_times, &virtual_times_ms),
       TimeDelta::FromMilliseconds(2));
 
-  web_frame_scheduler_->TimerTaskRunner()->PostDelayedTask(
+  web_frame_scheduler_->ThrottleableTaskRunner()->PostDelayedTask(
       BLINK_FROM_HERE,
-      MakeVirtualTimeRecorderTask(clock_.get(),
-                                  web_frame_scheduler_->TimerTaskRunner(),
-                                  &real_times, &virtual_times_ms),
+      MakeVirtualTimeRecorderTask(
+          clock_.get(), web_frame_scheduler_->ThrottleableTaskRunner(),
+          &real_times, &virtual_times_ms),
       TimeDelta::FromMilliseconds(5));
 
-  web_frame_scheduler_->TimerTaskRunner()->PostDelayedTask(
+  web_frame_scheduler_->ThrottleableTaskRunner()->PostDelayedTask(
       BLINK_FROM_HERE,
-      MakeVirtualTimeRecorderTask(clock_.get(),
-                                  web_frame_scheduler_->TimerTaskRunner(),
-                                  &real_times, &virtual_times_ms),
+      MakeVirtualTimeRecorderTask(
+          clock_.get(), web_frame_scheduler_->ThrottleableTaskRunner(),
+          &real_times, &virtual_times_ms),
       TimeDelta::FromMilliseconds(7));
 
   web_view_scheduler_->GrantVirtualTimeBudget(
@@ -735,13 +741,13 @@
   mock_task_runner_->RunUntilTime(base::TimeTicks() +
                                   base::TimeDelta::FromMilliseconds(2500));
 
-  web_frame_scheduler_->TimerTaskRunner()
+  web_frame_scheduler_->ThrottleableTaskRunner()
       ->ToSingleThreadTaskRunner()
       ->PostDelayedTask(
           BLINK_FROM_HERE,
           base::Bind(&ExpensiveTestTask, clock_.get(), &run_times),
           TimeDelta::FromMilliseconds(1));
-  web_frame_scheduler_->TimerTaskRunner()
+  web_frame_scheduler_->ThrottleableTaskRunner()
       ->ToSingleThreadTaskRunner()
       ->PostDelayedTask(
           BLINK_FROM_HERE,
@@ -761,13 +767,13 @@
 
   web_view_scheduler_->SetPageVisible(false);
 
-  web_frame_scheduler_->TimerTaskRunner()
+  web_frame_scheduler_->ThrottleableTaskRunner()
       ->ToSingleThreadTaskRunner()
       ->PostDelayedTask(
           BLINK_FROM_HERE,
           base::Bind(&ExpensiveTestTask, clock_.get(), &run_times),
           TimeDelta::FromMicroseconds(1));
-  web_frame_scheduler_->TimerTaskRunner()
+  web_frame_scheduler_->ThrottleableTaskRunner()
       ->ToSingleThreadTaskRunner()
       ->PostDelayedTask(
           BLINK_FROM_HERE,
@@ -809,7 +815,7 @@
                                   base::TimeDelta::FromMilliseconds(20500));
 
   for (size_t i = 0; i < 3; ++i) {
-    web_frame_scheduler1->TimerTaskRunner()
+    web_frame_scheduler1->ThrottleableTaskRunner()
         ->ToSingleThreadTaskRunner()
         ->PostDelayedTask(
             BLINK_FROM_HERE,
@@ -832,7 +838,7 @@
       websocket_connection = web_frame_scheduler1->OnActiveConnectionCreated();
 
   for (size_t i = 0; i < 3; ++i) {
-    web_frame_scheduler1->TimerTaskRunner()
+    web_frame_scheduler1->ThrottleableTaskRunner()
         ->ToSingleThreadTaskRunner()
         ->PostDelayedTask(
             BLINK_FROM_HERE,
@@ -854,7 +860,7 @@
   run_times.clear();
 
   for (size_t i = 0; i < 3; ++i) {
-    web_frame_scheduler2->TimerTaskRunner()
+    web_frame_scheduler2->ThrottleableTaskRunner()
         ->ToSingleThreadTaskRunner()
         ->PostDelayedTask(
             BLINK_FROM_HERE,
@@ -881,7 +887,7 @@
                                   base::TimeDelta::FromMilliseconds(70500));
 
   for (size_t i = 0; i < 3; ++i) {
-    web_frame_scheduler1->TimerTaskRunner()
+    web_frame_scheduler1->ThrottleableTaskRunner()
         ->ToSingleThreadTaskRunner()
         ->PostDelayedTask(
             BLINK_FROM_HERE,
diff --git a/third_party/WebKit/public/platform/WebImageGenerator.h b/third_party/WebKit/public/platform/WebImageGenerator.h
index bd6144ef..499cff8b 100644
--- a/third_party/WebKit/public/platform/WebImageGenerator.h
+++ b/third_party/WebKit/public/platform/WebImageGenerator.h
@@ -41,7 +41,8 @@
 
 class BLINK_PLATFORM_EXPORT WebImageGenerator {
  public:
-  static std::unique_ptr<SkImageGenerator> Create(sk_sp<SkData>);
+  static std::unique_ptr<SkImageGenerator> CreateAsSkImageGenerator(
+      sk_sp<SkData>);
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/public/platform/WebLayer.h b/third_party/WebKit/public/platform/WebLayer.h
index b9886a2..92ae802 100644
--- a/third_party/WebKit/public/platform/WebLayer.h
+++ b/third_party/WebKit/public/platform/WebLayer.h
@@ -172,6 +172,8 @@
   // bounds.
   virtual void SetScrollable(const WebSize& scroll_container_bounds) = 0;
   virtual bool Scrollable() const = 0;
+  virtual WebSize ScrollContainerBoundsForTesting() const = 0;
+
   virtual void SetUserScrollable(bool horizontal, bool vertical) = 0;
   virtual bool UserScrollableHorizontal() const = 0;
   virtual bool UserScrollableVertical() const = 0;
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index eecc71d..998f262 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -39521,6 +39521,7 @@
   <int value="7" label="Download permission was suppressed in VR"/>
   <int value="8" label="File access permission was suppressed in VR"/>
   <int value="9" label="Password manager was disabled in VR"/>
+  <int value="10" label="Autofill was disabled in VR"/>
 </enum>
 
 <enum name="VRUnsupportedMode">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 51c2a0e..54b6916 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -28248,30 +28248,6 @@
   </summary>
 </histogram>
 
-<histogram name="InterProcessTimeTicks.BrowserAhead" units="ms">
-  <owner>ppi@chromium.org</owner>
-  <summary>
-    Estimated additive skew between processes, recorded if the browser process
-    is ahead (higher TimeTicks value) than the renderer process.
-  </summary>
-</histogram>
-
-<histogram name="InterProcessTimeTicks.BrowserBehind" units="ms">
-  <owner>ppi@chromium.org</owner>
-  <summary>
-    Estimated additive skew between processes, recorded if the browser process
-    is behind (lower TimeTicks value) than the renderer process.
-  </summary>
-</histogram>
-
-<histogram name="InterProcessTimeTicks.IsSkewAdditive" enum="Boolean">
-  <owner>ppi@chromium.org</owner>
-  <summary>
-    True iff the conversion from the browser process TimeTicks to renderer
-    process TimeTicks is done by adding a constant, without scaling.
-  </summary>
-</histogram>
-
 <histogram name="interstitial.authority_invalid_time" units="ms">
   <obsolete>
     Removed on 8/1/13.
@@ -95445,15 +95421,6 @@
   <affected-histogram name="Startup.FirstCommitNavigationTime3"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="InterProcessTimeTicksConversionType" separator="_">
-  <owner>ppi@chromium.org</owner>
-  <suffix name="BrowserToRenderer"/>
-  <suffix name="RendererToBrowser"/>
-  <affected-histogram name="InterProcessTimeTicks.BrowserAhead"/>
-  <affected-histogram name="InterProcessTimeTicks.BrowserBehind"/>
-  <affected-histogram name="InterProcessTimeTicks.IsSkewAdditive"/>
-</histogram_suffixes>
-
 <histogram_suffixes name="Interval" separator="_">
   <obsolete>
     Removed 10/2016.
diff --git a/tools/metrics/ukm/ukm.xml b/tools/metrics/ukm/ukm.xml
index 478a0168..87022da 100644
--- a/tools/metrics/ukm/ukm.xml
+++ b/tools/metrics/ukm/ukm.xml
@@ -1117,25 +1117,6 @@
   </metric>
 </event>
 
-<event name="TabManager.Background.FirstAlertFired">
-  <owner>chrisha@chromium.org</owner>
-  <owner>lpy@chromium.org</owner>
-  <summary>
-    Collects the duration in MS from when the tab is backgrounded to when a
-    JavaScript alert is fired. Only recorded when the tab is in the background.
-  </summary>
-  <metric name="IsMainFrame">
-    <summary>
-      Indicates whether the alert is fired from main frame.
-    </summary>
-  </metric>
-  <metric name="TimeFromBackgrounded">
-    <summary>
-      Duration in MS from when the tab is backgrounded to when alert is fired.
-    </summary>
-  </metric>
-</event>
-
 <event name="TabManager.Background.FirstAudioStarts">
   <owner>chrisha@chromium.org</owner>
   <owner>lpy@chromium.org</owner>
@@ -1145,60 +1126,13 @@
   </summary>
   <metric name="IsMainFrame">
     <summary>
-      Indicates whether the audio stream belongs to the main frame.
+      Indicates whether the the audio stream belongs to the main frame.
     </summary>
   </metric>
   <metric name="TimeFromBackgrounded">
     <summary>
       Duration in MS from when the tab is backgrounded to when audio starts to
-      play.
-    </summary>
-  </metric>
-</event>
-
-<event name="TabManager.Background.FirstFaviconUpdated">
-  <owner>chrisha@chromium.org</owner>
-  <owner>lpy@chromium.org</owner>
-  <summary>
-    Collects the duration in MS from when the tab is backgrounded to when the
-    favicon is updated. Only recorded when the tab is in the background.
-  </summary>
-  <metric name="TimeFromBackgrounded">
-    <summary>
-      Duration in MS from when the tab is backgrounded to when the favicon is
-      updated.
-    </summary>
-  </metric>
-</event>
-
-<event name="TabManager.Background.FirstNonPersistentNotificationCreated">
-  <owner>chrisha@chromium.org</owner>
-  <owner>lpy@chromium.org</owner>
-  <summary/>
-  <metric name="IsMainFrame">
-    <summary>
-      Indicates whether the notification creation is from the main frame.
-    </summary>
-  </metric>
-  <metric name="TimeFromBackgrounded">
-    <summary>
-      Duration in MS from when the tab is backgrounded to when a non-persistent
-      notification is created.
-    </summary>
-  </metric>
-</event>
-
-<event name="TabManager.Background.FirstTitleUpdated">
-  <owner>chrisha@chromium.org</owner>
-  <owner>lpy@chromium.org</owner>
-  <summary>
-    Collects the duration in MS from when the tab is backgrounded to when the
-    title is updated. Only recorded when the tab is in the background.
-  </summary>
-  <metric name="TimeFromBackgrounded">
-    <summary>
-      Duration in MS from when the tab is backgrounded to when the title is
-      updated.
+      play. Only recorded when the tab is in the background.
     </summary>
   </metric>
 </event>