diff --git a/DEPS b/DEPS
index 8e3b345..5a382742e 100644
--- a/DEPS
+++ b/DEPS
@@ -63,7 +63,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': '92b9b498543f7bb6d07fdf18bf8f1f479c57d89a',
+  'v8_revision': 'f91116b5220f3e4a5cbe0904b3d70f4176f70182',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -605,7 +605,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '34842fa3c36988840c89f5bc6a68503175acf7d9',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '449d295d1a4e974285f46ab86f3ce099ea586e4f', # commit position 20528
+    Var('webrtc_git') + '/src.git' + '@' + '868607710204d8a249290531a2efde1ef4362a0e', # commit position 20528
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
diff --git a/ash/message_center/message_center_button_bar.cc b/ash/message_center/message_center_button_bar.cc
index 699136e..ecb6da0 100644
--- a/ash/message_center/message_center_button_bar.cc
+++ b/ash/message_center/message_center_button_bar.cc
@@ -35,7 +35,6 @@
 #include "ui/views/painter.h"
 
 using message_center::MessageCenter;
-using message_center::NotifierSettingsProvider;
 
 namespace ash {
 
@@ -72,7 +71,6 @@
 MessageCenterButtonBar::MessageCenterButtonBar(
     MessageCenterView* message_center_view,
     MessageCenter* message_center,
-    NotifierSettingsProvider* notifier_settings_provider,
     bool settings_initially_visible,
     const base::string16& title)
     : message_center_view_(message_center_view),
diff --git a/ash/message_center/message_center_button_bar.h b/ash/message_center/message_center_button_bar.h
index 895e382..5ae8afd 100644
--- a/ash/message_center/message_center_button_bar.h
+++ b/ash/message_center/message_center_button_bar.h
@@ -18,7 +18,6 @@
 
 namespace message_center {
 class MessageCenter;
-class NotifierSettingsProvider;
 }  // namespace message_center
 
 namespace ash {
@@ -33,7 +32,6 @@
   MessageCenterButtonBar(
       MessageCenterView* message_center_view,
       message_center::MessageCenter* message_center,
-      message_center::NotifierSettingsProvider* notifier_settings_provider,
       bool settings_initially_visible,
       const base::string16& title);
   ~MessageCenterButtonBar() override;
diff --git a/ash/message_center/message_center_controller.cc b/ash/message_center/message_center_controller.cc
index fed90368..3451c48 100644
--- a/ash/message_center/message_center_controller.cc
+++ b/ash/message_center/message_center_controller.cc
@@ -6,8 +6,10 @@
 
 #include "ui/message_center/message_center.h"
 #include "ui/message_center/notification_delegate.h"
+#include "ui/message_center/notifier_settings.h"
 
 using message_center::MessageCenter;
+using message_center::NotifierId;
 
 namespace ash {
 
@@ -58,6 +60,16 @@
   binding_.Bind(std::move(request));
 }
 
+void MessageCenterController::SetNotifierEnabled(const NotifierId& notifier_id,
+                                                 bool enabled) {
+  client_->SetNotifierEnabled(notifier_id, enabled);
+}
+
+void MessageCenterController::OnNotifierAdvancedSettingsRequested(
+    const NotifierId& notifier_id) {
+  client_->HandleNotifierAdvancedSettingsRequested(notifier_id);
+}
+
 void MessageCenterController::SetClient(
     mojom::AshMessageCenterClientAssociatedPtrInfo client) {
   DCHECK(!client_.is_bound());
@@ -74,4 +86,35 @@
   MessageCenter::Get()->AddNotification(std::move(message_center_notification));
 }
 
+void MessageCenterController::UpdateNotifierIcon(const NotifierId& notifier_id,
+                                                 const gfx::ImageSkia& icon) {
+  if (notifier_settings_)
+    notifier_settings_->UpdateNotifierIcon(notifier_id, icon);
+}
+
+void MessageCenterController::NotifierEnabledChanged(
+    const NotifierId& notifier_id,
+    bool enabled) {
+  if (!enabled)
+    MessageCenter::Get()->RemoveNotificationsForNotifierId(notifier_id);
+}
+
+void MessageCenterController::SetNotifierSettingsListener(
+    NotifierSettingsListener* listener) {
+  DCHECK(!listener || !notifier_settings_);
+  notifier_settings_ = listener;
+
+  // |client_| may not be bound in unit tests.
+  if (listener && client_.is_bound()) {
+    client_->GetNotifierList(base::BindOnce(
+        &MessageCenterController::OnGotNotifierList, base::Unretained(this)));
+  }
+}
+
+void MessageCenterController::OnGotNotifierList(
+    std::vector<mojom::NotifierUiDataPtr> ui_data) {
+  if (notifier_settings_)
+    notifier_settings_->SetNotifierList(ui_data);
+}
+
 }  // namespace ash
diff --git a/ash/message_center/message_center_controller.h b/ash/message_center/message_center_controller.h
index 476d4b05..c08a068 100644
--- a/ash/message_center/message_center_controller.h
+++ b/ash/message_center/message_center_controller.h
@@ -5,6 +5,7 @@
 #ifndef ASH_MESSAGE_CENTER_MESSAGE_CENTER_CONTROLLER_H_
 #define ASH_MESSAGE_CENTER_MESSAGE_CENTER_CONTROLLER_H_
 
+#include "ash/ash_export.h"
 #include "ash/public/interfaces/ash_message_center_controller.mojom.h"
 #include "ash/system/web_notification/fullscreen_notification_blocker.h"
 #include "ash/system/web_notification/inactive_user_notification_blocker.h"
@@ -13,35 +14,73 @@
 #include "mojo/public/cpp/bindings/associated_binding.h"
 #include "mojo/public/cpp/bindings/binding.h"
 
+namespace message_center {
+struct NotifierId;
+}
+
 namespace ash {
 
-// This class manages the ash message center. For now it just houses
-// Ash-specific notification blockers. In the future, when the MessageCenter
-// lives in the Ash process, it will also manage adding and removing
-// notifications sent from clients (like Chrome).
-class MessageCenterController : public mojom::AshMessageCenterController {
+// This class manages the ash message center and allows clients (like Chrome) to
+// add and remove notifications.
+class ASH_EXPORT MessageCenterController
+    : public mojom::AshMessageCenterController {
  public:
   MessageCenterController();
   ~MessageCenterController() override;
 
   void BindRequest(mojom::AshMessageCenterControllerRequest request);
 
-  // AshMessageCenterController:
+  // Called when the user has toggled a notifier in the inline settings UI.
+  void SetNotifierEnabled(const message_center::NotifierId& notifier_id,
+                          bool enabled);
+
+  // Called upon request for more information about a particular notifier.
+  void OnNotifierAdvancedSettingsRequested(
+      const message_center::NotifierId& notifier_id);
+
+  // mojom::AshMessageCenterController:
   void SetClient(
       mojom::AshMessageCenterClientAssociatedPtrInfo client) override;
   void ShowClientNotification(
       const message_center::Notification& notification) override;
+  void UpdateNotifierIcon(const message_center::NotifierId& notifier_id,
+                          const gfx::ImageSkia& icon) override;
+  void NotifierEnabledChanged(const message_center::NotifierId& notifier_id,
+                              bool enabled) override;
 
   InactiveUserNotificationBlocker*
   inactive_user_notification_blocker_for_testing() {
     return &inactive_user_notification_blocker_;
   }
 
+  // An interface used to listen for changes to notifier settings information,
+  // implemented by the view that displays notifier settings.
+  class NotifierSettingsListener {
+   public:
+    // Sets the user-visible and toggle-able list of notifiers.
+    virtual void SetNotifierList(
+        const std::vector<mojom::NotifierUiDataPtr>& ui_data) = 0;
+
+    // Updates an icon for a notifier previously sent via SetNotifierList.
+    virtual void UpdateNotifierIcon(
+        const message_center::NotifierId& notifier_id,
+        const gfx::ImageSkia& icon) = 0;
+  };
+
+  // Sets |notifier_settings_| and asks the client for the list of notifiers to
+  // display.
+  void SetNotifierSettingsListener(NotifierSettingsListener* listener);
+
  private:
+  // Callback for GetNotifierList.
+  void OnGotNotifierList(std::vector<mojom::NotifierUiDataPtr> ui_data);
+
   FullscreenNotificationBlocker fullscreen_notification_blocker_;
   InactiveUserNotificationBlocker inactive_user_notification_blocker_;
   LoginStateNotificationBlocker login_notification_blocker_;
 
+  NotifierSettingsListener* notifier_settings_ = nullptr;
+
   mojo::Binding<mojom::AshMessageCenterController> binding_;
 
   mojom::AshMessageCenterClientAssociatedPtr client_;
diff --git a/ash/message_center/message_center_view.cc b/ash/message_center/message_center_view.cc
index 0f2584cd..6a15c65 100644
--- a/ash/message_center/message_center_view.cc
+++ b/ash/message_center/message_center_view.cc
@@ -140,11 +140,8 @@
   set_notify_enter_exit_on_child(true);
   SetBackground(views::CreateSolidBackground(kBackgroundColor));
 
-  message_center::NotifierSettingsProvider* notifier_settings_provider =
-      message_center_->GetNotifierSettingsProvider();
   button_bar_ = new MessageCenterButtonBar(
-      this, message_center, notifier_settings_provider,
-      initially_settings_visible, GetButtonBarTitle());
+      this, message_center, initially_settings_visible, GetButtonBarTitle());
   button_bar_->SetCloseAllButtonEnabled(false);
 
   const int button_height = button_bar_->GetPreferredSize().height();
@@ -171,7 +168,7 @@
   scroller_contents->AddChildView(message_list_view_.get());
   scroller_->SetContents(scroller_contents);
 
-  settings_view_ = new NotifierSettingsView(notifier_settings_provider);
+  settings_view_ = new NotifierSettingsView();
 
   no_notifications_view_ = new EmptyNotificationView();
 
diff --git a/ash/message_center/notifier_settings_view.cc b/ash/message_center/notifier_settings_view.cc
index 6d3467a..7ef7da5 100644
--- a/ash/message_center/notifier_settings_view.cc
+++ b/ash/message_center/notifier_settings_view.cc
@@ -10,9 +10,11 @@
 #include <string>
 #include <utility>
 
+#include "ash/message_center/message_center_controller.h"
 #include "ash/message_center/message_center_style.h"
 #include "ash/message_center/message_center_view.h"
 #include "ash/resources/vector_icons/vector_icons.h"
+#include "ash/shell.h"
 #include "ash/strings/grit/ash_strings.h"
 #include "base/macros.h"
 #include "base/strings/string16.h"
@@ -53,9 +55,8 @@
 namespace ash {
 
 using message_center::MessageCenter;
-using message_center::NotifierUiData;
+using mojom::NotifierUiData;
 using message_center::NotifierId;
-using message_center::NotifierSettingsProvider;
 
 namespace {
 
@@ -257,31 +258,26 @@
 // We do not use views::Checkbox class directly because it doesn't support
 // showing 'icon'.
 NotifierSettingsView::NotifierButton::NotifierButton(
-    NotifierSettingsProvider* provider,
-    std::unique_ptr<NotifierUiData> notifier_ui_data,
+    const mojom::NotifierUiData& notifier_ui_data,
     views::ButtonListener* listener)
     : views::Button(listener),
-      provider_(provider),
-      notifier_ui_data_(std::move(notifier_ui_data)),
+      notifier_id_(notifier_ui_data.notifier_id),
       icon_view_(new views::ImageView()),
-      name_view_(new views::Label(notifier_ui_data_->name)),
+      name_view_(new views::Label(notifier_ui_data.name)),
       checkbox_(new views::Checkbox(base::string16(), true /* force_md */)),
       learn_more_(nullptr) {
-  DCHECK(provider_);
-  DCHECK(notifier_ui_data_);
-
   name_view_->SetAutoColorReadabilityEnabled(false);
   name_view_->SetEnabledColor(kLabelColor);
   // "Roboto-Regular, 13sp" is specified in the mock.
   name_view_->SetFontList(message_center_style::GetFontListForSizeAndWeight(
       kLabelFontSize, gfx::Font::Weight::NORMAL));
 
-  checkbox_->SetChecked(notifier_ui_data_->enabled);
+  checkbox_->SetChecked(notifier_ui_data.enabled);
   checkbox_->set_listener(this);
   checkbox_->SetFocusBehavior(FocusBehavior::NEVER);
-  checkbox_->SetAccessibleName(notifier_ui_data_->name);
+  checkbox_->SetAccessibleName(notifier_ui_data.name);
 
-  if (ShouldHaveLearnMoreButton()) {
+  if (notifier_ui_data.has_advanced_settings) {
     // Create a more-info button that will be right-aligned.
     learn_more_ = new views::ImageButton(this);
     learn_more_->SetFocusPainter(CreateFocusPainter());
@@ -310,27 +306,25 @@
                                    views::ImageButton::ALIGN_MIDDLE);
   }
 
-  UpdateIconImage(notifier_ui_data_->icon);
+  UpdateIconImage(notifier_ui_data.icon);
 }
 
 NotifierSettingsView::NotifierButton::~NotifierButton() {}
 
 void NotifierSettingsView::NotifierButton::UpdateIconImage(
-    const gfx::Image& icon) {
-  notifier_ui_data_->icon = icon;
-  if (icon.IsEmpty()) {
+    const gfx::ImageSkia& icon) {
+  if (icon.isNull()) {
     icon_view_->SetImage(gfx::CreateVectorIcon(
         message_center::kProductIcon, kEntryIconSize, gfx::kChromeIconGrey));
   } else {
-    icon_view_->SetImage(icon.ToImageSkia());
+    icon_view_->SetImage(icon);
     icon_view_->SetImageSize(gfx::Size(kEntryIconSize, kEntryIconSize));
   }
-  GridChanged(ShouldHaveLearnMoreButton());
+  GridChanged();
 }
 
 void NotifierSettingsView::NotifierButton::SetChecked(bool checked) {
   checkbox_->SetChecked(checked);
-  notifier_ui_data_->enabled = checked;
 }
 
 bool NotifierSettingsView::NotifierButton::checked() const {
@@ -341,11 +335,6 @@
   return learn_more_ != nullptr;
 }
 
-const NotifierUiData& NotifierSettingsView::NotifierButton::notifier_ui_data()
-    const {
-  return *notifier_ui_data_;
-}
-
 void NotifierSettingsView::NotifierButton::SendLearnMorePressedForTest() {
   if (learn_more_ == nullptr)
     return;
@@ -366,9 +355,9 @@
     checkbox_->SetChecked(!checkbox_->checked());
     Button::NotifyClick(event);
   } else if (button == learn_more_) {
-    DCHECK(provider_);
-    provider_->OnNotifierAdvancedSettingsRequested(
-        notifier_ui_data_->notifier_id, nullptr);
+    Shell::Get()
+        ->message_center_controller()
+        ->OnNotifierAdvancedSettingsRequested(notifier_id_);
   }
 }
 
@@ -377,14 +366,7 @@
   static_cast<views::View*>(checkbox_)->GetAccessibleNodeData(node_data);
 }
 
-bool NotifierSettingsView::NotifierButton::ShouldHaveLearnMoreButton() const {
-  if (!provider_)
-    return false;
-
-  return notifier_ui_data_->has_advanced_settings;
-}
-
-void NotifierSettingsView::NotifierButton::GridChanged(bool has_learn_more) {
+void NotifierSettingsView::NotifierButton::GridChanged() {
   using views::ColumnSet;
   using views::GridLayout;
 
@@ -409,7 +391,7 @@
   cs->AddPaddingColumn(1, 0);
 
   // Add a column for the learn more button if necessary.
-  if (has_learn_more) {
+  if (learn_more_) {
     cs->AddPaddingColumn(0, kInternalHorizontalSpacing);
     cs->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 0,
                   GridLayout::USE_PREF, 0, 0);
@@ -419,7 +401,7 @@
   layout->AddView(checkbox_);
   layout->AddView(icon_view_);
   layout->AddView(name_view_);
-  if (has_learn_more)
+  if (learn_more_)
     layout->AddView(learn_more_);
 
   Layout();
@@ -427,19 +409,14 @@
 
 // NotifierSettingsView -------------------------------------------------------
 
-NotifierSettingsView::NotifierSettingsView(NotifierSettingsProvider* provider)
+NotifierSettingsView::NotifierSettingsView()
     : title_arrow_(nullptr),
       quiet_mode_icon_(nullptr),
       quiet_mode_toggle_(nullptr),
       header_view_(nullptr),
       top_label_(nullptr),
       scroller_(nullptr),
-      no_notifiers_view_(nullptr),
-      provider_(provider) {
-  // |provider_| may be null in tests.
-  if (provider_)
-    provider_->AddObserver(this);
-
+      no_notifiers_view_(nullptr) {
   SetFocusBehavior(FocusBehavior::ALWAYS);
   SetBackground(
       views::CreateSolidBackground(message_center_style::kBackgroundColor));
@@ -500,17 +477,13 @@
   no_notifiers_view_ = new EmptyNotifierView();
   AddChildView(no_notifiers_view_);
 
-  std::vector<std::unique_ptr<NotifierUiData>> notifiers;
-  if (provider_)
-    provider_->GetNotifierList(&notifiers);
-
-  UpdateContentsView(std::move(notifiers));
+  SetNotifierList({});
+  Shell::Get()->message_center_controller()->SetNotifierSettingsListener(this);
 }
 
 NotifierSettingsView::~NotifierSettingsView() {
-  // |provider_| may be null in tests.
-  if (provider_)
-    provider_->RemoveObserver(this);
+  Shell::Get()->message_center_controller()->SetNotifierSettingsListener(
+      nullptr);
 }
 
 bool NotifierSettingsView::IsScrollable() {
@@ -532,19 +505,8 @@
   }
 }
 
-void NotifierSettingsView::UpdateIconImage(const NotifierId& notifier_id,
-                                           const gfx::Image& icon) {
-  for (std::set<NotifierButton*>::iterator iter = buttons_.begin();
-       iter != buttons_.end(); ++iter) {
-    if ((*iter)->notifier_ui_data().notifier_id == notifier_id) {
-      (*iter)->UpdateIconImage(icon);
-      return;
-    }
-  }
-}
-
-void NotifierSettingsView::UpdateContentsView(
-    std::vector<std::unique_ptr<NotifierUiData>> ui_data) {
+void NotifierSettingsView::SetNotifierList(
+    const std::vector<mojom::NotifierUiDataPtr>& ui_data) {
   buttons_.clear();
 
   views::View* contents_view = new ScrollContentsView();
@@ -553,8 +515,7 @@
 
   size_t notifier_count = ui_data.size();
   for (size_t i = 0; i < notifier_count; ++i) {
-    NotifierButton* button =
-        new NotifierButton(provider_, std::move(ui_data[i]), this);
+    NotifierButton* button = new NotifierButton(*ui_data[i], this);
     EntryView* entry = new EntryView(button);
 
     entry->SetFocusBehavior(FocusBehavior::ALWAYS);
@@ -571,6 +532,16 @@
   InvalidateLayout();
 }
 
+void NotifierSettingsView::UpdateNotifierIcon(const NotifierId& notifier_id,
+                                              const gfx::ImageSkia& icon) {
+  for (auto* button : buttons_) {
+    if (button->notifier_id() == notifier_id) {
+      button->UpdateIconImage(icon);
+      return;
+    }
+  }
+}
+
 void NotifierSettingsView::Layout() {
   int header_height = header_view_->GetHeightForWidth(width());
   header_view_->SetBounds(0, 0, width(), header_height);
@@ -636,16 +607,14 @@
     return;
   }
 
-  std::set<NotifierButton*>::iterator iter =
-      buttons_.find(static_cast<NotifierButton*>(sender));
-
+  auto iter = buttons_.find(static_cast<NotifierButton*>(sender));
   if (iter == buttons_.end())
     return;
 
-  (*iter)->SetChecked(!(*iter)->checked());
-  if (provider_)
-    provider_->SetNotifierEnabled((*iter)->notifier_ui_data().notifier_id,
-                                  (*iter)->checked());
+  NotifierButton* button = *iter;
+  button->SetChecked(!button->checked());
+  Shell::Get()->message_center_controller()->SetNotifierEnabled(
+      button->notifier_id(), button->checked());
 }
 
 }  // namespace ash
diff --git a/ash/message_center/notifier_settings_view.h b/ash/message_center/notifier_settings_view.h
index 5686acb0..5ea7c1a7 100644
--- a/ash/message_center/notifier_settings_view.h
+++ b/ash/message_center/notifier_settings_view.h
@@ -9,6 +9,7 @@
 #include <set>
 
 #include "ash/ash_export.h"
+#include "ash/message_center/message_center_controller.h"
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
 #include "ui/message_center/notifier_settings.h"
@@ -27,25 +28,22 @@
 // A class to show the list of notifier extensions / URL patterns and allow
 // users to customize the settings.
 class ASH_EXPORT NotifierSettingsView
-    : public message_center::NotifierSettingsObserver,
-      public views::View,
-      public views::ButtonListener {
+    : public views::View,
+      public views::ButtonListener,
+      public MessageCenterController::NotifierSettingsListener {
  public:
-  explicit NotifierSettingsView(
-      message_center::NotifierSettingsProvider* provider);
+  explicit NotifierSettingsView();
   ~NotifierSettingsView() override;
 
   bool IsScrollable();
 
   void SetQuietModeState(bool is_quiet_mode);
 
-  // Overridden from NotifierSettingsDelegate:
-  void UpdateIconImage(const message_center::NotifierId& notifier_id,
-                       const gfx::Image& icon) override;
-
-  void set_provider(message_center::NotifierSettingsProvider* new_provider) {
-    provider_ = new_provider;
-  }
+  // NotifierSettingsListener:
+  void SetNotifierList(
+      const std::vector<mojom::NotifierUiDataPtr>& ui_data) override;
+  void UpdateNotifierIcon(const message_center::NotifierId& notifier_id,
+                          const gfx::ImageSkia& icon) override;
 
  private:
   FRIEND_TEST_ALL_PREFIXES(NotifierSettingsViewTest, TestLearnMoreButton);
@@ -54,17 +52,17 @@
   class ASH_EXPORT NotifierButton : public views::Button,
                                     public views::ButtonListener {
    public:
-    NotifierButton(
-        message_center::NotifierSettingsProvider* provider,
-        std::unique_ptr<message_center::NotifierUiData> notifier_ui_data,
-        views::ButtonListener* listener);
+    NotifierButton(const mojom::NotifierUiData& notifier_ui_data,
+                   views::ButtonListener* listener);
     ~NotifierButton() override;
 
-    void UpdateIconImage(const gfx::Image& icon);
+    void UpdateIconImage(const gfx::ImageSkia& icon);
     void SetChecked(bool checked);
     bool checked() const;
     bool has_learn_more() const;
-    const message_center::NotifierUiData& notifier_ui_data() const;
+    const message_center::NotifierId& notifier_id() const {
+      return notifier_id_;
+    }
 
     void SendLearnMorePressedForTest();
 
@@ -73,25 +71,19 @@
     void ButtonPressed(views::Button* button, const ui::Event& event) override;
     void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
 
-    bool ShouldHaveLearnMoreButton() const;
     // Helper function to reset the layout when the view has substantially
     // changed.
-    void GridChanged(bool has_learn_more);
+    void GridChanged();
 
-    message_center::NotifierSettingsProvider* provider_;  // Weak.
-    std::unique_ptr<message_center::NotifierUiData> notifier_ui_data_;
+    message_center::NotifierId notifier_id_;
     views::ImageView* icon_view_;
     views::Label* name_view_;
     views::Checkbox* checkbox_;
-    views::ImageButton* learn_more_;
+    views::ImageButton* learn_more_ = nullptr;
 
     DISALLOW_COPY_AND_ASSIGN(NotifierButton);
   };
 
-  // Given a new list of notifiers, updates the view to reflect it.
-  void UpdateContentsView(
-      std::vector<std::unique_ptr<message_center::NotifierUiData>> ui_data);
-
   // Overridden from views::View:
   void Layout() override;
   gfx::Size GetMinimumSize() const override;
@@ -112,7 +104,6 @@
   views::Label* top_label_;
   views::ScrollView* scroller_;
   views::View* no_notifiers_view_;
-  message_center::NotifierSettingsProvider* provider_;
   std::set<NotifierButton*> buttons_;
 
   DISALLOW_COPY_AND_ASSIGN(NotifierSettingsView);
diff --git a/ash/message_center/notifier_settings_view_unittest.cc b/ash/message_center/notifier_settings_view_unittest.cc
index 0c5ad22..8e17438 100644
--- a/ash/message_center/notifier_settings_view_unittest.cc
+++ b/ash/message_center/notifier_settings_view_unittest.cc
@@ -5,7 +5,10 @@
 #include <stddef.h>
 #include <memory>
 
+#include "ash/message_center/message_center_controller.h"
 #include "ash/message_center/notifier_settings_view.h"
+#include "ash/public/interfaces/ash_message_center_controller.mojom.h"
+#include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
 #include "base/macros.h"
 #include "base/strings/utf_string_conversions.h"
@@ -13,66 +16,69 @@
 #include "ui/message_center/notifier_settings.h"
 #include "ui/views/controls/scroll_view.h"
 
-using message_center::NotifierUiData;
-using message_center::NotifierId;
-using message_center::NotifierSettingsObserver;
-using message_center::NotifierSettingsProvider;
-
 namespace ash {
 
+using mojom::NotifierUiData;
+using message_center::NotifierId;
+
 namespace {
 
-// A class used by NotifierSettingsView to integrate with a setting system
-// for the clients of this module.
-class TestingNotifierSettingsProvider : public NotifierSettingsProvider {
+class TestAshMessageCenterClient : public mojom::AshMessageCenterClient {
  public:
-  ~TestingNotifierSettingsProvider() override = default;
+  TestAshMessageCenterClient() : binding_(this) {}
+  ~TestAshMessageCenterClient() override = default;
 
-  size_t request_count() const { return request_count_; }
+  size_t settings_request_count() const { return settings_request_count_; }
   const NotifierId* last_requested_notifier_id() const {
     return last_notifier_id_settings_requested_.get();
   }
+  void set_no_notifiers(bool no_notifiers) { no_notifiers_ = no_notifiers; }
 
-  // NotifierSettingsProvider
-
-  void AddObserver(NotifierSettingsObserver* observer) override {}
-  void RemoveObserver(NotifierSettingsObserver* observer) override {}
-
-  void GetNotifierList(
-      std::vector<std::unique_ptr<NotifierUiData>>* ui_data) override {
-    ui_data->clear();
-    if (!no_notifiers_) {
-      ui_data->push_back(NewNotifier("id", "title", true /* enabled */));
-      ui_data->push_back(
-          NewNotifier("id2", "other title", false /* enabled */));
-    }
+  mojom::AshMessageCenterClientAssociatedPtrInfo CreateInterfacePtr() {
+    mojom::AshMessageCenterClientAssociatedPtr ptr;
+    binding_.Bind(mojo::MakeIsolatedRequest(&ptr));
+    return ptr.PassInterface();
   }
 
+  // mojom::AshMessageCenterClient:
+  void HandleNotificationClosed(const std::string& id, bool by_user) override {}
+  void HandleNotificationClicked(const std::string& id) override {}
+  void HandleNotificationButtonClicked(const std::string& id,
+                                       int button_index) override {}
+
   void SetNotifierEnabled(const NotifierId& notifier_id,
                           bool enabled) override {}
 
-  void OnNotifierAdvancedSettingsRequested(
-      const NotifierId& notifier_id,
-      const std::string* notification_id) override {
-    request_count_++;
+  void HandleNotifierAdvancedSettingsRequested(
+      const NotifierId& notifier_id) override {
+    settings_request_count_++;
     last_notifier_id_settings_requested_.reset(new NotifierId(notifier_id));
   }
 
-  void set_no_notifiers(bool no_notifiers) { no_notifiers_ = no_notifiers; }
+  void GetNotifierList(GetNotifierListCallback callback) override {
+    std::vector<mojom::NotifierUiDataPtr> ui_data;
+    if (!no_notifiers_) {
+      ui_data.push_back(mojom::NotifierUiData::New(
+          NotifierId(NotifierId::APPLICATION, "id"),
+          base::ASCIIToUTF16("title"), true /* has_advanced_settings */,
+          true /* enabled */, gfx::ImageSkia()));
+      ui_data.push_back(mojom::NotifierUiData::New(
+          NotifierId(NotifierId::APPLICATION, "id2"),
+          base::ASCIIToUTF16("other title"), false /* has_advanced_settings */,
+          false /* enabled */, gfx::ImageSkia()));
+    }
 
- private:
-  std::unique_ptr<NotifierUiData> NewNotifier(const std::string& id,
-                                              const std::string& title,
-                                              bool enabled) {
-    NotifierId notifier_id(NotifierId::APPLICATION, id);
-    return std::make_unique<NotifierUiData>(
-        notifier_id, base::UTF8ToUTF16(title),
-        id == "id" /*has_advanced_settings*/, enabled);
+    std::move(callback).Run(std::move(ui_data));
   }
 
-  size_t request_count_ = 0u;
+ private:
+  size_t settings_request_count_ = 0u;
   std::unique_ptr<NotifierId> last_notifier_id_settings_requested_;
   bool no_notifiers_ = false;
+
+  mojo::AssociatedBinding<mojom::AshMessageCenterClient> binding_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestAshMessageCenterClient);
 };
 
 }  // namespace
@@ -87,15 +93,13 @@
 
   void InitView();
   NotifierSettingsView* GetView() const;
-  const TestingNotifierSettingsProvider* settings_provider() const {
-    return &settings_provider_;
-  }
+  TestAshMessageCenterClient* client() { return &client_; }
   void SetNoNotifiers(bool no_notifiers) {
-    settings_provider_.set_no_notifiers(no_notifiers);
+    client_.set_no_notifiers(no_notifiers);
   }
 
  private:
-  TestingNotifierSettingsProvider settings_provider_;
+  TestAshMessageCenterClient client_;
   std::unique_ptr<NotifierSettingsView> notifier_settings_view_;
 
   DISALLOW_COPY_AND_ASSIGN(NotifierSettingsViewTest);
@@ -108,6 +112,9 @@
 void NotifierSettingsViewTest::SetUp() {
   AshTestBase::SetUp();
   SetNoNotifiers(false);
+
+  Shell::Get()->message_center_controller()->SetClient(
+      client_.CreateInterfacePtr());
 }
 
 void NotifierSettingsViewTest::TearDown() {
@@ -116,8 +123,8 @@
 }
 
 void NotifierSettingsViewTest::InitView() {
-  notifier_settings_view_ =
-      std::make_unique<NotifierSettingsView>(&settings_provider_);
+  notifier_settings_view_.reset();
+  notifier_settings_view_ = std::make_unique<NotifierSettingsView>();
 }
 
 NotifierSettingsView* NotifierSettingsViewTest::GetView() const {
@@ -126,6 +133,8 @@
 
 TEST_F(NotifierSettingsViewTest, TestLearnMoreButton) {
   InitView();
+  // Wait for mojo.
+  base::RunLoop().RunUntilIdle();
   const std::set<NotifierSettingsView::NotifierButton*>& buttons =
       GetView()->buttons_;
   EXPECT_EQ(2u, buttons.size());
@@ -137,10 +146,12 @@
     }
   }
 
+  // Wait for mojo.
+  base::RunLoop().RunUntilIdle();
   EXPECT_EQ(1u, number_of_settings_buttons);
-  EXPECT_EQ(1u, settings_provider()->request_count());
+  EXPECT_EQ(1u, client()->settings_request_count());
   const NotifierId* last_settings_button_id =
-      settings_provider()->last_requested_notifier_id();
+      client()->last_requested_notifier_id();
   ASSERT_FALSE(last_settings_button_id == nullptr);
   EXPECT_EQ(NotifierId(NotifierId::APPLICATION, "id"),
             *last_settings_button_id);
@@ -148,11 +159,15 @@
 
 TEST_F(NotifierSettingsViewTest, TestEmptyNotifierView) {
   InitView();
+  // Wait for mojo.
+  base::RunLoop().RunUntilIdle();
   EXPECT_FALSE(GetView()->no_notifiers_view_->visible());
   EXPECT_TRUE(GetView()->top_label_->visible());
 
   SetNoNotifiers(true);
   InitView();
+  // Wait for mojo.
+  base::RunLoop().RunUntilIdle();
   EXPECT_TRUE(GetView()->no_notifiers_view_->visible());
   EXPECT_FALSE(GetView()->top_label_->visible());
 }
diff --git a/ash/public/interfaces/ash_message_center_controller.mojom b/ash/public/interfaces/ash_message_center_controller.mojom
index 48edade..f42ce2c 100644
--- a/ash/public/interfaces/ash_message_center_controller.mojom
+++ b/ash/public/interfaces/ash_message_center_controller.mojom
@@ -4,7 +4,29 @@
 
 module ash.mojom;
 
+import "ui/gfx/image/mojo/image.mojom";
 import "ui/message_center/mojo/notification.mojom";
+import "ui/message_center/mojo/notifier_id.mojom";
+import "mojo/common/string16.mojom";
+
+// A struct that contains information for presenting a notifier in a settings
+// panel.
+struct NotifierUiData {
+  // The notifier (e.g. an extension).
+  message_center.mojom.NotifierId notifier_id;
+
+  // The user-visible name of the notifier (e.g. an extension's name).
+  mojo.common.mojom.String16 name;
+
+  // True if the notifier has a button for advanced settings/"learn more".
+  bool has_advanced_settings;
+
+  // True if notifications from the notifier are presently enabled.
+  bool enabled;
+
+  // An icon displayed next to the name.
+  gfx.mojom.ImageSkia? icon;
+};
 
 // The message center controller funnels notification requests from the client
 // to the MessageCenter.
@@ -12,6 +34,12 @@
   SetClient(associated AshMessageCenterClient client);
 
   ShowClientNotification(message_center.mojom.Notification notification);
+
+  UpdateNotifierIcon(message_center.mojom.NotifierId notifier_id,
+                     gfx.mojom.ImageSkia icon);
+
+  NotifierEnabledChanged(message_center.mojom.NotifierId notifier_id,
+                         bool enabled);
 };
 
 // The message center client interface mimics
@@ -28,4 +56,16 @@
   // Called when a notification that has buttons (e.g., "Learn more") receives a
   // click on one of the buttons.
   HandleNotificationButtonClicked(string id, int32 button_index);
+
+  // Called when a user enables or disables notifications from the given
+  // notifier.
+  SetNotifierEnabled(message_center.mojom.NotifierId notifier_id, bool enabled);
+
+  // Called when the advanced settings button is pressed for a notifier.
+  HandleNotifierAdvancedSettingsRequested(
+      message_center.mojom.NotifierId notifier_id);
+
+  // Asks the client for a list of notifiers and associated UI information to be
+  // displayed in a settings panel.
+  GetNotifierList() => (array<NotifierUiData> notifiers);
 };
diff --git a/ash/system/web_notification/web_notification_tray_unittest.cc b/ash/system/web_notification/web_notification_tray_unittest.cc
index 7120bc1..6fa4ee6 100644
--- a/ash/system/web_notification/web_notification_tray_unittest.cc
+++ b/ash/system/web_notification/web_notification_tray_unittest.cc
@@ -428,6 +428,9 @@
   EXPECT_TRUE(widget->IsActive());
   EXPECT_FALSE(tray->message_center_bubble());
 
+  // Wait for bubble to actually close.
+  RunAllPendingInMessageLoop();
+
   // Show a second widget.
   std::unique_ptr<views::Widget> second_widget(CreateTestWidget());
   EXPECT_TRUE(second_widget->IsActive());
diff --git a/base/files/file_util_posix.cc b/base/files/file_util_posix.cc
index 7582e7d..779da8d 100644
--- a/base/files/file_util_posix.cc
+++ b/base/files/file_util_posix.cc
@@ -266,18 +266,18 @@
   FileEnumerator traversal(path, true,
       FileEnumerator::FILES | FileEnumerator::DIRECTORIES |
       FileEnumerator::SHOW_SYM_LINKS);
-  for (FilePath current = traversal.Next(); success && !current.empty();
+  for (FilePath current = traversal.Next(); !current.empty();
        current = traversal.Next()) {
     if (traversal.GetInfo().IsDirectory())
       directories.push(current.value());
     else
-      success = (unlink(current.value().c_str()) == 0);
+      success &= (unlink(current.value().c_str()) == 0);
   }
 
-  while (success && !directories.empty()) {
+  while (!directories.empty()) {
     FilePath dir = FilePath(directories.top());
     directories.pop();
-    success = (rmdir(dir.value().c_str()) == 0);
+    success &= (rmdir(dir.value().c_str()) == 0);
   }
   return success;
 }
diff --git a/base/files/file_util_unittest.cc b/base/files/file_util_unittest.cc
index 3f2e0f08..9d3600b 100644
--- a/base/files/file_util_unittest.cc
+++ b/base/files/file_util_unittest.cc
@@ -18,6 +18,7 @@
 #include "base/bind_helpers.h"
 #include "base/callback_helpers.h"
 #include "base/environment.h"
+#include "base/files/file.h"
 #include "base/files/file_enumerator.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
@@ -46,9 +47,15 @@
 #if defined(OS_POSIX)
 #include <errno.h>
 #include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
 #include <unistd.h>
 #endif
 
+#if defined(OS_LINUX)
+#include <linux/fs.h>
+#endif
+
 #if defined(OS_ANDROID)
 #include "base/android/content_uri_utils.h"
 #endif
@@ -1330,6 +1337,52 @@
   EXPECT_FALSE(PathExists(test_subdir));
 }
 
+// Tests recursive Delete() for a directory.
+TEST_F(FileUtilTest, DeleteDirRecursiveWithOpenFile) {
+  // Create a subdirectory and put a file and two directories inside.
+  FilePath test_subdir = temp_dir_.GetPath().Append(FPL("DeleteWithOpenFile"));
+  CreateDirectory(test_subdir);
+  ASSERT_TRUE(PathExists(test_subdir));
+
+  FilePath file_name1 = test_subdir.Append(FPL("Undeletebable File1.txt"));
+  File file1(file_name1,
+             File::FLAG_CREATE | File::FLAG_READ | File::FLAG_WRITE);
+  ASSERT_TRUE(PathExists(file_name1));
+
+  FilePath file_name2 = test_subdir.Append(FPL("Deleteable File2.txt"));
+  CreateTextFile(file_name2, bogus_content);
+  ASSERT_TRUE(PathExists(file_name2));
+
+  FilePath file_name3 = test_subdir.Append(FPL("Undeletebable File3.txt"));
+  File file3(file_name3,
+             File::FLAG_CREATE | File::FLAG_READ | File::FLAG_WRITE);
+  ASSERT_TRUE(PathExists(file_name3));
+
+#if defined(OS_LINUX)
+  // On Windows, holding the file open in sufficient to make it un-deletable.
+  // The POSIX code is verifiable on Linux by creating an "immutable" file but
+  // this is best-effort because it's not supported by all file systems. Both
+  // files will have the same flags so no need to get them individually.
+  int flags;
+  CHECK_EQ(0, ioctl(file1.GetPlatformFile(), FS_IOC_GETFLAGS, &flags));
+  flags |= FS_IMMUTABLE_FL;
+  ioctl(file1.GetPlatformFile(), FS_IOC_SETFLAGS, &flags);
+  ioctl(file3.GetPlatformFile(), FS_IOC_SETFLAGS, &flags);
+#endif
+
+  // Delete recursively and check that at least the second file got deleted.
+  // This ensures that un-deletable files don't impact those that can be.
+  DeleteFile(test_subdir, true);
+  EXPECT_FALSE(PathExists(file_name2));
+
+#if defined(OS_LINUX)
+  // Make sure that the test can clean up after itself.
+  flags &= ~FS_IMMUTABLE_FL;
+  ioctl(file1.GetPlatformFile(), FS_IOC_SETFLAGS, &flags);
+  ioctl(file3.GetPlatformFile(), FS_IOC_SETFLAGS, &flags);
+#endif
+}
+
 TEST_F(FileUtilTest, MoveFileNew) {
   // Create a file
   FilePath file_name_from =
diff --git a/base/files/file_util_win.cc b/base/files/file_util_win.cc
index 9d16ad5..1f63211c 100644
--- a/base/files/file_util_win.cc
+++ b/base/files/file_util_win.cc
@@ -49,6 +49,7 @@
   FileEnumerator traversal(path, false,
                            FileEnumerator::FILES | FileEnumerator::DIRECTORIES,
                            pattern);
+  bool success = true;
   for (FilePath current = traversal.Next(); !current.empty();
        current = traversal.Next()) {
     // Try to clear the read-only bit if we find it.
@@ -63,12 +64,12 @@
     if (info.IsDirectory()) {
       if (recursive && (!DeleteFileRecursive(current, pattern, true) ||
                         !RemoveDirectory(current.value().c_str())))
-        return false;
+        success = false;
     } else if (!::DeleteFile(current.value().c_str())) {
-      return false;
+      success = false;
     }
   }
-  return true;
+  return success;
 }
 
 // Appends |mode_char| to |mode| before the optional character set encoding; see
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
index 22412e3..48031b4a 100644
--- a/build/config/compiler/BUILD.gn
+++ b/build/config/compiler/BUILD.gn
@@ -522,6 +522,7 @@
     if (is_win) {
       # This is a straight translation of the non-Windows flags below.
       ldflags += [
+        "/opt:lldlto=0",
         "/opt:lldltojobs=8",
         "/lldltocache:" +
             rebase_path("$root_out_dir/thinlto-cache", root_build_dir),
diff --git a/cc/DEPS b/cc/DEPS
index 0e483c8..79a0734 100644
--- a/cc/DEPS
+++ b/cc/DEPS
@@ -12,6 +12,7 @@
   "+gpu/command_buffer/common/mailbox_holder.h",
   "+gpu/command_buffer/common/sync_token.h",
   "+gpu/command_buffer/common/texture_in_use_response.h",
+  "+gpu/config/gpu_driver_bug_workaround_type.h",
   "+gpu/config/gpu_feature_info.h",
   "+gpu/vulkan",
   "+media",
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 4ff70bd..43b92fa 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -2721,10 +2721,10 @@
       "metrics/perf/windowed_incognito_observer.h",
       "notifications/arc_application_notifier_controller_chromeos.cc",
       "notifications/arc_application_notifier_controller_chromeos.h",
+      "notifications/chrome_ash_message_center_client.cc",
+      "notifications/chrome_ash_message_center_client.h",
       "notifications/extension_notifier_controller.cc",
       "notifications/extension_notifier_controller.h",
-      "notifications/message_center_settings_controller_chromeos.cc",
-      "notifications/message_center_settings_controller_chromeos.h",
       "notifications/notifier_controller.h",
       "notifications/web_page_notifier_controller.cc",
       "notifications/web_page_notifier_controller.h",
diff --git a/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.cc b/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.cc
index a002072..6790927 100644
--- a/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.cc
+++ b/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.cc
@@ -8,6 +8,7 @@
 
 #include "base/bind.h"
 #include "base/location.h"
+#include "base/metrics/histogram_macros.h"
 #include "base/metrics/user_metrics.h"
 #include "base/task_scheduler/post_task.h"
 #include "chrome/browser/android/shortcut_helper.h"
@@ -93,6 +94,10 @@
   return CreateLauncherIconInBackground(start_url, decoded);
 }
 
+void RecordAddToHomescreenDialogDuration(base::TimeDelta duration) {
+  UMA_HISTOGRAM_TIMES("Webapp.AddToHomescreenDialog.Timeout", duration);
+}
+
 }  // namespace
 
 AddToHomescreenDataFetcher::AddToHomescreenDataFetcher(
@@ -104,7 +109,7 @@
       installable_manager_(InstallableManager::FromWebContents(web_contents)),
       observer_(observer),
       shortcut_info_(GetShortcutUrl(web_contents)),
-      data_timeout_ms_(data_timeout_ms),
+      data_timeout_ms_(base::TimeDelta::FromMilliseconds(data_timeout_ms)),
       check_webapk_compatibility_(check_webapk_compatibility),
       is_waiting_for_web_application_info_(true),
       is_waiting_for_manifest_(true),
@@ -163,9 +168,10 @@
   // Kick off a timeout for downloading data. If we haven't finished within the
   // timeout, fall back to using a dynamically-generated launcher icon.
   data_timeout_timer_.Start(
-      FROM_HERE, base::TimeDelta::FromMilliseconds(data_timeout_ms_),
+      FROM_HERE, data_timeout_ms_,
       base::Bind(&AddToHomescreenDataFetcher::OnDataTimedout,
                  weak_ptr_factory_.GetWeakPtr()));
+  start_time_ = base::TimeTicks::Now();
 
   installable_manager_->GetData(
       ParamsToPerformManifestAndIconFetch(check_webapk_compatibility_),
@@ -190,7 +196,13 @@
   return handled;
 }
 
+void AddToHomescreenDataFetcher::StopTimer() {
+  data_timeout_timer_.Stop();
+  RecordAddToHomescreenDialogDuration(base::TimeTicks::Now() - start_time_);
+}
+
 void AddToHomescreenDataFetcher::OnDataTimedout() {
+  RecordAddToHomescreenDialogDuration(data_timeout_ms_);
   weak_ptr_factory_.InvalidateWeakPtrs();
 
   if (!web_contents())
@@ -229,7 +241,7 @@
       observer_->OnDidDetermineWebApkCompatibility(false);
     observer_->OnUserTitleAvailable(shortcut_info_.user_title,
                                     shortcut_info_.url);
-    data_timeout_timer_.Stop();
+    StopTimer();
     installable_manager_->RecordAddToHomescreenNoTimeout();
     FetchFavicon();
     return;
@@ -261,7 +273,7 @@
 
 void AddToHomescreenDataFetcher::OnDidPerformInstallableCheck(
     const InstallableData& data) {
-  data_timeout_timer_.Stop();
+  StopTimer();
 
   if (!web_contents())
     return;
diff --git a/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.h b/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.h
index 042cf8a7..8c42966 100644
--- a/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.h
+++ b/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.h
@@ -11,6 +11,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/strings/string16.h"
 #include "base/task/cancelable_task_tracker.h"
+#include "base/time/time.h"
 #include "base/timer/timer.h"
 #include "chrome/browser/android/shortcut_info.h"
 #include "content/public/browser/web_contents_observer.h"
@@ -73,6 +74,9 @@
   bool OnMessageReceived(const IPC::Message& message,
                          content::RenderFrameHost* sender) override;
 
+  // Called to stop the timeout timer.
+  void StopTimer();
+
   // Called if either InstallableManager or the favicon fetch takes too long.
   void OnDataTimedout();
 
@@ -104,8 +108,9 @@
 
   base::CancelableTaskTracker favicon_task_tracker_;
   base::OneShotTimer data_timeout_timer_;
+  base::TimeTicks start_time_;
 
-  const int data_timeout_ms_;
+  const base::TimeDelta data_timeout_ms_;
 
   // Indicates whether to check WebAPK compatibility.
   bool check_webapk_compatibility_;
diff --git a/chrome/browser/android/webapps/add_to_homescreen_data_fetcher_unittest.cc b/chrome/browser/android/webapps/add_to_homescreen_data_fetcher_unittest.cc
index 8625960..bc13429e 100644
--- a/chrome/browser/android/webapps/add_to_homescreen_data_fetcher_unittest.cc
+++ b/chrome/browser/android/webapps/add_to_homescreen_data_fetcher_unittest.cc
@@ -299,6 +299,7 @@
     histograms.ExpectUniqueSample(
         "Webapp.InstallabilityCheckStatus.AddToHomescreenTimeout",
         static_cast<int>(expected_status_for_histogram), 1);
+    histograms.ExpectTotalCount("Webapp.AddToHomescreenDialog.Timeout", 1);
   }
 
   void SetManifest(const content::Manifest& manifest) {
diff --git a/chrome/browser/chrome_service_worker_browsertest.cc b/chrome/browser/chrome_service_worker_browsertest.cc
index 33e7dbc..8303a37 100644
--- a/chrome/browser/chrome_service_worker_browsertest.cc
+++ b/chrome/browser/chrome_service_worker_browsertest.cc
@@ -359,11 +359,17 @@
 
  private:
   void ExecuteJavaScriptForTests(const std::string& js) {
+    base::RunLoop run_loop;
     browser()
         ->tab_strip_model()
         ->GetActiveWebContents()
         ->GetMainFrame()
-        ->ExecuteJavaScriptForTests(base::ASCIIToUTF16(js));
+        ->ExecuteJavaScriptForTests(
+            base::ASCIIToUTF16(js),
+            base::Bind([](const base::Closure& quit_callback,
+                          const base::Value* result) { quit_callback.Run(); },
+                       run_loop.QuitClosure()));
+    run_loop.Run();
   }
 
   std::string GetManifestAndIssuedRequests() {
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index b74bd89..7881630 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -1825,6 +1825,8 @@
     "login/users/affiliation_unittest.cc",
     "login/users/multi_profile_user_controller_unittest.cc",
     "login/users/user_manager_unittest.cc",
+    "login/users/wallpaper/wallpaper_manager_test_utils.cc",
+    "login/users/wallpaper/wallpaper_manager_test_utils.h",
     "login/users/wallpaper/wallpaper_manager_unittest.cc",
     "mobile/mobile_activator_unittest.cc",
     "mobile_config_unittest.cc",
diff --git a/chrome/browser/chromeos/arc/wallpaper/arc_wallpaper_service.cc b/chrome/browser/chromeos/arc/wallpaper/arc_wallpaper_service.cc
index d46a1206..ab60b216a 100644
--- a/chrome/browser/chromeos/arc/wallpaper/arc_wallpaper_service.cc
+++ b/chrome/browser/chromeos/arc/wallpaper/arc_wallpaper_service.cc
@@ -233,8 +233,8 @@
   // ImageDecoder::ImageRequest.
   decode_request_.reset();
   const PrimaryAccount& account = GetPrimaryAccount();
-  chromeos::WallpaperManager::Get()->SetDefaultWallpaper(account.id,
-                                                         account.is_active);
+  chromeos::WallpaperManager::Get()->SetDefaultWallpaper(
+      account.id, account.is_active /* update_wallpaper */);
 }
 
 void ArcWallpaperService::GetWallpaper(GetWallpaperCallback callback) {
diff --git a/chrome/browser/chromeos/arc/wallpaper/arc_wallpaper_service_unittest.cc b/chrome/browser/chromeos/arc/wallpaper/arc_wallpaper_service_unittest.cc
index db0937a..4cdb0802 100644
--- a/chrome/browser/chromeos/arc/wallpaper/arc_wallpaper_service_unittest.cc
+++ b/chrome/browser/chromeos/arc/wallpaper/arc_wallpaper_service_unittest.cc
@@ -16,6 +16,7 @@
 #include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
 #include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h"
 #include "chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.h"
+#include "chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager_test_utils.h"
 #include "chrome/browser/image_decoder.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile.h"
@@ -131,6 +132,8 @@
 TEST_F(ArcWallpaperServiceTest, SetDefaultWallpaper) {
   service_->SetDefaultWallpaper();
   RunAllPendingInMessageLoop();
+  // Wait until wallpaper loading is done.
+  chromeos::wallpaper_manager_test_utils::WaitAsyncWallpaperLoadFinished();
   ASSERT_EQ(1u, wallpaper_instance_->changed_ids().size());
   EXPECT_EQ(-1, wallpaper_instance_->changed_ids()[0]);
 }
@@ -141,7 +144,8 @@
   std::vector<uint8_t> bytes;
   service_->SetWallpaper(bytes, 10 /* ID */);
   content::RunAllTasksUntilIdle();
-
+  // Wait until wallpaper loading is done.
+  chromeos::wallpaper_manager_test_utils::WaitAsyncWallpaperLoadFinished();
   ASSERT_EQ(1u, wallpaper_instance_->changed_ids().size());
   EXPECT_EQ(10, wallpaper_instance_->changed_ids()[0]);
 
@@ -160,6 +164,8 @@
   std::vector<uint8_t> bytes;
   service_->SetWallpaper(bytes, 10 /* ID */);
   content::RunAllTasksUntilIdle();
+  // Wait until wallpaper loading is done.
+  chromeos::wallpaper_manager_test_utils::WaitAsyncWallpaperLoadFinished();
 
   // For failure case, ArcWallpaperService reports that wallpaper is changed to
   // requested wallpaper (ID=10), then reports that the wallpaper is changed
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
index cc7b21df..a926efb 100644
--- a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
+++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
@@ -101,7 +101,7 @@
 #include "chrome/browser/defaults.h"
 #include "chrome/browser/lifetime/application_lifetime.h"
 #include "chrome/browser/net/chrome_network_delegate.h"
-#include "chrome/browser/notifications/message_center_settings_controller_chromeos.h"
+#include "chrome/browser/notifications/notification_platform_bridge.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/task_manager/task_manager_interface.h"
@@ -879,9 +879,8 @@
   message_center::MessageCenter::Get()->SetProductOSName(
       l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_OS_NAME));
 
-  // Create and set the settings provider for the message center.
-  message_center::MessageCenter::Get()->SetNotifierSettingsProvider(
-      std::make_unique<MessageCenterSettingsControllerChromeOs>());
+  if (!base::FeatureList::IsEnabled(features::kNativeNotifications))
+    notification_client_.reset(NotificationPlatformBridge::Create());
 
   // Register all installed components for regular update.
   base::PostTaskWithTraitsAndReplyWithResult(
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.h b/chrome/browser/chromeos/chrome_browser_main_chromeos.h
index d0d2248..d2b8eed2 100644
--- a/chrome/browser/chromeos/chrome_browser_main_chromeos.h
+++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.h
@@ -15,6 +15,7 @@
 #include "chromeos/system/version_loader.h"
 
 class NightLightClient;
+class NotificationPlatformBridge;
 class TabletModeClient;
 
 namespace lock_screen_apps {
@@ -113,6 +114,11 @@
 
   std::unique_ptr<NightLightClient> night_light_client_;
 
+  // TODO(estade): Remove this when Chrome OS uses native notifications by
+  // default (as it will be instantiated elsewhere). For now it's necessary to
+  // send notifier settings information to Ash.
+  std::unique_ptr<NotificationPlatformBridge> notification_client_;
+
   DISALLOW_COPY_AND_ASSIGN(ChromeBrowserMainPartsChromeos);
 };
 
diff --git a/chrome/browser/chromeos/customization/customization_wallpaper_downloader_browsertest.cc b/chrome/browser/chromeos/customization/customization_wallpaper_downloader_browsertest.cc
index 5820b41..73e4c70 100644
--- a/chrome/browser/chromeos/customization/customization_wallpaper_downloader_browsertest.cc
+++ b/chrome/browser/chromeos/customization/customization_wallpaper_downloader_browsertest.cc
@@ -247,7 +247,8 @@
 IN_PROC_BROWSER_TEST_F(CustomizationWallpaperDownloaderBrowserTest,
                        OEMWallpaperIsPresent) {
   CreateCmdlineWallpapers();
-  WallpaperManager::Get()->SetDefaultWallpaperNow(EmptyAccountId());
+  WallpaperManager::Get()->SetDefaultWallpaper(EmptyAccountId(),
+                                               true /* update_wallpaper */);
   wallpaper_manager_test_utils::WaitAsyncWallpaperLoadFinished();
   EXPECT_TRUE(wallpaper_manager_test_utils::ImageIsNearColor(
       ash::Shell::Get()->wallpaper_controller()->GetWallpaper(),
@@ -276,7 +277,8 @@
 IN_PROC_BROWSER_TEST_F(CustomizationWallpaperDownloaderBrowserTest,
                        OEMWallpaperRetryFetch) {
   CreateCmdlineWallpapers();
-  WallpaperManager::Get()->SetDefaultWallpaperNow(EmptyAccountId());
+  WallpaperManager::Get()->SetDefaultWallpaper(EmptyAccountId(),
+                                               true /* update_wallpaper */);
   wallpaper_manager_test_utils::WaitAsyncWallpaperLoadFinished();
   EXPECT_TRUE(wallpaper_manager_test_utils::ImageIsNearColor(
       ash::Shell::Get()->wallpaper_controller()->GetWallpaper(),
diff --git a/chrome/browser/chromeos/extensions/wallpaper_private_api.cc b/chrome/browser/chromeos/extensions/wallpaper_private_api.cc
index 688258e..d663661 100644
--- a/chrome/browser/chromeos/extensions/wallpaper_private_api.cc
+++ b/chrome/browser/chromeos/extensions/wallpaper_private_api.cc
@@ -479,7 +479,8 @@
   if (wallpaper_manager->IsPolicyControlled(account_id))
     return false;
 
-  wallpaper_manager->SetDefaultWallpaper(account_id, true);
+  wallpaper_manager->SetDefaultWallpaper(account_id,
+                                         true /* update_wallpaper */);
 
   Profile* profile = Profile::FromBrowserContext(browser_context());
   // This API is only available to the component wallpaper picker. We do not
diff --git a/chrome/browser/chromeos/login/lock/views_screen_locker.cc b/chrome/browser/chromeos/login/lock/views_screen_locker.cc
index fae53fb..7465d59 100644
--- a/chrome/browser/chromeos/login/lock/views_screen_locker.cc
+++ b/chrome/browser/chromeos/login/lock/views_screen_locker.cc
@@ -188,7 +188,7 @@
     lock_screen_utils::SetUserInputMethod(account_id.GetUserEmail(),
                                           ime_state_.get());
     lock_screen_utils::SetKeyboardSettings(account_id);
-    WallpaperManager::Get()->SetUserWallpaperDelayed(account_id);
+    WallpaperManager::Get()->SetUserWallpaper(account_id);
 
     bool use_24hour_clock = false;
     if (user_manager::known_user::GetBooleanPref(
diff --git a/chrome/browser/chromeos/login/ui/user_adding_screen.cc b/chrome/browser/chromeos/login/ui/user_adding_screen.cc
index 75a545e..b6f2e89 100644
--- a/chrome/browser/chromeos/login/ui/user_adding_screen.cc
+++ b/chrome/browser/chromeos/login/ui/user_adding_screen.cc
@@ -69,7 +69,7 @@
 
   // Reset wallpaper if cancel adding user from multiple user sign in page.
   if (user_manager::UserManager::Get()->IsUserLoggedIn()) {
-    WallpaperManager::Get()->SetUserWallpaperDelayed(
+    WallpaperManager::Get()->SetUserWallpaper(
         user_manager::UserManager::Get()->GetActiveUser()->GetAccountId());
   }
 }
diff --git a/chrome/browser/chromeos/login/ui/webui_login_display.cc b/chrome/browser/chromeos/login/ui/webui_login_display.cc
index 1d24b425..e5afbdf 100644
--- a/chrome/browser/chromeos/login/ui/webui_login_display.cc
+++ b/chrome/browser/chromeos/login/ui/webui_login_display.cc
@@ -223,14 +223,14 @@
 }
 
 void WebUILoginDisplay::LoadWallpaper(const AccountId& account_id) {
-  WallpaperManager::Get()->SetUserWallpaperDelayed(account_id);
+  WallpaperManager::Get()->SetUserWallpaper(account_id);
 }
 
 void WebUILoginDisplay::LoadSigninWallpaper() {
   if (!WallpaperManager::Get()->SetDeviceWallpaperIfApplicable(
           user_manager::SignInAccountId())) {
-    WallpaperManager::Get()->SetDefaultWallpaperDelayed(
-        user_manager::SignInAccountId());
+    WallpaperManager::Get()->SetDefaultWallpaper(
+        user_manager::SignInAccountId(), true /* update_wallpaper */);
   }
 }
 
diff --git a/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc b/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc
index 379d559..8bae38218 100644
--- a/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc
+++ b/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc
@@ -770,7 +770,7 @@
       user_manager::User::USER_IMAGE_INVALID, false);
 
   // Initializes wallpaper after active_user_ is set.
-  WallpaperManager::Get()->SetUserWallpaperNow(user_manager::GuestAccountId());
+  WallpaperManager::Get()->SetUserWallpaper(user_manager::GuestAccountId());
 }
 
 void ChromeUserManagerImpl::RegularUserLoggedIn(const AccountId& account_id) {
@@ -785,7 +785,7 @@
   }
 
   if (IsCurrentUserNew())
-    WallpaperManager::Get()->SetUserWallpaperNow(account_id);
+    WallpaperManager::Get()->SetUserWallpaper(account_id);
 
   GetUserImageManager(account_id)->UserLoggedIn(IsCurrentUserNew(), false);
 
@@ -801,7 +801,7 @@
   ChromeUserManager::RegularUserLoggedInAsEphemeral(account_id);
 
   GetUserImageManager(account_id)->UserLoggedIn(IsCurrentUserNew(), false);
-  WallpaperManager::Get()->SetUserWallpaperNow(account_id);
+  WallpaperManager::Get()->SetUserWallpaper(account_id);
 }
 
 void ChromeUserManagerImpl::SupervisedUserLoggedIn(
@@ -816,11 +816,11 @@
     SetIsCurrentUserNew(true);
     active_user_ = user_manager::User::CreateSupervisedUser(account_id);
     // Leaving OAuth token status at the default state = unknown.
-    WallpaperManager::Get()->SetUserWallpaperNow(account_id);
+    WallpaperManager::Get()->SetUserWallpaper(account_id);
   } else {
     if (supervised_user_manager_->CheckForFirstRun(account_id.GetUserEmail())) {
       SetIsCurrentUserNew(true);
-      WallpaperManager::Get()->SetUserWallpaperNow(account_id);
+      WallpaperManager::Get()->SetUserWallpaper(account_id);
     } else {
       SetIsCurrentUserNew(false);
     }
@@ -860,7 +860,7 @@
   // always fetched/cleared inside a user session), in the case the user-policy
   // controlled wallpaper was cached/cleared by not updated in the login screen,
   // so we need to update the wallpaper after the public user logged in.
-  WallpaperManager::Get()->SetUserWallpaperNow(user->GetAccountId());
+  WallpaperManager::Get()->SetUserWallpaper(user->GetAccountId());
   WallpaperManager::Get()->EnsureLoggedInUserWallpaperLoaded();
 
   SetPublicAccountDelegates();
@@ -877,7 +877,7 @@
       user_manager::User::USER_IMAGE_INVALID, false);
 
   const AccountId& kiosk_app_account_id = user->GetAccountId();
-  WallpaperManager::Get()->SetUserWallpaperNow(kiosk_app_account_id);
+  WallpaperManager::Get()->SetUserWallpaper(kiosk_app_account_id);
 
   // TODO(bartfab): Add KioskAppUsers to the users_ list and keep metadata like
   // the kiosk_app_id in these objects, removing the need to re-parse the
@@ -947,7 +947,7 @@
           *ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
               IDR_LOGIN_DEFAULT_USER)),
       user_manager::User::USER_IMAGE_INVALID, false);
-  WallpaperManager::Get()->SetUserWallpaperNow(user_manager::DemoAccountId());
+  WallpaperManager::Get()->SetUserWallpaper(user_manager::DemoAccountId());
 
   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
   command_line->AppendSwitch(::switches::kForceAppMode);
diff --git a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.cc b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.cc
index 7f32f5b..1c38b23 100644
--- a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.cc
+++ b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.cc
@@ -361,48 +361,42 @@
 // Enqueued but not started request might be updated by subsequent load
 // request. Therefore it's created empty, and updated being enqueued.
 //
-// PendingWallpaper is owned by WallpaperManager, but reference to this object
-// is passed to other threads by PostTask() calls, therefore it is
-// RefCountedThreadSafe.
-class WallpaperManager::PendingWallpaper
-    : public base::RefCountedThreadSafe<PendingWallpaper> {
+// PendingWallpaper is owned by WallpaperManager.
+class WallpaperManager::PendingWallpaper {
  public:
-  // Do LoadWallpaper() - image not found in cache.
-  PendingWallpaper(const base::TimeDelta delay, const AccountId& account_id)
-      : account_id_(account_id),
-        default_(false),
-        on_finish_(new MovableOnDestroyCallback(
-            base::Bind(&WallpaperManager::PendingWallpaper::OnWallpaperSet,
-                       this))) {
-    timer.Start(
-        FROM_HERE, delay,
-        base::Bind(&WallpaperManager::PendingWallpaper::ProcessRequest, this));
+  PendingWallpaper(const base::TimeDelta delay) : weak_factory_(this) {
+    timer.Start(FROM_HERE, delay,
+                base::Bind(&WallpaperManager::PendingWallpaper::ProcessRequest,
+                           weak_factory_.GetWeakPtr()));
   }
 
-  // There are 4 cases in SetUserWallpaper:
+  ~PendingWallpaper() { weak_factory_.InvalidateWeakPtrs(); }
+
+  // There are four cases:
   // 1) gfx::ImageSkia is found in cache.
-  //    - Schedule task to (probably) resize it and install:
-  //    call SetWallpaper(user_wallpaper, layout);
-  // 2) WallpaperInfo is found in cache
-  //    - need to LoadWallpaper(), resize and install.
-  // 3) wallpaper path is not NULL, load image URL, then resize, etc...
-  // 4) SetDefaultWallpaper (either on some error, or when user is new).
-  void ResetSetWallpaperImage(const gfx::ImageSkia& image,
-                              const wallpaper::WallpaperInfo& info) {
-    SetMode(image, info, base::FilePath(), false);
+  void SetWallpaperFromImage(const AccountId& account_id,
+                             const gfx::ImageSkia& image,
+                             const wallpaper::WallpaperInfo& info) {
+    SetMode(account_id, image, info, base::FilePath(), false);
   }
 
-  void ResetLoadWallpaper(const wallpaper::WallpaperInfo& info) {
-    SetMode(gfx::ImageSkia(), info, base::FilePath(), false);
+  // 2) WallpaperInfo is found in cache.
+  void SetWallpaperFromInfo(const AccountId& account_id,
+                            const wallpaper::WallpaperInfo& info) {
+    SetMode(account_id, gfx::ImageSkia(), info, base::FilePath(), false);
   }
 
-  void ResetSetCustomWallpaper(const wallpaper::WallpaperInfo& info,
-                               const base::FilePath& wallpaper_path) {
-    SetMode(gfx::ImageSkia(), info, wallpaper_path, false);
+  // 3) Wallpaper path is not null.
+  void SetWallpaperFromPath(const AccountId& account_id,
+                            const wallpaper::WallpaperInfo& info,
+                            const base::FilePath& wallpaper_path) {
+    SetMode(account_id, gfx::ImageSkia(), info, wallpaper_path, false);
   }
 
-  void ResetSetDefaultWallpaper() {
-    SetMode(gfx::ImageSkia(), WallpaperInfo(), base::FilePath(), true);
+  // 4) Set default wallpaper (either on some error, or when user is new).
+  void SetDefaultWallpaper(const AccountId& account_id) {
+    SetMode(account_id, gfx::ImageSkia(), WallpaperInfo(), base::FilePath(),
+            true);
   }
 
   uint32_t GetImageId() const {
@@ -410,15 +404,13 @@
   }
 
  private:
-  friend class base::RefCountedThreadSafe<PendingWallpaper>;
-
-  ~PendingWallpaper() {}
-
-  // All Reset*() methods use SetMode() to set object to new state.
-  void SetMode(const gfx::ImageSkia& image,
+  // All methods use SetMode() to set object to new state.
+  void SetMode(const AccountId& account_id,
+               const gfx::ImageSkia& image,
                const wallpaper::WallpaperInfo& info,
                const base::FilePath& wallpaper_path,
                const bool is_default) {
+    account_id_ = account_id;
     user_wallpaper_ = image;
     info_ = info;
     wallpaper_path_ = wallpaper_path;
@@ -427,52 +419,65 @@
 
   // This method is usually triggered by timer to actually load request.
   void ProcessRequest() {
-    DCHECK_CURRENTLY_ON(BrowserThread::UI);
+    // The only known case for this check to fail is global destruction during
+    // wallpaper load. It should never happen.
+    if (!BrowserThread::CurrentlyOn(BrowserThread::UI))
+      return;
 
-    timer.Stop();  // Erase reference to self.
+    // Erase reference to self.
+    timer.Stop();
 
     WallpaperManager* manager = WallpaperManager::Get();
     if (manager->pending_inactive_ == this)
       manager->pending_inactive_ = NULL;
 
+    // This is "on destroy" callback that will call OnWallpaperSet() when
+    // image is loaded.
+    MovableOnDestroyCallbackHolder on_finish =
+        std::make_unique<MovableOnDestroyCallback>(
+            base::Bind(&WallpaperManager::PendingWallpaper::OnWallpaperSet,
+                       weak_factory_.GetWeakPtr()));
+
     started_load_at_ = base::Time::Now();
 
     if (default_) {
+      // The most recent request is |SetDefaultWallpaper|.
       manager->DoSetDefaultWallpaper(account_id_, true /* update_wallpaper */,
-                                     std::move(on_finish_));
+                                     std::move(on_finish));
     } else if (!user_wallpaper_.isNull()) {
+      // The most recent request is |SetWallpaperFromImage|.
       SetWallpaper(user_wallpaper_, info_);
     } else if (!wallpaper_path_.empty()) {
+      // The most recent request is |SetWallpaperFromPath|.
       manager->task_runner_->PostTask(
           FROM_HERE,
           base::BindOnce(&WallpaperManager::GetCustomWallpaperInternal,
                          account_id_, info_, wallpaper_path_,
                          true /* update wallpaper */,
                          base::ThreadTaskRunnerHandle::Get(),
-                         base::Passed(std::move(on_finish_)),
+                         base::Passed(std::move(on_finish)),
                          manager->weak_factory_.GetWeakPtr()));
     } else if (!info_.location.empty()) {
+      // The most recent request is |SetWallpaperFromInfo|.
       manager->LoadWallpaper(account_id_, info_, true /* update_wallpaper */,
-                             std::move(on_finish_));
+                             std::move(on_finish));
     } else {
-      // PendingWallpaper was created and never initialized?
+      // PendingWallpaper was created but none of the four methods was called.
+      // This should never happen. Do not record time in this case.
       NOTREACHED();
-      // Error. Do not record time.
       started_load_at_ = base::Time();
     }
-    on_finish_.reset();
   }
 
   // This method is called by callback, when load request is finished.
   void OnWallpaperSet() {
-    DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
     // The only known case for this check to fail is global destruction during
     // wallpaper load. It should never happen.
     if (!BrowserThread::CurrentlyOn(BrowserThread::UI))
-      return;  // We are in a process of global destruction.
+      return;
 
-    timer.Stop();  // Erase reference to self.
+    // Erase reference to self.
+    timer.Stop();
 
     WallpaperManager* manager = WallpaperManager::Get();
     if (!started_load_at_.is_null()) {
@@ -496,14 +501,13 @@
   // Load default wallpaper instead of user image.
   bool default_;
 
-  // This is "on destroy" callback that will call OnWallpaperSet() when
-  // image will be loaded.
-  MovableOnDestroyCallbackHolder on_finish_;
   base::OneShotTimer timer;
 
   // Load start time to calculate duration.
   base::Time started_load_at_;
 
+  base::WeakPtrFactory<PendingWallpaper> weak_factory_;
+
   DISALLOW_COPY_AND_ASSIGN(PendingWallpaper);
 };
 
@@ -614,6 +618,9 @@
   device_wallpaper_image_subscription_.reset();
   user_manager::UserManager::Get()->RemoveObserver(this);
   weak_factory_.InvalidateWeakPtrs();
+  // In case there's wallpaper load request being processed.
+  for (size_t i = 0; i < loading_.size(); ++i)
+    delete loading_[i];
 }
 
 // static
@@ -765,7 +772,7 @@
   // If decoded wallpaper is empty, we have probably failed to decode the file.
   // Use default wallpaper in this case.
   if (image.isNull()) {
-    SetDefaultWallpaperDelayed(account_id);
+    GetPendingWallpaper()->SetDefaultWallpaper(account_id);
     return;
   }
 
@@ -811,7 +818,7 @@
                         base::Time::Now().LocalMidnight()};
   SetUserWallpaperInfo(account_id, info, is_persistent);
   if (update_wallpaper) {
-    GetPendingWallpaper(account_id, false)->ResetSetWallpaperImage(image, info);
+    GetPendingWallpaper()->SetWallpaperFromImage(account_id, image, info);
   }
 
   wallpaper_cache_[account_id] = CustomWallpaperElement(wallpaper_path, image);
@@ -820,7 +827,6 @@
 void WallpaperManager::SetDefaultWallpaper(const AccountId& account_id,
                                            bool update_wallpaper) {
   RemoveUserWallpaperInfo(account_id);
-
   const wallpaper::WallpaperInfo info = {
       std::string(), wallpaper::WALLPAPER_LAYOUT_CENTER, wallpaper::DEFAULT,
       base::Time::Now().LocalMidnight()};
@@ -830,23 +836,7 @@
   SetUserWallpaperInfo(account_id, info, is_persistent);
 
   if (update_wallpaper)
-    SetDefaultWallpaperNow(account_id);
-}
-
-void WallpaperManager::SetDefaultWallpaperNow(const AccountId& account_id) {
-  GetPendingWallpaper(account_id, false)->ResetSetDefaultWallpaper();
-}
-
-void WallpaperManager::SetDefaultWallpaperDelayed(const AccountId& account_id) {
-  GetPendingWallpaper(account_id, true)->ResetSetDefaultWallpaper();
-}
-
-void WallpaperManager::SetUserWallpaperNow(const AccountId& account_id) {
-  ScheduleSetUserWallpaper(account_id, false);
-}
-
-void WallpaperManager::SetUserWallpaperDelayed(const AccountId& account_id) {
-  ScheduleSetUserWallpaper(account_id, true);
+    GetPendingWallpaper()->SetDefaultWallpaper(account_id);
 }
 
 void WallpaperManager::SetUserWallpaperInfo(const AccountId& account_id,
@@ -897,10 +887,8 @@
   wallpaper_cache_[account_id] =
       CustomWallpaperElement(base::FilePath(), image);
 
-  if (update_wallpaper) {
-    GetPendingWallpaper(last_selected_user_, false /* Not delayed */)
-        ->ResetSetWallpaperImage(image, info);
-  }
+  if (update_wallpaper)
+    GetPendingWallpaper()->SetWallpaperFromImage(account_id, image, info);
 }
 
 void WallpaperManager::InitializeWallpaper() {
@@ -936,12 +924,13 @@
 
   if (!user_manager->IsUserLoggedIn()) {
     if (!StartupUtils::IsDeviceRegistered())
-      SetDefaultWallpaperDelayed(user_manager::SignInAccountId());
+      GetPendingWallpaper()->SetDefaultWallpaper(
+          user_manager::SignInAccountId());
     else
       InitializeRegisteredDeviceWallpaper();
     return;
   }
-  SetUserWallpaperDelayed(user_manager->GetActiveUser()->GetAccountId());
+  SetUserWallpaper(user_manager->GetActiveUser()->GetAccountId());
 }
 
 void WallpaperManager::UpdateWallpaper(bool clear_cache) {
@@ -950,13 +939,13 @@
   // be set. It could result a black screen on external monitors.
   // See http://crbug.com/265689 for detail.
   if (last_selected_user_.empty())
-    SetDefaultWallpaperNow(user_manager::SignInAccountId());
+    GetPendingWallpaper()->SetDefaultWallpaper(user_manager::SignInAccountId());
 
   for (auto& observer : observers_)
     observer.OnUpdateWallpaperForTesting();
   if (clear_cache)
     wallpaper_cache_.clear();
-  SetUserWallpaperNow(last_selected_user_);
+  SetUserWallpaper(last_selected_user_);
 }
 
 bool WallpaperManager::IsPendingWallpaper(uint32_t image_id) {
@@ -1023,7 +1012,7 @@
     if (info == current_user_wallpaper_info_)
       return;
   }
-  SetUserWallpaperNow(
+  SetUserWallpaper(
       user_manager::UserManager::Get()->GetActiveUser()->GetAccountId());
 }
 
@@ -1119,7 +1108,7 @@
   // If we're at the login screen, do not change the wallpaper but defer it
   // until the user logs in to the system.
   if (user_manager::UserManager::Get()->IsUserLoggedIn())
-    SetDefaultWallpaperNow(account_id);
+    GetPendingWallpaper()->SetDefaultWallpaper(account_id);
 }
 
 void WallpaperManager::SetCustomizedDefaultWallpaper(
@@ -1220,7 +1209,7 @@
 }
 
 void WallpaperManager::OnChildStatusChanged(const user_manager::User& user) {
-  SetUserWallpaperNow(user.GetAccountId());
+  SetUserWallpaper(user.GetAccountId());
 }
 
 void WallpaperManager::OnWindowActivated(ActivationReason reason,
@@ -1582,7 +1571,8 @@
       !HasNonDeviceLocalAccounts(users)) {
     // Boot into sign in form, preload default wallpaper.
     if (!SetDeviceWallpaperIfApplicable(user_manager::SignInAccountId()))
-      SetDefaultWallpaperDelayed(user_manager::SignInAccountId());
+      GetPendingWallpaper()->SetDefaultWallpaper(
+          user_manager::SignInAccountId());
     return;
   }
 
@@ -1591,7 +1581,7 @@
     // Normal boot, load user wallpaper.
     // If normal boot animation is disabled wallpaper would be set
     // asynchronously once user pods are loaded.
-    SetUserWallpaperDelayed(users[index]->GetAccountId());
+    SetUserWallpaper(users[index]->GetAccountId());
   }
 }
 
@@ -1808,8 +1798,7 @@
     SetWallpaper(user_image->image(), info);
 }
 
-void WallpaperManager::ScheduleSetUserWallpaper(const AccountId& account_id,
-                                                bool delayed) {
+void WallpaperManager::SetUserWallpaper(const AccountId& account_id) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   // Some unit tests come here without a UserManager or without a pref system.
   if (!user_manager::UserManager::IsInitialized() ||
@@ -1838,7 +1827,7 @@
        user->HasGaiaAccount()) ||
       user->GetType() == user_manager::USER_TYPE_GUEST) {
     InitInitialUserWallpaper(account_id, false);
-    GetPendingWallpaper(account_id, delayed)->ResetSetDefaultWallpaper();
+    GetPendingWallpaper()->SetDefaultWallpaper(account_id);
     if (base::SysInfo::IsRunningOnChromeOS()) {
       LOG(ERROR)
           << "User is ephemeral or guest! Fallback to default wallpaper.";
@@ -1858,13 +1847,13 @@
   gfx::ImageSkia user_wallpaper;
   current_user_wallpaper_info_ = info;
   if (GetWallpaperFromCache(account_id, &user_wallpaper)) {
-    GetPendingWallpaper(account_id, delayed)
-        ->ResetSetWallpaperImage(user_wallpaper, info);
+    GetPendingWallpaper()->SetWallpaperFromImage(account_id, user_wallpaper,
+                                                 info);
   } else {
     if (info.location.empty()) {
       // Uses default built-in wallpaper when file is empty. Eventually, we
       // will only ship one built-in wallpaper in ChromeOS image.
-      GetPendingWallpaper(account_id, delayed)->ResetSetDefaultWallpaper();
+      GetPendingWallpaper()->SetDefaultWallpaper(account_id);
       return;
     }
 
@@ -1897,13 +1886,14 @@
           CustomWallpaperElement(wallpaper_path, gfx::ImageSkia());
       loaded_wallpapers_for_test_++;
 
-      GetPendingWallpaper(account_id, delayed)
-          ->ResetSetCustomWallpaper(info, wallpaper_path);
+      GetPendingWallpaper()->SetWallpaperFromPath(account_id, info,
+                                                  wallpaper_path);
       return;
     }
 
-    // Load downloaded ONLINE or converted DEFAULT wallpapers.
-    GetPendingWallpaper(account_id, delayed)->ResetLoadWallpaper(info);
+    // Load downloaded online or converted default wallpapers according to the
+    // WallpaperInfo.
+    GetPendingWallpaper()->SetWallpaperFromInfo(account_id, info);
   }
 }
 
@@ -2007,22 +1997,22 @@
   if (last_load_times_.size() == 0) {
     delay = base::TimeDelta::FromMilliseconds(kLoadDefaultDelayMs);
   } else {
+    // Calculate the average loading time.
     delay = std::accumulate(last_load_times_.begin(), last_load_times_.end(),
                             base::TimeDelta(), std::plus<base::TimeDelta>()) /
             last_load_times_.size();
-  }
 
-  if (delay < base::TimeDelta::FromMilliseconds(kLoadMinDelayMs))
-    delay = base::TimeDelta::FromMilliseconds(kLoadMinDelayMs);
-  else if (delay > base::TimeDelta::FromMilliseconds(kLoadMaxDelayMs))
-    delay = base::TimeDelta::FromMilliseconds(kLoadMaxDelayMs);
+    if (delay < base::TimeDelta::FromMilliseconds(kLoadMinDelayMs))
+      delay = base::TimeDelta::FromMilliseconds(kLoadMinDelayMs);
+    else if (delay > base::TimeDelta::FromMilliseconds(kLoadMaxDelayMs))
+      delay = base::TimeDelta::FromMilliseconds(kLoadMaxDelayMs);
 
-  // If we had ever loaded wallpaper, adjust wait delay by time since last load.
-  if (!last_load_finished_at_.is_null()) {
+    // Reduce the delay by the time passed after the last wallpaper load.
+    DCHECK(!last_load_finished_at_.is_null());
     const base::TimeDelta interval = base::Time::Now() - last_load_finished_at_;
     if (interval > delay)
       delay = base::TimeDelta::FromMilliseconds(0);
-    else if (interval > base::TimeDelta::FromMilliseconds(0))
+    else
       delay -= interval;
   }
   return delay;
@@ -2222,26 +2212,25 @@
   DoSetDefaultWallpaper(account_id, update_wallpaper, std::move(on_finish));
 }
 
-WallpaperManager::PendingWallpaper* WallpaperManager::GetPendingWallpaper(
-    const AccountId& account_id,
-    bool delayed) {
+WallpaperManager::PendingWallpaper* WallpaperManager::GetPendingWallpaper() {
+  // If |pending_inactive_| already exists, return it directly. This allows the
+  // pending request (whose timer is still running) to be overriden by a
+  // subsequent request.
   if (!pending_inactive_) {
-    loading_.push_back(new WallpaperManager::PendingWallpaper(
-        (delayed ? GetWallpaperLoadDelay()
-                 : base::TimeDelta::FromMilliseconds(0)),
-        account_id));
-    pending_inactive_ = loading_.back().get();
+    loading_.push_back(
+        new WallpaperManager::PendingWallpaper(GetWallpaperLoadDelay()));
+    pending_inactive_ = loading_.back();
   }
   return pending_inactive_;
 }
 
 void WallpaperManager::RemovePendingWallpaperFromList(
-    PendingWallpaper* pending) {
+    PendingWallpaper* finished_loading_request) {
   DCHECK(loading_.size() > 0);
-  for (WallpaperManager::PendingList::iterator i = loading_.begin();
-       i != loading_.end(); ++i) {
-    if (i->get() == pending) {
-      loading_.erase(i);
+  for (size_t i = 0; i < loading_.size(); ++i) {
+    if (loading_[i] == finished_loading_request) {
+      delete loading_[i];
+      loading_.erase(loading_.begin() + i);
       break;
     }
   }
@@ -2314,7 +2303,7 @@
   if (!success) {
     LOG(ERROR) << "Failed to download the device wallpaper. Fallback to "
                   "default wallpaper.";
-    SetDefaultWallpaperDelayed(account_id);
+    GetPendingWallpaper()->SetDefaultWallpaper(account_id);
     return;
   }
 
@@ -2346,7 +2335,7 @@
     } else {
       LOG(ERROR) << "The device wallpaper hash doesn't match with provided "
                     "hash value. Fallback to default wallpaper! ";
-      SetDefaultWallpaperDelayed(account_id);
+      GetPendingWallpaper()->SetDefaultWallpaper(account_id);
 
       // Reset the boolean variable so that it can retry to download when the
       // next device wallpaper request comes in.
@@ -2373,8 +2362,8 @@
                                     wallpaper::WALLPAPER_LAYOUT_CENTER_CROPPED,
                                     wallpaper::DEVICE,
                                     base::Time::Now().LocalMidnight()};
-    GetPendingWallpaper(user_manager::SignInAccountId(), false)
-        ->ResetSetWallpaperImage(user_image->image(), wallpaper_info);
+    GetPendingWallpaper()->SetWallpaperFromImage(
+        account_id, user_image->image(), wallpaper_info);
   }
 }
 
diff --git a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.h b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.h
index fd3d2b4..bf1dabc3 100644
--- a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.h
+++ b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.h
@@ -257,30 +257,21 @@
                           const gfx::ImageSkia& image,
                           bool update_wallpaper);
 
-  // Updates wallpaper info for |account_id| to default. If |update_wallpaper|
-  // is false, don't change wallpaper but only update cache.
+  // Sets default wallpaper. |update_wallpaper| indicates whether to actually
+  // change the wallpaper, or only update cache.
   void SetDefaultWallpaper(const AccountId& account_id, bool update_wallpaper);
 
-  // Sets wallpaper to default wallpaper (asynchronously with zero delay).
-  void SetDefaultWallpaperNow(const AccountId& account_id);
+  // Sets |account_id|'s wallpaper.
+  void SetUserWallpaper(const AccountId& account_id);
 
-  // Sets wallpaper to default wallpaper (asynchronously with default delay).
-  void SetDefaultWallpaperDelayed(const AccountId& account_id);
-
-  // Sets |account_id|'s wallpaper (asynchronously with zero delay).
-  void SetUserWallpaperNow(const AccountId& account_id);
-
-  // Sets |account_id|'s wallpaper (asynchronously with default delay).
-  void SetUserWallpaperDelayed(const AccountId& account_id);
-
-  // Sets selected wallpaper information for |account_id| and saves it to Local
-  // State if |is_persistent| is true.
+  // Sets wallpaper info for |account_id| and saves it to local state if
+  // |is_persistent| is true.
   void SetUserWallpaperInfo(const AccountId& account_id,
                             const wallpaper::WallpaperInfo& info,
                             bool is_persistent);
 
-  // Sets wallpaper to |image| (asynchronously with zero delay). If
-  // |update_wallpaper| is false, skip change wallpaper but only update cache.
+  // Sets wallpaper to |image|. If |update_wallpaper| is false, skip change
+  // wallpaper but only update cache.
   void SetWallpaperFromImageSkia(const AccountId& account_id,
                                  const gfx::ImageSkia& image,
                                  wallpaper::WallpaperLayout layout,
@@ -292,7 +283,7 @@
   void InitializeWallpaper();
 
   // Updates current wallpaper. It may switch the size of wallpaper based on the
-  // current display's resolution. (asynchronously with zero delay)
+  // current display's resolution.
   void UpdateWallpaper(bool clear_cache);
 
   // Returns if the image is in the pending list. |image_id| can be obtained
@@ -515,9 +506,6 @@
                           MovableOnDestroyCallbackHolder on_finish,
                           std::unique_ptr<user_manager::UserImage> user_image);
 
-  // Creates new PendingWallpaper request (or updates currently pending).
-  void ScheduleSetUserWallpaper(const AccountId& account_id, bool delayed);
-
   // Sets wallpaper to default if |update_wallpaper| is true. Otherwise just
   // load defaut wallpaper to cache.
   void DoSetDefaultWallpaper(const AccountId& account_id,
@@ -538,11 +526,9 @@
   // Notify all registered observers.
   void NotifyAnimationFinished();
 
-  // Calculate delay for next wallpaper load.
-  // It is usually average wallpaper load time.
-  // If last wallpaper load happened long ago, timeout should be reduced by
-  // the time passed after last wallpaper load. So usual user experience results
-  // in zero delay.
+  // Calculates delay for the next wallpaper load. In most cases it is zero. It
+  // starts with the average wallpaper load time, and is reduced by the time
+  // passed after the last wallpaper load.
   base::TimeDelta GetWallpaperLoadDelay() const;
 
   // This is called after we check that supplied default wallpaper files exist.
@@ -606,13 +592,13 @@
                                      bool update_wallpaper,
                                      MovableOnDestroyCallbackHolder on_finish);
 
-  // Returns modifiable PendingWallpaper.
-  // Returns pending_inactive_ or creates new PendingWallpaper if necessary.
-  PendingWallpaper* GetPendingWallpaper(const AccountId& account_id,
-                                        bool delayed);
+  // Returns modifiable PendingWallpaper. (Either |pending_inactive_| or a new
+  // |PendingWallpaper| object.)
+  PendingWallpaper* GetPendingWallpaper();
 
   // This is called by PendingWallpaper when load is finished.
-  void RemovePendingWallpaperFromList(PendingWallpaper* pending);
+  void RemovePendingWallpaperFromList(
+      PendingWallpaper* finished_loading_request);
 
   // Set wallpaper to |user_image| controlled by policy.  (Takes a UserImage
   // because that's the callback interface provided by UserImageLoader.)
@@ -718,7 +704,7 @@
   // Owns PendingWallpaper.
   // PendingWallpaper deletes itself from here on load complete.
   // All pending will be finally deleted on destroy.
-  typedef std::vector<scoped_refptr<PendingWallpaper>> PendingList;
+  typedef std::vector<PendingWallpaper*> PendingList;
   PendingList loading_;
 
   content::NotificationRegistrar registrar_;
diff --git a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager_browsertest.cc b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager_browsertest.cc
index 5be5c10c..e91ef1c 100644
--- a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager_browsertest.cc
+++ b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager_browsertest.cc
@@ -236,7 +236,7 @@
   wallpaper_manager->SetUserWallpaperInfo(test_account_id1_, info, true);
 
   // Set the wallpaper for |test_account_id1_|.
-  wallpaper_manager->SetUserWallpaperNow(test_account_id1_);
+  wallpaper_manager->SetUserWallpaper(test_account_id1_);
   wallpaper_manager_test_utils::WaitAsyncWallpaperLoadFinished();
   gfx::ImageSkia wallpaper = controller_->GetWallpaper();
 
@@ -285,15 +285,16 @@
   WallpaperManager* wallpaper_manager = WallpaperManager::Get();
   // New user log in, a default wallpaper is loaded.
   LogIn(test_account_id1_, kTestUser1Hash);
+  wallpaper_manager_test_utils::WaitAsyncWallpaperLoadFinished();
   EXPECT_EQ(1, LoadedWallpapers());
   // Loads the same wallpaper before the initial one finished. It should be
   // prevented.
-  wallpaper_manager->SetUserWallpaperNow(test_account_id1_);
+  wallpaper_manager->SetUserWallpaper(test_account_id1_);
   wallpaper_manager_test_utils::WaitAsyncWallpaperLoadFinished();
   EXPECT_EQ(1, LoadedWallpapers());
   // Loads the same wallpaper after the initial one finished. It should be
   // prevented.
-  wallpaper_manager->SetUserWallpaperNow(test_account_id1_);
+  wallpaper_manager->SetUserWallpaper(test_account_id1_);
   wallpaper_manager_test_utils::WaitAsyncWallpaperLoadFinished();
   EXPECT_EQ(1, LoadedWallpapers());
   ClearDisposableWallpaperCache();
@@ -314,15 +315,15 @@
                         base::Time::Now().LocalMidnight()};
   wallpaper_manager->SetUserWallpaperInfo(test_account_id1_, info, true);
 
-  wallpaper_manager->SetUserWallpaperNow(test_account_id1_);
+  wallpaper_manager->SetUserWallpaper(test_account_id1_);
   WaitAsyncWallpaperLoadStarted();
   EXPECT_EQ(2, LoadedWallpapers());
   // Loads the same wallpaper before the initial one finished. It should be
   // prevented.
-  wallpaper_manager->SetUserWallpaperNow(test_account_id1_);
+  wallpaper_manager->SetUserWallpaper(test_account_id1_);
   WaitAsyncWallpaperLoadStarted();
   EXPECT_EQ(2, LoadedWallpapers());
-  wallpaper_manager->SetUserWallpaperNow(test_account_id1_);
+  wallpaper_manager->SetUserWallpaper(test_account_id1_);
   wallpaper_manager_test_utils::WaitAsyncWallpaperLoadFinished();
   EXPECT_EQ(2, LoadedWallpapers());
 }
@@ -383,8 +384,8 @@
                        HotPlugInScreenAtGAIALoginScreen) {
   UpdateDisplay("800x600");
   // Set initial wallpaper to the default wallpaper.
-  WallpaperManager::Get()->SetDefaultWallpaperNow(
-      user_manager::StubAccountId());
+  WallpaperManager::Get()->SetDefaultWallpaper(user_manager::StubAccountId(),
+                                               true /* update_wallpaper */);
   wallpaper_manager_test_utils::WaitAsyncWallpaperLoadFinished();
 
   // Hook up a 2000x2000 display. The large resolution custom wallpaper should
@@ -482,6 +483,7 @@
 #endif
 IN_PROC_BROWSER_TEST_F(WallpaperManagerBrowserTestCrashRestore,
                        MAYBE_RestoreWallpaper) {
+  wallpaper_manager_test_utils::WaitAsyncWallpaperLoadFinished();
   EXPECT_EQ(1, LoadedWallpapers());
 }
 
@@ -524,11 +526,11 @@
                         wallpaper::CUSTOMIZED,
                         base::Time::Now().LocalMidnight()};
   wallpaper_manager->SetUserWallpaperInfo(test_account_id1_, info, true);
-  wallpaper_manager->SetUserWallpaperNow(test_account_id1_);
+  wallpaper_manager->SetUserWallpaper(test_account_id1_);
   wallpaper_manager_test_utils::WaitAsyncWallpaperLoadFinished();
   std::unique_ptr<WallpaperManager::TestApi> test_api;
   test_api.reset(new WallpaperManager::TestApi(wallpaper_manager));
-  // Verify SetUserWallpaperNow updates wallpaper cache.
+  // Verify SetUserWallpaper updates wallpaper cache.
   gfx::ImageSkia cached_wallpaper;
   EXPECT_TRUE(
       test_api->GetWallpaperFromCache(test_account_id1_, &cached_wallpaper));
@@ -601,7 +603,8 @@
   EXPECT_TRUE(test_api->GetPathFromCache(test_account_id1_, &path));
   EXPECT_NE(original_path, path);
 
-  wallpaper_manager->SetDefaultWallpaperNow(test_account_id1_);
+  wallpaper_manager->SetDefaultWallpaper(test_account_id1_,
+                                         true /* update_wallpaper */);
   wallpaper_manager_test_utils::WaitAsyncWallpaperLoadFinished();
   // SetDefaultWallpaper should invalidate the user's wallpaper cache.
   EXPECT_FALSE(
@@ -731,7 +734,8 @@
 
   // At 800x600, the small wallpaper should be loaded.
   UpdateDisplay("800x600");
-  WallpaperManager::Get()->SetDefaultWallpaperNow(EmptyAccountId());
+  WallpaperManager::Get()->SetDefaultWallpaper(EmptyAccountId(),
+                                               true /* update_wallpaper */);
   wallpaper_manager_test_utils::WaitAsyncWallpaperLoadFinished();
   EXPECT_TRUE(wallpaper_manager_test_utils::ImageIsNearColor(
       controller_->GetWallpaper(),
@@ -741,7 +745,8 @@
 IN_PROC_BROWSER_TEST_F(WallpaperManagerBrowserTest, LargeDefaultWallpaper) {
   CreateCmdlineWallpapers();
   UpdateDisplay("1600x1200");
-  WallpaperManager::Get()->SetDefaultWallpaperNow(EmptyAccountId());
+  WallpaperManager::Get()->SetDefaultWallpaper(EmptyAccountId(),
+                                               true /* update_wallpaper */);
   wallpaper_manager_test_utils::WaitAsyncWallpaperLoadFinished();
   EXPECT_TRUE(wallpaper_manager_test_utils::ImageIsNearColor(
       controller_->GetWallpaper(),
@@ -753,7 +758,8 @@
   CreateCmdlineWallpapers();
 
   UpdateDisplay("1200x800/r");
-  WallpaperManager::Get()->SetDefaultWallpaperNow(EmptyAccountId());
+  WallpaperManager::Get()->SetDefaultWallpaper(EmptyAccountId(),
+                                               true /* update_wallpaper */);
   wallpaper_manager_test_utils::WaitAsyncWallpaperLoadFinished();
   EXPECT_TRUE(wallpaper_manager_test_utils::ImageIsNearColor(
       controller_->GetWallpaper(),
@@ -765,7 +771,8 @@
   SessionManager::Get()->CreateSession(user_manager::GuestAccountId(),
                                        user_manager::kGuestUserName);
   UpdateDisplay("800x600");
-  WallpaperManager::Get()->SetDefaultWallpaperNow(EmptyAccountId());
+  WallpaperManager::Get()->SetDefaultWallpaper(user_manager::GuestAccountId(),
+                                               true /* update_wallpaper */);
   wallpaper_manager_test_utils::WaitAsyncWallpaperLoadFinished();
   EXPECT_TRUE(wallpaper_manager_test_utils::ImageIsNearColor(
       controller_->GetWallpaper(),
@@ -777,7 +784,8 @@
   SessionManager::Get()->CreateSession(user_manager::GuestAccountId(),
                                        user_manager::kGuestUserName);
   UpdateDisplay("1600x1200");
-  WallpaperManager::Get()->SetDefaultWallpaperNow(EmptyAccountId());
+  WallpaperManager::Get()->SetDefaultWallpaper(user_manager::GuestAccountId(),
+                                               true /* update_wallpaper */);
   wallpaper_manager_test_utils::WaitAsyncWallpaperLoadFinished();
   EXPECT_TRUE(wallpaper_manager_test_utils::ImageIsNearColor(
       controller_->GetWallpaper(),
@@ -788,7 +796,8 @@
   CreateCmdlineWallpapers();
   LogInAsChild(test_account_id1_, kTestUser1Hash);
   UpdateDisplay("800x600");
-  WallpaperManager::Get()->SetDefaultWallpaperNow(EmptyAccountId());
+  WallpaperManager::Get()->SetDefaultWallpaper(test_account_id1_,
+                                               true /* update_wallpaper */);
   wallpaper_manager_test_utils::WaitAsyncWallpaperLoadFinished();
   EXPECT_TRUE(wallpaper_manager_test_utils::ImageIsNearColor(
       controller_->GetWallpaper(),
@@ -799,7 +808,8 @@
   CreateCmdlineWallpapers();
   LogInAsChild(test_account_id1_, kTestUser1Hash);
   UpdateDisplay("1600x1200");
-  WallpaperManager::Get()->SetDefaultWallpaperNow(EmptyAccountId());
+  WallpaperManager::Get()->SetDefaultWallpaper(test_account_id1_,
+                                               true /* update_wallpaper */);
   wallpaper_manager_test_utils::WaitAsyncWallpaperLoadFinished();
   EXPECT_TRUE(wallpaper_manager_test_utils::ImageIsNearColor(
       controller_->GetWallpaper(),
@@ -814,7 +824,8 @@
   SessionManager::Get()->CreateSession(user_manager::StubAccountId(),
                                        "test_hash");
 
-  WallpaperManager::Get()->SetDefaultWallpaperNow(EmptyAccountId());
+  WallpaperManager::Get()->SetDefaultWallpaper(user_manager::StubAccountId(),
+                                               true /* update_wallpaper */);
 
   // Custom wallpaper should be applied immediately, canceling the default
   // wallpaper load task.
@@ -830,7 +841,8 @@
       controller_->GetWallpaper(),
       wallpaper_manager_test_utils::kCustomWallpaperColor));
 
-  WallpaperManager::Get()->SetDefaultWallpaperNow(EmptyAccountId());
+  WallpaperManager::Get()->SetDefaultWallpaper(user_manager::StubAccountId(),
+                                               true /* update_wallpaper */);
   wallpaper_manager_test_utils::WaitAsyncWallpaperLoadFinished();
 
   EXPECT_TRUE(wallpaper_manager_test_utils::ImageIsNearColor(
@@ -845,7 +857,8 @@
   SessionManager::Get()->CreateSession(user_manager::StubAccountId(),
                                        "test_hash");
 
-  WallpaperManager::Get()->SetDefaultWallpaperNow(EmptyAccountId());
+  WallpaperManager::Get()->SetDefaultWallpaper(user_manager::StubAccountId(),
+                                               true /* update_wallpaper */);
 
   gfx::ImageSkia image = wallpaper_manager_test_utils::CreateTestImage(
       640, 480, wallpaper_manager_test_utils::kCustomWallpaperColor);
@@ -893,7 +906,7 @@
                          wallpaper::CUSTOMIZED,
                          base::Time::Now().LocalMidnight()};
   wallpaper_manager->SetUserWallpaperInfo(test_account_id2_, info2, true);
-  wallpaper_manager->SetUserWallpaperNow(test_account_id2_);
+  wallpaper_manager->SetUserWallpaper(test_account_id2_);
   wallpaper_manager_test_utils::WaitAsyncWallpaperLoadFinished();
   EXPECT_TRUE(wallpaper_manager_test_utils::ImageIsNearColor(
       controller_->GetWallpaper(),
@@ -947,7 +960,7 @@
                         wallpaper::CUSTOMIZED,
                         base::Time::Now().LocalMidnight()};
   wallpaper_manager->SetUserWallpaperInfo(test_account_id1_, info, true);
-  wallpaper_manager->SetUserWallpaperNow(test_account_id1_);
+  wallpaper_manager->SetUserWallpaper(test_account_id1_);
   wallpaper_manager_test_utils::WaitAsyncWallpaperLoadFinished();
   EXPECT_TRUE(base::PathExists(small_wallpaper_path));
 
@@ -967,7 +980,7 @@
                          wallpaper::CUSTOMIZED,
                          base::Time::Now().LocalMidnight()};
   wallpaper_manager->SetUserWallpaperInfo(test_account_id2_, info2, true);
-  wallpaper_manager->SetUserWallpaperNow(test_account_id2_);
+  wallpaper_manager->SetUserWallpaper(test_account_id2_);
   wallpaper_manager_test_utils::WaitAsyncWallpaperLoadFinished();
   EXPECT_TRUE(base::PathExists(small_wallpaper_path2));
 
@@ -1008,7 +1021,7 @@
                         wallpaper::CUSTOMIZED,
                         base::Time::Now().LocalMidnight()};
   wallpaper_manager->SetUserWallpaperInfo(test_account_id1_, info, true);
-  wallpaper_manager->SetUserWallpaperNow(test_account_id1_);
+  wallpaper_manager->SetUserWallpaper(test_account_id1_);
   wallpaper_manager_test_utils::WaitAsyncWallpaperLoadFinished();
   EXPECT_TRUE(base::PathExists(small_wallpaper_path));
 
@@ -1019,7 +1032,8 @@
   WallpaperInfo info2 = {"", WALLPAPER_LAYOUT_CENTER_CROPPED,
                          wallpaper::DEFAULT, base::Time::Now().LocalMidnight()};
   wallpaper_manager->SetUserWallpaperInfo(test_account_id2_, info2, true);
-  WallpaperManager::Get()->SetDefaultWallpaperNow(test_account_id2_);
+  WallpaperManager::Get()->SetDefaultWallpaper(test_account_id2_,
+                                               true /* update_wallpaper */);
   wallpaper_manager_test_utils::WaitAsyncWallpaperLoadFinished();
 
   // Simulate the removal of |test_account_id2_|.
diff --git a/chrome/browser/notifications/arc_application_notifier_controller_chromeos.cc b/chrome/browser/notifications/arc_application_notifier_controller_chromeos.cc
index b792878..f168082 100644
--- a/chrome/browser/notifications/arc_application_notifier_controller_chromeos.cc
+++ b/chrome/browser/notifications/arc_application_notifier_controller_chromeos.cc
@@ -29,14 +29,14 @@
   StopObserving();
 }
 
-std::vector<std::unique_ptr<message_center::NotifierUiData>>
+std::vector<ash::mojom::NotifierUiDataPtr>
 ArcApplicationNotifierControllerChromeOS::GetNotifierList(Profile* profile) {
   package_to_app_ids_.clear();
   icons_.clear();
   StopObserving();
 
   ArcAppListPrefs* const app_list = ArcAppListPrefs::Get(profile);
-  std::vector<std::unique_ptr<message_center::NotifierUiData>> results;
+  std::vector<ash::mojom::NotifierUiDataPtr> results;
   // The app list can be null in unit tests.
   if (!app_list)
     return results;
@@ -69,10 +69,9 @@
     package_to_app_ids_.insert(std::make_pair(app->package_name, app_id));
     message_center::NotifierId notifier_id(
         message_center::NotifierId::ARC_APPLICATION, app_id);
-    auto ui_data = std::make_unique<message_center::NotifierUiData>(
+    auto ui_data = ash::mojom::NotifierUiData::New(
         notifier_id, base::UTF8ToUTF16(app->name), false,
-        app->notifications_enabled);
-    ui_data->icon = gfx::Image(icon->image_skia());
+        app->notifications_enabled, icon->image_skia());
     icons_.push_back(std::move(icon));
     results.push_back(std::move(ui_data));
   }
@@ -105,7 +104,7 @@
   observer_->OnIconImageUpdated(
       message_center::NotifierId(message_center::NotifierId::ARC_APPLICATION,
                                  icon->app_id()),
-      gfx::Image(icon->image_skia()));
+      icon->image_skia());
 }
 
 void ArcApplicationNotifierControllerChromeOS::StopObserving() {
diff --git a/chrome/browser/notifications/arc_application_notifier_controller_chromeos.h b/chrome/browser/notifications/arc_application_notifier_controller_chromeos.h
index 75b2c65..29b9d219 100644
--- a/chrome/browser/notifications/arc_application_notifier_controller_chromeos.h
+++ b/chrome/browser/notifications/arc_application_notifier_controller_chromeos.h
@@ -31,14 +31,14 @@
   ~ArcApplicationNotifierControllerChromeOS() override;
 
   // TODO(hirono): Rewrite the function with new API to fetch package list.
-  std::vector<std::unique_ptr<message_center::NotifierUiData>> GetNotifierList(
+  std::vector<ash::mojom::NotifierUiDataPtr> GetNotifierList(
       Profile* profile) override;
   void SetNotifierEnabled(Profile* profile,
                           const message_center::NotifierId& notifier_id,
                           bool enabled) override;
 
  private:
-  // Overriden from ArcAppIcon::Observer.
+  // Overridden from ArcAppIcon::Observer.
   void OnIconUpdated(ArcAppIcon* icon) override;
   void StopObserving();
 
diff --git a/chrome/browser/notifications/chrome_ash_message_center_client.cc b/chrome/browser/notifications/chrome_ash_message_center_client.cc
new file mode 100644
index 0000000..ef18cd2
--- /dev/null
+++ b/chrome/browser/notifications/chrome_ash_message_center_client.cc
@@ -0,0 +1,182 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/notifications/chrome_ash_message_center_client.h"
+
+#include "ash/public/interfaces/ash_message_center_controller.mojom.h"
+#include "ash/public/interfaces/constants.mojom.h"
+#include "base/i18n/string_compare.h"
+#include "chrome/browser/chromeos/profiles/profile_helper.h"
+#include "chrome/browser/notifications/arc_application_notifier_controller_chromeos.h"
+#include "chrome/browser/notifications/extension_notifier_controller.h"
+#include "chrome/browser/notifications/web_page_notifier_controller.h"
+#include "components/user_manager/user_manager.h"
+#include "content/public/common/service_manager_connection.h"
+#include "mojo/public/cpp/bindings/associated_binding.h"
+#include "services/service_manager/public/cpp/connector.h"
+#include "ui/message_center/notifier_settings.h"
+
+using ash::mojom::NotifierUiDataPtr;
+using message_center::NotifierId;
+
+namespace {
+
+// All notifier actions are performed on the notifiers for the currently active
+// profile, so this just returns the active profile.
+Profile* GetProfileForNotifiers() {
+  return chromeos::ProfileHelper::Get()->GetProfileByUser(
+      user_manager::UserManager::Get()->GetActiveUser());
+}
+
+class NotifierComparator {
+ public:
+  explicit NotifierComparator(icu::Collator* collator) : collator_(collator) {}
+
+  bool operator()(const NotifierUiDataPtr& n1, const NotifierUiDataPtr& n2) {
+    if (n1->notifier_id.type != n2->notifier_id.type)
+      return n1->notifier_id.type < n2->notifier_id.type;
+
+    if (collator_) {
+      return base::i18n::CompareString16WithCollator(*collator_, n1->name,
+                                                     n2->name) == UCOL_LESS;
+    }
+    return n1->name < n2->name;
+  }
+
+ private:
+  icu::Collator* collator_;
+};
+
+}  // namespace
+
+ChromeAshMessageCenterClient::ChromeAshMessageCenterClient(
+    NotificationPlatformBridgeDelegate* delegate)
+    : delegate_(delegate), binding_(this) {
+  // May be null in unit tests.
+  auto* connection = content::ServiceManagerConnection::GetForProcess();
+  if (connection) {
+    connection->GetConnector()->BindInterface(ash::mojom::kServiceName,
+                                              &controller_);
+
+    // Register this object as the client interface implementation.
+    ash::mojom::AshMessageCenterClientAssociatedPtrInfo ptr_info;
+    binding_.Bind(mojo::MakeRequest(&ptr_info));
+    controller_->SetClient(std::move(ptr_info));
+  }
+
+  sources_.insert(std::make_pair(NotifierId::APPLICATION,
+                                 std::unique_ptr<NotifierController>(
+                                     new ExtensionNotifierController(this))));
+
+  sources_.insert(std::make_pair(NotifierId::WEB_PAGE,
+                                 std::unique_ptr<NotifierController>(
+                                     new WebPageNotifierController(this))));
+
+  sources_.insert(std::make_pair(
+      NotifierId::ARC_APPLICATION,
+      std::unique_ptr<NotifierController>(
+          new arc::ArcApplicationNotifierControllerChromeOS(this))));
+}
+
+ChromeAshMessageCenterClient::~ChromeAshMessageCenterClient() {}
+
+// The unused variables here will not be a part of the future
+// NotificationPlatformBridge interface.
+void ChromeAshMessageCenterClient::Display(
+    NotificationCommon::Type /*notification_type*/,
+    const std::string& /*notification_id*/,
+    const std::string& /*profile_id*/,
+    bool /*is_incognito*/,
+    const message_center::Notification& notification,
+    std::unique_ptr<NotificationCommon::Metadata> metadata) {
+  controller_->ShowClientNotification(notification);
+}
+
+// The unused variable here will not be a part of the future
+// NotificationPlatformBridge interface.
+void ChromeAshMessageCenterClient::Close(const std::string& /*profile_id*/,
+                                         const std::string& notification_id) {
+  // TODO(estade): tell the controller to close the notification.
+  NOTIMPLEMENTED();
+}
+
+// The unused variables here will not be a part of the future
+// NotificationPlatformBridge interface.
+void ChromeAshMessageCenterClient::GetDisplayed(
+    const std::string& /*profile_id*/,
+    bool /*incognito*/,
+    const GetDisplayedNotificationsCallback& callback) const {
+  // TODO(estade): get the displayed notifications from the controller.
+  NOTIMPLEMENTED();
+}
+
+void ChromeAshMessageCenterClient::SetReadyCallback(
+    NotificationBridgeReadyCallback callback) {
+  std::move(callback).Run(true);
+}
+
+void ChromeAshMessageCenterClient::HandleNotificationClosed(
+    const std::string& id,
+    bool by_user) {
+  delegate_->HandleNotificationClosed(id, by_user);
+}
+
+void ChromeAshMessageCenterClient::HandleNotificationClicked(
+    const std::string& id) {
+  delegate_->HandleNotificationClicked(id);
+}
+
+void ChromeAshMessageCenterClient::HandleNotificationButtonClicked(
+    const std::string& id,
+    int button_index) {
+  delegate_->HandleNotificationButtonClicked(id, button_index);
+}
+
+void ChromeAshMessageCenterClient::SetNotifierEnabled(
+    const NotifierId& notifier_id,
+    bool enabled) {
+  sources_[notifier_id.type]->SetNotifierEnabled(GetProfileForNotifiers(),
+                                                 notifier_id, enabled);
+}
+
+void ChromeAshMessageCenterClient::HandleNotifierAdvancedSettingsRequested(
+    const NotifierId& notifier_id) {
+  sources_[notifier_id.type]->OnNotifierAdvancedSettingsRequested(
+      GetProfileForNotifiers(), notifier_id);
+}
+
+void ChromeAshMessageCenterClient::GetNotifierList(
+    GetNotifierListCallback callback) {
+  std::vector<ash::mojom::NotifierUiDataPtr> notifiers;
+  for (auto& source : sources_) {
+    auto source_notifiers =
+        source.second->GetNotifierList(GetProfileForNotifiers());
+    for (auto& notifier : source_notifiers) {
+      notifiers.push_back(std::move(notifier));
+    }
+  }
+
+  UErrorCode error = U_ZERO_ERROR;
+  std::unique_ptr<icu::Collator> collator(icu::Collator::createInstance(error));
+  NotifierComparator comparator(U_SUCCESS(error) ? collator.get() : nullptr);
+  std::sort(notifiers.begin(), notifiers.end(), comparator);
+
+  std::move(callback).Run(std::move(notifiers));
+}
+
+void ChromeAshMessageCenterClient::OnIconImageUpdated(
+    const NotifierId& notifier_id,
+    const gfx::ImageSkia& image) {
+  // |controller_| may be null in unit tests.
+  if (!image.isNull() && controller_)
+    controller_->UpdateNotifierIcon(notifier_id, image);
+}
+
+void ChromeAshMessageCenterClient::OnNotifierEnabledChanged(
+    const NotifierId& notifier_id,
+    bool enabled) {
+  // May be null in unit tests.
+  if (controller_)
+    controller_->NotifierEnabledChanged(notifier_id, enabled);
+}
diff --git a/chrome/browser/notifications/chrome_ash_message_center_client.h b/chrome/browser/notifications/chrome_ash_message_center_client.h
new file mode 100644
index 0000000..c381ad2
--- /dev/null
+++ b/chrome/browser/notifications/chrome_ash_message_center_client.h
@@ -0,0 +1,75 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_NOTIFICATIONS_CHROME_ASH_MESSAGE_CENTER_CLIENT_H_
+#define CHROME_BROWSER_NOTIFICATIONS_CHROME_ASH_MESSAGE_CENTER_CLIENT_H_
+
+#include "ash/public/interfaces/ash_message_center_controller.mojom.h"
+#include "chrome/browser/notifications/notification_platform_bridge.h"
+#include "chrome/browser/notifications/notification_platform_bridge_chromeos.h"
+#include "chrome/browser/notifications/notifier_controller.h"
+#include "mojo/public/cpp/bindings/associated_binding.h"
+#include "ui/message_center/notifier_settings.h"
+
+// This class serves as Chrome's AshMessageCenterClient, as well as the
+// NotificationPlatformBridge for ChromeOS. It dispatches notifications to Ash
+// and handles interactions with those notifications, plus it keeps track of
+// NotifierControllers to provide notifier settings information to Ash (visible
+// in NotifierSettingsView).
+class ChromeAshMessageCenterClient : public NotificationPlatformBridge,
+                                     public ash::mojom::AshMessageCenterClient,
+                                     public NotifierController::Observer {
+ public:
+  explicit ChromeAshMessageCenterClient(
+      NotificationPlatformBridgeDelegate* delegate);
+
+  ~ChromeAshMessageCenterClient() override;
+
+  // NotificationPlatformBridge:
+  void Display(NotificationCommon::Type notification_type,
+               const std::string& notification_id,
+               const std::string& profile_id,
+               bool is_incognito,
+               const message_center::Notification& notification,
+               std::unique_ptr<NotificationCommon::Metadata> metadata) override;
+  void Close(const std::string& profile_id,
+             const std::string& notification_id) override;
+  void GetDisplayed(
+      const std::string& profile_id,
+      bool incognito,
+      const GetDisplayedNotificationsCallback& callback) const override;
+  void SetReadyCallback(NotificationBridgeReadyCallback callback) override;
+
+  // ash::mojom::AshMessageCenterClient:
+  void HandleNotificationClosed(const std::string& id, bool by_user) override;
+  void HandleNotificationClicked(const std::string& id) override;
+  void HandleNotificationButtonClicked(const std::string& id,
+                                       int button_index) override;
+  void SetNotifierEnabled(const message_center::NotifierId& notifier_id,
+                          bool enabled) override;
+  void HandleNotifierAdvancedSettingsRequested(
+      const message_center::NotifierId& notifier_id) override;
+  void GetNotifierList(GetNotifierListCallback callback) override;
+
+  // NotifierController::Observer:
+  void OnIconImageUpdated(const message_center::NotifierId& notifier_id,
+                          const gfx::ImageSkia& icon) override;
+  void OnNotifierEnabledChanged(const message_center::NotifierId& notifier_id,
+                                bool enabled) override;
+
+ private:
+  NotificationPlatformBridgeDelegate* delegate_;
+
+  // Notifier source for each notifier type.
+  std::map<message_center::NotifierId::NotifierType,
+           std::unique_ptr<NotifierController>>
+      sources_;
+
+  ash::mojom::AshMessageCenterControllerPtr controller_;
+  mojo::AssociatedBinding<ash::mojom::AshMessageCenterClient> binding_;
+
+  DISALLOW_COPY_AND_ASSIGN(ChromeAshMessageCenterClient);
+};
+
+#endif  // CHROME_BROWSER_NOTIFICATIONS_CHROME_ASH_MESSAGE_CENTER_CLIENT_H_
diff --git a/chrome/browser/notifications/message_center_settings_controller_chromeos_unittest.cc b/chrome/browser/notifications/chrome_ash_message_center_client_unittest.cc
similarity index 85%
rename from chrome/browser/notifications/message_center_settings_controller_chromeos_unittest.cc
rename to chrome/browser/notifications/chrome_ash_message_center_client_unittest.cc
index 804a88abf..202816a 100644
--- a/chrome/browser/notifications/message_center_settings_controller_chromeos_unittest.cc
+++ b/chrome/browser/notifications/chrome_ash_message_center_client_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/notifications/message_center_settings_controller_chromeos.h"
+#include "chrome/browser/notifications/chrome_ash_message_center_client.h"
 
 #include <string>
 #include <utility>
@@ -30,11 +30,13 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/message_center/notifier_settings.h"
 
-class MessageCenterSettingsControllerChromeOsTest : public testing::Test {
+namespace {
+
+class ChromeAshMessageCenterClientTest : public testing::Test {
  protected:
-  MessageCenterSettingsControllerChromeOsTest()
+  ChromeAshMessageCenterClientTest()
       : testing_profile_manager_(TestingBrowserProcess::GetGlobal()) {}
-  ~MessageCenterSettingsControllerChromeOsTest() override {}
+  ~ChromeAshMessageCenterClientTest() override {}
 
   void SetUp() override {
     ASSERT_TRUE(testing_profile_manager_.SetUp());
@@ -44,7 +46,7 @@
         new chromeos::FakeChromeUserManager));
   }
 
-  void TearDown() override { ResetController(); }
+  void TearDown() override { client_.reset(); }
 
   TestingProfile* CreateProfile(const std::string& name) {
     TestingProfile* profile =
@@ -65,34 +67,45 @@
     GetFakeUserManager()->SwitchActiveUser(AccountId::FromUserEmail(name));
   }
 
-  void CreateController() {
-    controller_.reset(new MessageCenterSettingsControllerChromeOs());
+  void CreateClient() {
+    client_.reset(new ChromeAshMessageCenterClient(nullptr));
   }
 
-  void ResetController() { controller_.reset(); }
-
-  MessageCenterSettingsControllerChromeOs* controller() {
-    return controller_.get();
+  ChromeAshMessageCenterClient* message_center_client() {
+    return client_.get();
   }
 
+ protected:
+  void RefreshNotifierList() {
+    message_center_client()->GetNotifierList(
+        base::BindOnce(&ChromeAshMessageCenterClientTest::SetNotifierUiData,
+                       base::Unretained(this)));
+  }
+
+  std::vector<ash::mojom::NotifierUiDataPtr> notifiers_;
+
  private:
   chromeos::FakeChromeUserManager* GetFakeUserManager() {
     return static_cast<chromeos::FakeChromeUserManager*>(
         user_manager::UserManager::Get());
   }
 
+  void SetNotifierUiData(std::vector<ash::mojom::NotifierUiDataPtr> notifiers) {
+    notifiers_ = std::move(notifiers);
+  }
+
   content::TestBrowserThreadBundle thread_bundle_;
   TestingProfileManager testing_profile_manager_;
-  std::unique_ptr<MessageCenterSettingsControllerChromeOs> controller_;
+  std::unique_ptr<ChromeAshMessageCenterClient> client_;
   std::unique_ptr<chromeos::ScopedUserManagerEnabler> user_manager_enabler_;
 
-  DISALLOW_COPY_AND_ASSIGN(MessageCenterSettingsControllerChromeOsTest);
+  DISALLOW_COPY_AND_ASSIGN(ChromeAshMessageCenterClientTest);
 };
 
 // TODO(mukai): write a test case to reproduce the actual guest session scenario
 // in ChromeOS.
 
-TEST_F(MessageCenterSettingsControllerChromeOsTest, NotifierSortOrder) {
+TEST_F(ChromeAshMessageCenterClientTest, NotifierSortOrder) {
   TestingProfile* profile = CreateProfile("Profile-1");
   extensions::TestExtensionSystem* test_extension_system =
       static_cast<extensions::TestExtensionSystem*>(
@@ -198,18 +211,17 @@
 
   baf_app.SetID(kBafId);
   extension_service->AddExtension(baf_app.Build().get());
-  CreateController();
+  CreateClient();
 
-  std::vector<std::unique_ptr<message_center::NotifierUiData>> notifiers;
-  controller()->GetNotifierList(&notifiers);
-  EXPECT_EQ(2u, notifiers.size());
-  EXPECT_EQ(kBarId, notifiers[0]->notifier_id.id);
-  EXPECT_EQ(kFooId, notifiers[1]->notifier_id.id);
+  RefreshNotifierList();
+  ASSERT_EQ(2u, notifiers_.size());
+  EXPECT_EQ(kBarId, notifiers_[0]->notifier_id.id);
+  EXPECT_EQ(kFooId, notifiers_[1]->notifier_id.id);
 }
 
-TEST_F(MessageCenterSettingsControllerChromeOsTest, SetWebPageNotifierEnabled) {
+TEST_F(ChromeAshMessageCenterClientTest, SetWebPageNotifierEnabled) {
   Profile* profile = CreateProfile("MyProfile");
-  CreateController();
+  CreateClient();
 
   GURL origin("https://example.com/");
 
@@ -223,7 +235,7 @@
   PermissionManager* permission_manager = PermissionManager::Get(profile);
 
   // (1) Enable the permission when the default is to ask (expected to set).
-  controller()->SetNotifierEnabled(notifier_id, true);
+  message_center_client()->SetNotifierEnabled(notifier_id, true);
   EXPECT_EQ(CONTENT_SETTING_ALLOW,
             permission_manager
                 ->GetPermissionStatus(CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
@@ -231,7 +243,7 @@
                 .content_setting);
 
   // (2) Disable the permission when the default is to ask (expected to clear).
-  controller()->SetNotifierEnabled(notifier_id, false);
+  message_center_client()->SetNotifierEnabled(notifier_id, false);
   EXPECT_EQ(CONTENT_SETTING_ASK,
             permission_manager
                 ->GetPermissionStatus(CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
@@ -244,7 +256,7 @@
                                  CONTENT_SETTING_ALLOW);
 
   // (3) Disable the permission when the default is allowed (expected to set).
-  controller()->SetNotifierEnabled(notifier_id, false);
+  message_center_client()->SetNotifierEnabled(notifier_id, false);
   EXPECT_EQ(CONTENT_SETTING_BLOCK,
             permission_manager
                 ->GetPermissionStatus(CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
@@ -252,7 +264,7 @@
                 .content_setting);
 
   // (4) Enable the permission when the default is allowed (expected to clear).
-  controller()->SetNotifierEnabled(notifier_id, true);
+  message_center_client()->SetNotifierEnabled(notifier_id, true);
   EXPECT_EQ(CONTENT_SETTING_ALLOW,
             permission_manager
                 ->GetPermissionStatus(CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
@@ -265,7 +277,7 @@
                                  CONTENT_SETTING_BLOCK);
 
   // (5) Enable the permission when the default is blocked (expected to set).
-  controller()->SetNotifierEnabled(notifier_id, true);
+  message_center_client()->SetNotifierEnabled(notifier_id, true);
   EXPECT_EQ(CONTENT_SETTING_ALLOW,
             permission_manager
                 ->GetPermissionStatus(CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
@@ -273,10 +285,12 @@
                 .content_setting);
 
   // (6) Disable the permission when the default is blocked (expected to clear).
-  controller()->SetNotifierEnabled(notifier_id, false);
+  message_center_client()->SetNotifierEnabled(notifier_id, false);
   EXPECT_EQ(CONTENT_SETTING_BLOCK,
             permission_manager
                 ->GetPermissionStatus(CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
                                       origin, origin)
                 .content_setting);
 }
+
+}  // namespace
diff --git a/chrome/browser/notifications/extension_notifier_controller.cc b/chrome/browser/notifications/extension_notifier_controller.cc
index adb4379..ba241245 100644
--- a/chrome/browser/notifications/extension_notifier_controller.cc
+++ b/chrome/browser/notifications/extension_notifier_controller.cc
@@ -22,9 +22,9 @@
 
 ExtensionNotifierController::~ExtensionNotifierController() {}
 
-std::vector<std::unique_ptr<message_center::NotifierUiData>>
+std::vector<ash::mojom::NotifierUiDataPtr>
 ExtensionNotifierController::GetNotifierList(Profile* profile) {
-  std::vector<std::unique_ptr<message_center::NotifierUiData>> ui_data;
+  std::vector<ash::mojom::NotifierUiDataPtr> ui_data;
   const extensions::ExtensionSet& extension_set =
       extensions::ExtensionRegistry::Get(profile)->enabled_extensions();
   // The extension icon size has to be 32x32 at least to load bigger icons if
@@ -62,10 +62,11 @@
             : false;
     NotifierStateTracker* const notifier_state_tracker =
         NotifierStateTrackerFactory::GetForProfile(profile);
-    ui_data.emplace_back(new message_center::NotifierUiData(
+    ui_data.push_back(ash::mojom::NotifierUiData::New(
         notifier_id, base::UTF8ToUTF16(extension->name()),
         has_advanced_settings_button,
-        notifier_state_tracker->IsNotifierEnabled(notifier_id)));
+        notifier_state_tracker->IsNotifierEnabled(notifier_id),
+        gfx::ImageSkia()));
     app_icon_loader_->FetchImage(extension->id());
   }
 
@@ -83,8 +84,7 @@
 
 void ExtensionNotifierController::OnNotifierAdvancedSettingsRequested(
     Profile* profile,
-    const message_center::NotifierId& notifier_id,
-    const std::string* notification_id) {
+    const message_center::NotifierId& notifier_id) {
   const std::string& extension_id = notifier_id.id;
 
   extensions::EventRouter* event_router = extensions::EventRouter::Get(profile);
@@ -102,5 +102,5 @@
     const gfx::ImageSkia& image) {
   observer_->OnIconImageUpdated(
       message_center::NotifierId(message_center::NotifierId::APPLICATION, id),
-      gfx::Image(image));
+      image);
 }
diff --git a/chrome/browser/notifications/extension_notifier_controller.h b/chrome/browser/notifications/extension_notifier_controller.h
index 5c30018..516e645 100644
--- a/chrome/browser/notifications/extension_notifier_controller.h
+++ b/chrome/browser/notifications/extension_notifier_controller.h
@@ -19,15 +19,14 @@
   ~ExtensionNotifierController() override;
 
   // NotifierController:
-  std::vector<std::unique_ptr<message_center::NotifierUiData>> GetNotifierList(
+  std::vector<ash::mojom::NotifierUiDataPtr> GetNotifierList(
       Profile* profile) override;
   void SetNotifierEnabled(Profile* profile,
                           const message_center::NotifierId& notifier_id,
                           bool enabled) override;
   void OnNotifierAdvancedSettingsRequested(
       Profile* profile,
-      const message_center::NotifierId& notifier_id,
-      const std::string* notification_id) override;
+      const message_center::NotifierId& notifier_id) override;
 
  private:
   // Overridden from AppIconLoaderDelegate.
diff --git a/chrome/browser/notifications/message_center_settings_controller_chromeos.cc b/chrome/browser/notifications/message_center_settings_controller_chromeos.cc
deleted file mode 100644
index fc4a207..0000000
--- a/chrome/browser/notifications/message_center_settings_controller_chromeos.cc
+++ /dev/null
@@ -1,125 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/notifications/message_center_settings_controller_chromeos.h"
-
-#include <algorithm>
-#include <string>
-#include <utility>
-
-#include "base/i18n/string_compare.h"
-#include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/chromeos/profiles/profile_helper.h"
-#include "chrome/browser/notifications/arc_application_notifier_controller_chromeos.h"
-#include "chrome/browser/notifications/extension_notifier_controller.h"
-#include "chrome/browser/notifications/web_page_notifier_controller.h"
-#include "chrome/browser/profiles/profile.h"
-#include "components/user_manager/user_manager.h"
-#include "ui/gfx/image/image.h"
-
-using message_center::NotifierUiData;
-using message_center::NotifierId;
-
-namespace {
-
-class NotifierComparator {
- public:
-  explicit NotifierComparator(icu::Collator* collator) : collator_(collator) {}
-
-  bool operator()(const std::unique_ptr<NotifierUiData>& n1,
-                  const std::unique_ptr<NotifierUiData>& n2) {
-    if (n1->notifier_id.type != n2->notifier_id.type)
-      return n1->notifier_id.type < n2->notifier_id.type;
-
-    if (collator_) {
-      return base::i18n::CompareString16WithCollator(*collator_, n1->name,
-                                                     n2->name) == UCOL_LESS;
-    }
-    return n1->name < n2->name;
-  }
-
- private:
-  icu::Collator* collator_;
-};
-
-}  // namespace
-
-MessageCenterSettingsControllerChromeOs::
-    MessageCenterSettingsControllerChromeOs() {
-  sources_.insert(std::make_pair(NotifierId::APPLICATION,
-                                 std::unique_ptr<NotifierController>(
-                                     new ExtensionNotifierController(this))));
-
-  sources_.insert(std::make_pair(NotifierId::WEB_PAGE,
-                                 std::unique_ptr<NotifierController>(
-                                     new WebPageNotifierController(this))));
-
-  sources_.insert(std::make_pair(
-      NotifierId::ARC_APPLICATION,
-      std::unique_ptr<NotifierController>(
-          new arc::ArcApplicationNotifierControllerChromeOS(this))));
-}
-
-MessageCenterSettingsControllerChromeOs::
-    ~MessageCenterSettingsControllerChromeOs() {}
-
-void MessageCenterSettingsControllerChromeOs::AddObserver(
-    message_center::NotifierSettingsObserver* observer) {
-  observers_.AddObserver(observer);
-}
-
-void MessageCenterSettingsControllerChromeOs::RemoveObserver(
-    message_center::NotifierSettingsObserver* observer) {
-  observers_.RemoveObserver(observer);
-}
-
-void MessageCenterSettingsControllerChromeOs::GetNotifierList(
-    std::vector<std::unique_ptr<NotifierUiData>>* notifiers) {
-  DCHECK(notifiers);
-  for (auto& source : sources_) {
-    auto source_notifiers = source.second->GetNotifierList(GetProfile());
-    for (auto& notifier : source_notifiers) {
-      notifiers->push_back(std::move(notifier));
-    }
-  }
-
-  UErrorCode error = U_ZERO_ERROR;
-  std::unique_ptr<icu::Collator> collator(icu::Collator::createInstance(error));
-  NotifierComparator comparator(U_SUCCESS(error) ? collator.get() : nullptr);
-
-  std::sort(notifiers->begin(), notifiers->end(), comparator);
-}
-
-void MessageCenterSettingsControllerChromeOs::SetNotifierEnabled(
-    const NotifierId& notifier_id,
-    bool enabled) {
-  sources_[notifier_id.type]->SetNotifierEnabled(GetProfile(), notifier_id,
-                                                 enabled);
-}
-
-void MessageCenterSettingsControllerChromeOs::
-    OnNotifierAdvancedSettingsRequested(const NotifierId& notifier_id,
-                                        const std::string* notification_id) {
-  return sources_[notifier_id.type]->OnNotifierAdvancedSettingsRequested(
-      GetProfile(), notifier_id, notification_id);
-}
-
-void MessageCenterSettingsControllerChromeOs::OnIconImageUpdated(
-    const NotifierId& id,
-    const gfx::Image& image) {
-  for (message_center::NotifierSettingsObserver& observer : observers_)
-    observer.UpdateIconImage(id, image);
-}
-
-Profile* MessageCenterSettingsControllerChromeOs::GetProfile() const {
-  return chromeos::ProfileHelper::Get()->GetProfileByUser(
-      user_manager::UserManager::Get()->GetActiveUser());
-}
-
-void MessageCenterSettingsControllerChromeOs::OnNotifierEnabledChanged(
-    const NotifierId& id,
-    bool enabled) {
-  for (message_center::NotifierSettingsObserver& observer : observers_)
-    observer.NotifierEnabledChanged(id, enabled);
-}
diff --git a/chrome/browser/notifications/message_center_settings_controller_chromeos.h b/chrome/browser/notifications/message_center_settings_controller_chromeos.h
deleted file mode 100644
index a139821..0000000
--- a/chrome/browser/notifications/message_center_settings_controller_chromeos.h
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_NOTIFICATIONS_MESSAGE_CENTER_SETTINGS_CONTROLLER_CHROMEOS_H_
-#define CHROME_BROWSER_NOTIFICATIONS_MESSAGE_CENTER_SETTINGS_CONTROLLER_CHROMEOS_H_
-
-#include <stddef.h>
-
-#include <map>
-#include <memory>
-#include <vector>
-
-#include "base/macros.h"
-#include "base/observer_list.h"
-#include "build/build_config.h"
-#include "chrome/browser/notifications/notifier_controller.h"
-#include "chrome/browser/profiles/profile_attributes_storage.h"
-#include "chrome/browser/ui/app_icon_loader.h"
-#include "ui/message_center/notifier_settings.h"
-
-class NotifierController;
-
-// The class to bridge between the settings UI of notifiers and the preference
-// storage.
-class MessageCenterSettingsControllerChromeOs
-    : public message_center::NotifierSettingsProvider,
-      public NotifierController::Observer {
- public:
-  MessageCenterSettingsControllerChromeOs();
-  ~MessageCenterSettingsControllerChromeOs() override;
-
-  // message_center::NotifierSettingsProvider
-  void AddObserver(message_center::NotifierSettingsObserver* observer) override;
-  void RemoveObserver(
-      message_center::NotifierSettingsObserver* observer) override;
-  void GetNotifierList(
-      std::vector<std::unique_ptr<message_center::NotifierUiData>>* notifiers)
-      override;
-  void SetNotifierEnabled(const message_center::NotifierId& notifier_id,
-                          bool enabled) override;
-  void OnNotifierAdvancedSettingsRequested(
-      const message_center::NotifierId& notifier_id,
-      const std::string* notification_id) override;
-
- private:
-  // NotifierController::Observer
-  void OnIconImageUpdated(const message_center::NotifierId&,
-                          const gfx::Image&) override;
-  void OnNotifierEnabledChanged(const message_center::NotifierId&,
-                                bool) override;
-
-  Profile* GetProfile() const;
-
-  // The views displaying notifier settings.
-  base::ObserverList<message_center::NotifierSettingsObserver> observers_;
-
-  // Notifier source for each notifier type.
-  std::map<message_center::NotifierId::NotifierType,
-           std::unique_ptr<NotifierController>>
-      sources_;
-
-  DISALLOW_COPY_AND_ASSIGN(MessageCenterSettingsControllerChromeOs);
-};
-
-#endif  // CHROME_BROWSER_NOTIFICATIONS_MESSAGE_CENTER_SETTINGS_CONTROLLER_CHROMEOS_H_
diff --git a/chrome/browser/notifications/notification_platform_bridge_chromeos.cc b/chrome/browser/notifications/notification_platform_bridge_chromeos.cc
index 131d576..3f630273 100644
--- a/chrome/browser/notifications/notification_platform_bridge_chromeos.cc
+++ b/chrome/browser/notifications/notification_platform_bridge_chromeos.cc
@@ -4,134 +4,28 @@
 
 #include "chrome/browser/notifications/notification_platform_bridge_chromeos.h"
 
-#include "ash/public/interfaces/ash_message_center_controller.mojom.h"
-#include "ash/public/interfaces/constants.mojom.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/notifications/chrome_ash_message_center_client.h"
 #include "chrome/browser/notifications/notification_display_service.h"
 #include "chrome/browser/notifications/notification_display_service_factory.h"
+#include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
-#include "content/public/common/service_manager_connection.h"
-#include "mojo/public/cpp/bindings/associated_binding.h"
-#include "services/service_manager/public/cpp/connector.h"
+#include "chrome/browser/ui/app_icon_loader.h"
+#include "ui/gfx/image/image.h"
 
 namespace {
 
 // TODO(estade): remove this function. NotificationPlatformBridge should either
 // get Profile* pointers or, longer term, all profile management should be moved
 // up a layer to NativeNotificationDisplayService.
-Profile* GetProfile(const std::string& profile_id, bool incognito) {
+Profile* GetProfileFromId(const std::string& profile_id, bool incognito) {
   ProfileManager* manager = g_browser_process->profile_manager();
   Profile* profile =
       manager->GetProfile(manager->user_data_dir().AppendASCII(profile_id));
   return incognito ? profile->GetOffTheRecordProfile() : profile;
 }
 
-class NotificationPlatformBridgeChromeOsImpl
-    : public NotificationPlatformBridge,
-      public ash::mojom::AshMessageCenterClient {
- public:
-  explicit NotificationPlatformBridgeChromeOsImpl(
-      NotificationPlatformBridgeDelegate* delegate);
-
-  ~NotificationPlatformBridgeChromeOsImpl() override;
-
-  // NotificationPlatformBridge:
-  void Display(NotificationCommon::Type notification_type,
-               const std::string& notification_id,
-               const std::string& profile_id,
-               bool is_incognito,
-               const message_center::Notification& notification,
-               std::unique_ptr<NotificationCommon::Metadata> metadata) override;
-  void Close(const std::string& profile_id,
-             const std::string& notification_id) override;
-  void GetDisplayed(
-      const std::string& profile_id,
-      bool incognito,
-      const GetDisplayedNotificationsCallback& callback) const override;
-  void SetReadyCallback(NotificationBridgeReadyCallback callback) override;
-
-  // ash::mojom::AshMessageCenterClient:
-  void HandleNotificationClosed(const std::string& id, bool by_user) override;
-  void HandleNotificationClicked(const std::string& id) override;
-  void HandleNotificationButtonClicked(const std::string& id,
-                                       int button_index) override;
-
- private:
-  NotificationPlatformBridgeDelegate* delegate_;
-
-  ash::mojom::AshMessageCenterControllerPtr controller_;
-  mojo::AssociatedBinding<ash::mojom::AshMessageCenterClient> binding_;
-
-  DISALLOW_COPY_AND_ASSIGN(NotificationPlatformBridgeChromeOsImpl);
-};
-
-NotificationPlatformBridgeChromeOsImpl::NotificationPlatformBridgeChromeOsImpl(
-    NotificationPlatformBridgeDelegate* delegate)
-    : delegate_(delegate), binding_(this) {
-  service_manager::Connector* connector =
-      content::ServiceManagerConnection::GetForProcess()->GetConnector();
-  connector->BindInterface(ash::mojom::kServiceName, &controller_);
-
-  // Register this object as the client interface implementation.
-  ash::mojom::AshMessageCenterClientAssociatedPtrInfo ptr_info;
-  binding_.Bind(mojo::MakeRequest(&ptr_info));
-  controller_->SetClient(std::move(ptr_info));
-}
-
-NotificationPlatformBridgeChromeOsImpl::
-    ~NotificationPlatformBridgeChromeOsImpl() {}
-
-// The unused variables here will not be a part of the future
-// NotificationPlatformBridge interface.
-void NotificationPlatformBridgeChromeOsImpl::Display(
-    NotificationCommon::Type /*notification_type*/,
-    const std::string& /*notification_id*/,
-    const std::string& /*profile_id*/,
-    bool /*is_incognito*/,
-    const message_center::Notification& notification,
-    std::unique_ptr<NotificationCommon::Metadata> metadata) {
-  controller_->ShowClientNotification(notification);
-}
-
-// The unused variable here will not be a part of the future
-// NotificationPlatformBridge interface.
-void NotificationPlatformBridgeChromeOsImpl::Close(
-    const std::string& /*profile_id*/,
-    const std::string& notification_id) {
-  NOTIMPLEMENTED();
-}
-
-// The unused variables here will not be a part of the future
-// NotificationPlatformBridge interface.
-void NotificationPlatformBridgeChromeOsImpl::GetDisplayed(
-    const std::string& /*profile_id*/,
-    bool /*incognito*/,
-    const GetDisplayedNotificationsCallback& callback) const {
-  NOTIMPLEMENTED();
-}
-
-void NotificationPlatformBridgeChromeOsImpl::SetReadyCallback(
-    NotificationBridgeReadyCallback callback) {
-  std::move(callback).Run(true);
-}
-
-void NotificationPlatformBridgeChromeOsImpl::HandleNotificationClosed(
-    const std::string& id,
-    bool by_user) {
-  delegate_->HandleNotificationClosed(id, by_user);
-}
-
-void NotificationPlatformBridgeChromeOsImpl::HandleNotificationClicked(
-    const std::string& id) {
-  delegate_->HandleNotificationClicked(id);
-}
-
-void NotificationPlatformBridgeChromeOsImpl::HandleNotificationButtonClicked(
-    const std::string& id,
-    int button_index) {
-  delegate_->HandleNotificationButtonClicked(id, button_index);
-}
-
 }  // namespace
 
 // static
@@ -140,7 +34,7 @@
 }
 
 NotificationPlatformBridgeChromeOs::NotificationPlatformBridgeChromeOs()
-    : impl_(std::make_unique<NotificationPlatformBridgeChromeOsImpl>(this)) {}
+    : impl_(std::make_unique<ChromeAshMessageCenterClient>(this)) {}
 
 NotificationPlatformBridgeChromeOs::~NotificationPlatformBridgeChromeOs() {}
 
@@ -152,7 +46,8 @@
     const message_center::Notification& notification,
     std::unique_ptr<NotificationCommon::Metadata> metadata) {
   auto active_notification = std::make_unique<ProfileNotification>(
-      GetProfile(profile_id, is_incognito), notification, notification_type);
+      GetProfileFromId(profile_id, is_incognito), notification,
+      notification_type);
   impl_->Display(NotificationCommon::TYPE_MAX, std::string(), std::string(),
                  false, active_notification->notification(),
                  std::move(metadata));
diff --git a/chrome/browser/notifications/notifier_controller.h b/chrome/browser/notifications/notifier_controller.h
index 922db9c..fc6aa475 100644
--- a/chrome/browser/notifications/notifier_controller.h
+++ b/chrome/browser/notifications/notifier_controller.h
@@ -8,15 +8,12 @@
 #include <memory>
 #include <vector>
 
+#include "ash/public/interfaces/ash_message_center_controller.mojom.h"
 #include "base/macros.h"
 #include "ui/message_center/notifier_settings.h"
 
 class Profile;
 
-namespace message_center {
-struct NotifierUiData;
-}
-
 // An interface to control Notifiers, grouped by NotifierType. Controllers are
 // responsible for both collating display data and toggling settings in response
 // to user inputs.
@@ -25,7 +22,7 @@
   class Observer {
    public:
     virtual void OnIconImageUpdated(const message_center::NotifierId& id,
-                                    const gfx::Image& image) = 0;
+                                    const gfx::ImageSkia& image) = 0;
     virtual void OnNotifierEnabledChanged(const message_center::NotifierId& id,
                                           bool enabled) = 0;
   };
@@ -36,8 +33,8 @@
   // Returns notifiers to display in the settings UI. Not all notifiers appear
   // in settings. If the source starts loading for icon images, it needs to call
   // Observer::OnIconImageUpdated after the icon is loaded.
-  virtual std::vector<std::unique_ptr<message_center::NotifierUiData>>
-  GetNotifierList(Profile* profile) = 0;
+  virtual std::vector<ash::mojom::NotifierUiDataPtr> GetNotifierList(
+      Profile* profile) = 0;
 
   // Set notifier enabled. |notifier_id| must have notifier type that can be
   // handled by the source. It has responsibility to invoke
@@ -49,8 +46,7 @@
   // Called when the advanced settings button has been clicked.
   virtual void OnNotifierAdvancedSettingsRequested(
       Profile* profile,
-      const message_center::NotifierId& notifier_id,
-      const std::string* notification_id) {}
+      const message_center::NotifierId& notifier_id) {}
 
  private:
   DISALLOW_COPY_AND_ASSIGN(NotifierController);
diff --git a/chrome/browser/notifications/web_page_notifier_controller.cc b/chrome/browser/notifications/web_page_notifier_controller.cc
index 5915bcbe..62fa3e04 100644
--- a/chrome/browser/notifications/web_page_notifier_controller.cc
+++ b/chrome/browser/notifications/web_page_notifier_controller.cc
@@ -20,9 +20,9 @@
 
 WebPageNotifierController::~WebPageNotifierController() {}
 
-std::vector<std::unique_ptr<message_center::NotifierUiData>>
+std::vector<ash::mojom::NotifierUiDataPtr>
 WebPageNotifierController::GetNotifierList(Profile* profile) {
-  std::vector<std::unique_ptr<message_center::NotifierUiData>> notifiers;
+  std::vector<ash::mojom::NotifierUiDataPtr> notifiers;
 
   ContentSettingsForOneType settings;
   DesktopNotificationProfileUtil::GetNotificationsSettings(profile, &settings);
@@ -46,9 +46,10 @@
     message_center::NotifierId notifier_id(url);
     NotifierStateTracker* const notifier_state_tracker =
         NotifierStateTrackerFactory::GetForProfile(profile);
-    notifiers.emplace_back(new message_center::NotifierUiData(
+    notifiers.push_back(ash::mojom::NotifierUiData::New(
         notifier_id, name, false,
-        notifier_state_tracker->IsNotifierEnabled(notifier_id)));
+        notifier_state_tracker->IsNotifierEnabled(notifier_id),
+        gfx::ImageSkia()));
     patterns_[url_pattern] = iter->primary_pattern;
     // Note that favicon service obtains the favicon from history. This means
     // that it will fail to obtain the image if there are no history data for
@@ -131,5 +132,5 @@
     const GURL& url,
     const favicon_base::FaviconImageResult& favicon_result) {
   observer_->OnIconImageUpdated(message_center::NotifierId(url),
-                                favicon_result.image);
+                                favicon_result.image.AsImageSkia());
 }
diff --git a/chrome/browser/notifications/web_page_notifier_controller.h b/chrome/browser/notifications/web_page_notifier_controller.h
index 9e964244..239a71f 100644
--- a/chrome/browser/notifications/web_page_notifier_controller.h
+++ b/chrome/browser/notifications/web_page_notifier_controller.h
@@ -21,7 +21,7 @@
   explicit WebPageNotifierController(Observer* observer);
   ~WebPageNotifierController() override;
 
-  std::vector<std::unique_ptr<message_center::NotifierUiData>> GetNotifierList(
+  std::vector<ash::mojom::NotifierUiDataPtr> GetNotifierList(
       Profile* profile) override;
 
   void SetNotifierEnabled(Profile* profile,
diff --git a/chrome/browser/resources/md_extensions/item_list.html b/chrome/browser/resources/md_extensions/item_list.html
index cfaff5c..d895304 100644
--- a/chrome/browser/resources/md_extensions/item_list.html
+++ b/chrome/browser/resources/md_extensions/item_list.html
@@ -66,7 +66,12 @@
       </div>
       <template is="dom-if" if="[[shownExtensions_.length]]">
         <div class="items-container">
-          <template is="dom-repeat" items="[[shownExtensions_]]">
+          <!-- Construct and render a few items first, to improve FMP time, then
+            construct and render the remaining items on a different frame. Value
+            of 3 was chosen by experimentation, and it is a good tradeoff
+            between FMP and time to render everything. -->
+          <template is="dom-repeat" items="[[shownExtensions_]]"
+              initial-count="3">
             <extensions-item data="[[item]]" delegate="[[delegate]]"
                 in-dev-mode="[[inDevMode]]">
             </extensions-item>
diff --git a/chrome/browser/ui/ash/lock_screen_client.cc b/chrome/browser/ui/ash/lock_screen_client.cc
index 2c68835..7985267 100644
--- a/chrome/browser/ui/ash/lock_screen_client.cc
+++ b/chrome/browser/ui/ash/lock_screen_client.cc
@@ -92,7 +92,7 @@
 }
 
 void LockScreenClient::LoadWallpaper(const AccountId& account_id) {
-  chromeos::WallpaperManager::Get()->SetUserWallpaperDelayed(account_id);
+  chromeos::WallpaperManager::Get()->SetUserWallpaper(account_id);
 }
 
 void LockScreenClient::SignOutUser() {
diff --git a/chrome/browser/ui/ash/multi_user/user_switch_animator_chromeos.cc b/chrome/browser/ui/ash/multi_user/user_switch_animator_chromeos.cc
index 8d0405a..9d6938e 100644
--- a/chrome/browser/ui/ash/multi_user/user_switch_animator_chromeos.cc
+++ b/chrome/browser/ui/ash/multi_user/user_switch_animator_chromeos.cc
@@ -174,7 +174,7 @@
     wallpaper_delegate->SetAnimationDurationOverride(
         std::max(duration, kMinimalAnimationTimeMS));
     if (screen_cover_ != NEW_USER_COVERS_SCREEN) {
-      chromeos::WallpaperManager::Get()->SetUserWallpaperNow(new_account_id_);
+      chromeos::WallpaperManager::Get()->SetUserWallpaper(new_account_id_);
       wallpaper_user_id_for_test_ =
           (NO_USER_COVERS_SCREEN == screen_cover_ ? "->" : "") +
           new_account_id_.Serialize();
@@ -183,7 +183,7 @@
     // Revert the wallpaper cross dissolve animation duration back to the
     // default.
     if (screen_cover_ == NEW_USER_COVERS_SCREEN)
-      chromeos::WallpaperManager::Get()->SetUserWallpaperNow(new_account_id_);
+      chromeos::WallpaperManager::Get()->SetUserWallpaper(new_account_id_);
 
     // Coming here the wallpaper user id is the final result. No matter how we
     // got here.
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bubble_controller_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bubble_controller_unittest.mm
index 0be6a70..462e5cbb 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_bubble_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bubble_controller_unittest.mm
@@ -33,7 +33,6 @@
 #import "ui/base/cocoa/touch_bar_forward_declarations.h"
 #import "ui/base/cocoa/touch_bar_util.h"
 #include "ui/base/material_design/material_design_controller.h"
-#include "ui/base/ui_base_features.h"
 
 using base::ASCIIToUTF16;
 using bookmarks::BookmarkBubbleObserver;
@@ -85,14 +84,6 @@
     edits_ = 0;
   }
 
-  // CocoaProfileTest:
-  void SetUp() override {
-    CocoaProfileTest::SetUp();
-    // This file only tests Cocoa UI and can be deleted when kSecondaryUiMd is
-    // default.
-    scoped_feature_list_.InitAndDisableFeature(features::kSecondaryUiMd);
-  }
-
   void TearDown() override {
     [controller_ close];
     CocoaProfileTest::TearDown();
@@ -139,11 +130,6 @@
   bool IsWindowClosing() {
     return [static_cast<InfoBubbleWindow*>([controller_ window]) isClosing];
   }
-
- private:
-  base::test::ScopedFeatureList scoped_feature_list_;
-
-  DISALLOW_COPY_AND_ASSIGN(BookmarkBubbleControllerTest);
 };
 
 // static
diff --git a/chrome/browser/ui/cocoa/extensions/extension_message_bubble_browsertest_mac.mm b/chrome/browser/ui/cocoa/extensions/extension_message_bubble_browsertest_mac.mm
index 0a2c3c3..723b469 100644
--- a/chrome/browser/ui/cocoa/extensions/extension_message_bubble_browsertest_mac.mm
+++ b/chrome/browser/ui/cocoa/extensions/extension_message_bubble_browsertest_mac.mm
@@ -3,7 +3,6 @@
 // found in the LICENSE file.
 
 #include "base/macros.h"
-#include "base/test/scoped_feature_list.h"
 #include "chrome/browser/ui/browser_window.h"
 #import "chrome/browser/ui/cocoa/browser_window_controller.h"
 #import "chrome/browser/ui/cocoa/extensions/browser_action_button.h"
@@ -14,7 +13,6 @@
 #include "chrome/browser/ui/extensions/extension_message_bubble_browsertest.h"
 #include "chrome/browser/ui/extensions/settings_api_bubble_helpers.h"
 #include "ui/base/cocoa/cocoa_base_utils.h"
-#include "ui/base/ui_base_features.h"
 #include "ui/events/test/cocoa_test_event_utils.h"
 
 namespace {
@@ -91,14 +89,9 @@
     : public ExtensionMessageBubbleBrowserTest {
  public:
   ExtensionMessageBubbleBrowserTestMac() {}
+  ~ExtensionMessageBubbleBrowserTestMac() override {}
 
   // ExtensionMessageBubbleBrowserTest:
-  void SetUp() override {
-    ExtensionMessageBubbleBrowserTest::SetUp();
-    // This file only tests Cocoa UI and can be deleted when kSecondaryUiMd is
-    // default.
-    scoped_feature_list_.InitAndDisableFeature(features::kSecondaryUiMd);
-  }
   void SetUpCommandLine(base::CommandLine* command_line) override;
 
  private:
@@ -110,8 +103,6 @@
   void ClickActionButton(Browser* browser) override;
   void ClickDismissButton(Browser* browser) override;
 
-  base::test::ScopedFeatureList scoped_feature_list_;
-
   DISALLOW_COPY_AND_ASSIGN(ExtensionMessageBubbleBrowserTestMac);
 };
 
diff --git a/chrome/browser/ui/cocoa/page_info/permission_selector_button_unittest.mm b/chrome/browser/ui/cocoa/page_info/permission_selector_button_unittest.mm
index 039000d..89d39ba 100644
--- a/chrome/browser/ui/cocoa/page_info/permission_selector_button_unittest.mm
+++ b/chrome/browser/ui/cocoa/page_info/permission_selector_button_unittest.mm
@@ -5,12 +5,10 @@
 #import "chrome/browser/ui/cocoa/page_info/permission_selector_button.h"
 
 #include "base/mac/scoped_nsobject.h"
-#include "base/test/scoped_feature_list.h"
 #import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "chrome/browser/ui/page_info/page_info_ui.h"
 #include "chrome/test/base/testing_profile.h"
 #include "content/public/test/test_browser_thread_bundle.h"
-#include "ui/base/ui_base_features.h"
 
 @interface PermissionSelectorButton (Testing)
 - (NSMenu*)permissionMenu;
@@ -41,14 +39,6 @@
     [[test_window() contentView] addSubview:view_];
   }
 
-  // CocoaTest:
-  void SetUp() override {
-    CocoaTest::SetUp();
-    // This file only tests Cocoa UI and can be deleted when kSecondaryUiMd is
-    // default.
-    scoped_feature_list_.InitAndDisableFeature(features::kSecondaryUiMd);
-  }
-
   void Callback(const PageInfoUI::PermissionInfo& permission) {
     EXPECT_TRUE(permission.type == kTestPermissionType);
     got_callback_ = true;
@@ -59,11 +49,6 @@
 
   bool got_callback_;
   base::scoped_nsobject<PermissionSelectorButton> view_;
-
- private:
-  base::test::ScopedFeatureList scoped_feature_list_;
-
-  DISALLOW_COPY_AND_ASSIGN(PermissionSelectorButtonTest);
 };
 
 TEST_VIEW(PermissionSelectorButtonTest, view_);
diff --git a/chrome/browser/ui/cocoa/passwords/passwords_bubble_browsertest.mm b/chrome/browser/ui/cocoa/passwords/passwords_bubble_browsertest.mm
index cb71280..ccb44095 100644
--- a/chrome/browser/ui/cocoa/passwords/passwords_bubble_browsertest.mm
+++ b/chrome/browser/ui/cocoa/passwords/passwords_bubble_browsertest.mm
@@ -4,7 +4,6 @@
 
 #include "base/mac/foundation_util.h"
 #include "base/mac/scoped_objc_class_swizzler.h"
-#include "base/test/scoped_feature_list.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_window.h"
 #import "chrome/browser/ui/cocoa/browser_window_controller.h"
@@ -18,7 +17,6 @@
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "content/public/test/test_utils.h"
 #include "testing/gtest_mac.h"
-#include "ui/base/ui_base_features.h"
 
 // A helper class to swizzle [NSWindow isKeyWindow] to always return true.
 @interface AlwaysKeyNSWindow : NSWindow
@@ -34,13 +32,8 @@
 // Integration tests for the Mac password bubble.
 class ManagePasswordsBubbleTest : public ManagePasswordsTest {
  public:
-  ManagePasswordsBubbleTest() {}
-
   void SetUpOnMainThread() override {
     ManagePasswordsTest::SetUpOnMainThread();
-    // This file only tests Cocoa UI and can be deleted when kSecondaryUiMd is
-    // default.
-    scoped_feature_list_.InitAndDisableFeature(features::kSecondaryUiMd);
     browser()->window()->Show();
   }
 
@@ -76,11 +69,6 @@
   }
 
   ManagePasswordsIconCocoa* GetView() { return decoration()->icon(); }
-
- private:
-  base::test::ScopedFeatureList scoped_feature_list_;
-
-  DISALLOW_COPY_AND_ASSIGN(ManagePasswordsBubbleTest);
 };
 
 IN_PROC_BROWSER_TEST_F(ManagePasswordsBubbleTest,
diff --git a/chrome/browser/ui/cocoa/passwords/passwords_bubble_cocoa_unittest.mm b/chrome/browser/ui/cocoa/passwords/passwords_bubble_cocoa_unittest.mm
index c04bb06..920a68a 100644
--- a/chrome/browser/ui/cocoa/passwords/passwords_bubble_cocoa_unittest.mm
+++ b/chrome/browser/ui/cocoa/passwords/passwords_bubble_cocoa_unittest.mm
@@ -8,7 +8,6 @@
 
 #include "base/compiler_specific.h"
 #include "base/mac/foundation_util.h"
-#include "base/test/scoped_feature_list.h"
 #include "chrome/browser/password_manager/password_store_factory.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_command_controller.h"
@@ -31,23 +30,15 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/gtest_mac.h"
 #include "testing/platform_test.h"
-#include "ui/base/ui_base_features.h"
 
 using testing::Return;
 using testing::ReturnRef;
 
 class ManagePasswordsBubbleCocoaTest : public CocoaProfileTest {
  public:
-  ManagePasswordsBubbleCocoaTest() {}
-
-  // CocoaProfileTest:
   void SetUp() override {
     CocoaProfileTest::SetUp();
 
-    // This file only tests Cocoa UI and can be deleted when kSecondaryUiMd is
-    // default.
-    scoped_feature_list_.InitAndDisableFeature(features::kSecondaryUiMd);
-
     // Create the WebContents.
     siteInstance_ = content::SiteInstance::Create(profile());
     test_web_contents_ = CreateWebContents();
@@ -118,11 +109,8 @@
   }
 
  private:
-  base::test::ScopedFeatureList scoped_feature_list_;
   scoped_refptr<content::SiteInstance> siteInstance_;
   content::WebContents* test_web_contents_;  // weak
-
-  DISALLOW_COPY_AND_ASSIGN(ManagePasswordsBubbleCocoaTest);
 };
 
 TEST_F(ManagePasswordsBubbleCocoaTest, ShowShouldCreateAndShowBubble) {
diff --git a/chrome/browser/ui/cocoa/translate/translate_bubble_controller_unittest.mm b/chrome/browser/ui/cocoa/translate/translate_bubble_controller_unittest.mm
index 08edf87..5917d46e 100644
--- a/chrome/browser/ui/cocoa/translate/translate_bubble_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/translate/translate_bubble_controller_unittest.mm
@@ -6,7 +6,6 @@
 
 #include "base/message_loop/message_loop.h"
 #include "base/test/histogram_tester.h"
-#include "base/test/scoped_feature_list.h"
 #import "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_window.h"
 #import "chrome/browser/ui/cocoa/browser_window_controller.h"
@@ -16,7 +15,6 @@
 #include "chrome/browser/ui/translate/translate_bubble_model.h"
 #include "chrome/common/url_constants.h"
 #include "content/public/browser/site_instance.h"
-#include "ui/base/ui_base_features.h"
 
 @implementation BrowserWindowController (ForTesting)
 
@@ -40,16 +38,8 @@
 
 class TranslateBubbleControllerTest : public CocoaProfileTest {
  public:
-  TranslateBubbleControllerTest() {}
-
-  // CocoaProfileTest:
   void SetUp() override {
     CocoaProfileTest::SetUp();
-
-    // This file only tests Cocoa UI and can be deleted when kSecondaryUiMd is
-    // default.
-    scoped_feature_list_.InitAndDisableFeature(features::kSecondaryUiMd);
-
     site_instance_ = content::SiteInstance::Create(profile());
 
     NSWindow* nativeWindow = browser()->window()->GetNativeWindow();
@@ -99,12 +89,9 @@
   }
 
  private:
-  base::test::ScopedFeatureList scoped_feature_list_;
   scoped_refptr<content::SiteInstance> site_instance_;
   BrowserWindowController* bwc_;
   content::WebContents* web_contents_;
-
-  DISALLOW_COPY_AND_ASSIGN(TranslateBubbleControllerTest);
 };
 
 TEST_F(TranslateBubbleControllerTest, ShowAndClose) {
diff --git a/chrome/browser/ui/webui/chromeos/login/supervised_user_creation_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/supervised_user_creation_screen_handler.cc
index a6db11fe..92543e0 100644
--- a/chrome/browser/ui/webui/chromeos/login/supervised_user_creation_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/supervised_user_creation_screen_handler.cc
@@ -300,7 +300,7 @@
     const AccountId& manager_id) {
   if (!delegate_)
     return;
-  WallpaperManager::Get()->SetUserWallpaperNow(manager_id);
+  WallpaperManager::Get()->SetUserWallpaper(manager_id);
 }
 
 void SupervisedUserCreationScreenHandler::HandleImportUserSelected(
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index aa9ef207..be94b9f 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -3969,7 +3969,7 @@
     sources += [
       "../browser/component_updater/cros_component_installer_unittest.cc",
       "../browser/media/webrtc/desktop_media_list_ash_unittest.cc",
-      "../browser/notifications/message_center_settings_controller_chromeos_unittest.cc",
+      "../browser/notifications/chrome_ash_message_center_client_unittest.cc",
       "../browser/renderer_context_menu/mock_render_view_context_menu.cc",
       "../browser/renderer_context_menu/mock_render_view_context_menu.h",
       "../browser/signin/signin_error_notifier_ash_unittest.cc",
diff --git a/chrome/test/chromedriver/test/test_expectations b/chrome/test/chromedriver/test/test_expectations
index 8342cfd2..8ebad52 100644
--- a/chrome/test/chromedriver/test/test_expectations
+++ b/chrome/test/chromedriver/test/test_expectations
@@ -255,8 +255,6 @@
         'CorrectEventFiringTest.testShouldFireMouseDownEventWhenClicking',
         # https://bugs.chromium.org/p/chromedriver/issues/detail?id=2076
         'CorrectEventFiringTest.testShouldReportTheXAndYCoordinatesWhenClicking',
-        # https://bugs.chromium.org/p/chromedriver/issues/detail?id=2077
-        'CorrectEventFiringTest.testShouldEmitClickEventWhenClickingOnATextInputElement',
     ]
 )
 
diff --git a/components/download/internal/scheduler/device_status_listener.cc b/components/download/internal/scheduler/device_status_listener.cc
index fc66651..a551daf 100644
--- a/components/download/internal/scheduler/device_status_listener.cc
+++ b/components/download/internal/scheduler/device_status_listener.cc
@@ -88,10 +88,11 @@
       ToBatteryStatus(base::PowerMonitor::Get()->IsOnBatteryPower());
   status_.network_status =
       ToNetworkStatus(network_listener_->GetConnectionType());
+  pending_network_status_ = status_.network_status;
+
   listening_ = true;
   is_valid_state_ = true;
 
-  // Notify the current status if we are online or charging.
   NotifyStatusChange();
 }
 
@@ -113,13 +114,17 @@
 
 void DeviceStatusListener::OnNetworkChanged(
     net::NetworkChangeNotifier::ConnectionType type) {
-  NetworkStatus new_network_status = ToNetworkStatus(type);
-  if (status_.network_status == new_network_status)
+  pending_network_status_ = ToNetworkStatus(type);
+
+  if (pending_network_status_ == status_.network_status) {
+    timer_.Stop();
+    is_valid_state_ = true;
     return;
+  }
 
   bool change_to_online =
       (status_.network_status == NetworkStatus::DISCONNECTED) &&
-      (new_network_status != NetworkStatus::DISCONNECTED);
+      (pending_network_status_ != NetworkStatus::DISCONNECTED);
 
   // It's unreliable to send requests immediately after the network becomes
   // online that the signal may not fully consider DHCP. Notify network change
@@ -129,10 +134,10 @@
     is_valid_state_ = false;
     timer_.Start(FROM_HERE, online_delay_,
                  base::Bind(&DeviceStatusListener::NotifyNetworkChange,
-                            base::Unretained(this), new_network_status));
+                            base::Unretained(this)));
   } else {
     timer_.Stop();
-    NotifyNetworkChange(new_network_status);
+    NotifyNetworkChange();
   }
 }
 
@@ -146,9 +151,12 @@
   observer_->OnDeviceStatusChanged(status_);
 }
 
-void DeviceStatusListener::NotifyNetworkChange(NetworkStatus network_status) {
+void DeviceStatusListener::NotifyNetworkChange() {
   is_valid_state_ = true;
-  status_.network_status = network_status;
+  if (pending_network_status_ == status_.network_status)
+    return;
+
+  status_.network_status = pending_network_status_;
   NotifyStatusChange();
 }
 
diff --git a/components/download/internal/scheduler/device_status_listener.h b/components/download/internal/scheduler/device_status_listener.h
index f8eb9746..cedcda1 100644
--- a/components/download/internal/scheduler/device_status_listener.h
+++ b/components/download/internal/scheduler/device_status_listener.h
@@ -72,7 +72,7 @@
   void NotifyStatusChange();
 
   // Called after a delay to notify the observer. See |delay_|.
-  void NotifyNetworkChange(NetworkStatus network_status);
+  void NotifyNetworkChange();
 
   // Used to start the device listener or notify network change after a delay.
   base::OneShotTimer timer_;
@@ -83,6 +83,9 @@
   // The delay used when network status becomes online.
   base::TimeDelta online_delay_;
 
+  // Pending network status used to update the current network status.
+  NetworkStatus pending_network_status_ = NetworkStatus::DISCONNECTED;
+
   DISALLOW_COPY_AND_ASSIGN(DeviceStatusListener);
 };
 
diff --git a/components/download/internal/scheduler/device_status_listener_unittest.cc b/components/download/internal/scheduler/device_status_listener_unittest.cc
index 0d67c6f..acb22d5 100644
--- a/components/download/internal/scheduler/device_status_listener_unittest.cc
+++ b/components/download/internal/scheduler/device_status_listener_unittest.cc
@@ -84,11 +84,33 @@
 
   void TearDown() override { listener_.reset(); }
 
-  // Simulates a network change call.
+  // Start the listener with certain network and battery state.
+  void StartListener(ConnectionType type, bool on_battery_power) {
+    ChangeNetworkType(type);
+    SimulateBatteryChange(on_battery_power);
+    base::RunLoop().RunUntilIdle();
+
+    EXPECT_CALL(mock_observer_, OnDeviceStatusChanged(_))
+        .Times(1)
+        .RetiresOnSaturation();
+    listener_->Start(&mock_observer_);
+    base::RunLoop().RunUntilIdle();
+  }
+
+  // Simulates a network change call, the event will be broadcasted
+  // asynchronously.
   void ChangeNetworkType(ConnectionType type) {
     test_network_notifier_.ChangeNetworkType(type);
   }
 
+  // Simulates a network change call, the event will be sent to client
+  // immediately.
+  void ChangeNetworkTypeImmediately(ConnectionType type) {
+    DCHECK(listener_.get());
+    static_cast<NetworkStatusListener::Observer*>(listener_.get())
+        ->OnNetworkChanged(type);
+  }
+
   // Simulates a battery change call.
   void SimulateBatteryChange(bool on_battery_power) {
     power_source_->GeneratePowerStateEvent(on_battery_power);
@@ -138,8 +160,7 @@
 
   // Simulate a connection change directly on the DeviceStatusListener itself to
   // allow validating the state correctly here.
-  static_cast<NetworkStatusListener::Observer*>(listener_.get())
-      ->OnNetworkChanged(ConnectionType::CONNECTION_4G);
+  ChangeNetworkTypeImmediately(ConnectionType::CONNECTION_4G);
   EXPECT_FALSE(listener_->is_valid_state());
 
   {
@@ -150,8 +171,7 @@
 
   {
     EXPECT_CALL(mock_observer_, OnDeviceStatusChanged(_)).Times(1);
-    static_cast<NetworkStatusListener::Observer*>(listener_.get())
-        ->OnNetworkChanged(ConnectionType::CONNECTION_NONE);
+    ChangeNetworkTypeImmediately(ConnectionType::CONNECTION_NONE);
     EXPECT_TRUE(listener_->is_valid_state());
     base::RunLoop().RunUntilIdle();
     EXPECT_TRUE(listener_->is_valid_state());
@@ -226,5 +246,72 @@
   listener_->Stop();
 };
 
+// Verify a sequence of offline->online->offline network state changes.
+TEST_F(DeviceStatusListenerTest, OfflineOnlineOffline) {
+  StartListener(ConnectionType::CONNECTION_NONE, true);
+
+  // Initial state is offline.
+  EXPECT_EQ(NetworkStatus::DISCONNECTED,
+            listener_->CurrentDeviceStatus().network_status);
+  EXPECT_TRUE(listener_->is_valid_state());
+  EXPECT_CALL(mock_observer_, OnDeviceStatusChanged(_)).Times(0);
+
+  // Change to online.
+  ChangeNetworkTypeImmediately(ConnectionType::CONNECTION_4G);
+  EXPECT_FALSE(listener_->is_valid_state());
+  EXPECT_EQ(NetworkStatus::DISCONNECTED,
+            listener_->CurrentDeviceStatus().network_status);
+
+  // Change to offline immediately.
+  ChangeNetworkTypeImmediately(ConnectionType::CONNECTION_NONE);
+
+  // Since the state changed back to offline before delayed online signal is
+  // reported. The state becomes valid again immediately.
+  EXPECT_TRUE(listener_->is_valid_state());
+  EXPECT_EQ(NetworkStatus::DISCONNECTED,
+            listener_->CurrentDeviceStatus().network_status);
+
+  // No more online signal since we are already offline.
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(NetworkStatus::DISCONNECTED,
+            listener_->CurrentDeviceStatus().network_status);
+}
+
+// Verify a sequence of online->offline->online network state changes.
+TEST_F(DeviceStatusListenerTest, OnlineOfflineOnline) {
+  StartListener(ConnectionType::CONNECTION_3G, true);
+
+  // Initial states is online.
+  EXPECT_EQ(NetworkStatus::METERED,
+            listener_->CurrentDeviceStatus().network_status);
+  EXPECT_TRUE(listener_->is_valid_state());
+
+  // Change to offline. Signal is broadcasted immediately.
+  EXPECT_CALL(
+      mock_observer_,
+      OnDeviceStatusChanged(NetworkStatusEqual(NetworkStatus::DISCONNECTED)))
+      .Times(1)
+      .RetiresOnSaturation();
+  ChangeNetworkTypeImmediately(ConnectionType::CONNECTION_NONE);
+  EXPECT_TRUE(listener_->is_valid_state());
+  EXPECT_EQ(NetworkStatus::DISCONNECTED,
+            listener_->CurrentDeviceStatus().network_status);
+
+  // Change to online. Signal will be broadcasted after a delay.
+  ChangeNetworkTypeImmediately(ConnectionType::CONNECTION_WIFI);
+  EXPECT_FALSE(listener_->is_valid_state());
+  EXPECT_EQ(NetworkStatus::DISCONNECTED,
+            listener_->CurrentDeviceStatus().network_status);
+
+  EXPECT_CALL(mock_observer_, OnDeviceStatusChanged(
+                                  NetworkStatusEqual(NetworkStatus::UNMETERED)))
+      .Times(1)
+      .RetiresOnSaturation();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(listener_->is_valid_state());
+  EXPECT_EQ(NetworkStatus::UNMETERED,
+            listener_->CurrentDeviceStatus().network_status);
+}
+
 }  // namespace
 }  // namespace download
diff --git a/components/exo/wayland/clients/perftests.cc b/components/exo/wayland/clients/perftests.cc
index ff5b921..85c3c0e5 100644
--- a/components/exo/wayland/clients/perftests.cc
+++ b/components/exo/wayland/clients/perftests.cc
@@ -35,10 +35,26 @@
                          "frames/s", true);
 }
 
-TEST_F(WaylandClientPerfTests, Blur) {
+class WaylandClientBlurPerfTests
+    : public WaylandClientPerfTests,
+      public ::testing::WithParamInterface<double> {
+ public:
+  WaylandClientBlurPerfTests() = default;
+  ~WaylandClientBlurPerfTests() override = default;
+
+  double max_sigma() const { return GetParam(); }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(WaylandClientBlurPerfTests);
+};
+
+INSTANTIATE_TEST_CASE_P(,
+                        WaylandClientBlurPerfTests,
+                        testing::Values(4.0, 15.0));
+
+TEST_P(WaylandClientBlurPerfTests, BlurSigma) {
   const int kWarmUpFrames = 20;
   const int kTestFrames = 600;
-  const double kMaxSigma = 4.0;
   const bool kOffscreen = true;
 
   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
@@ -51,66 +67,88 @@
   client.Run(0, 0, 0, false, kWarmUpFrames);
 
   auto start_time = base::Time::Now();
-  client.Run(0, 0, kMaxSigma, kOffscreen, kTestFrames);
+  client.Run(0, 0, max_sigma(), kOffscreen, kTestFrames);
   auto time_delta = base::Time::Now() - start_time;
   float fps = kTestFrames / time_delta.InSecondsF();
-  perf_test::PrintResult("WaylandClientPerfTests", "", "BlurSigma0x0", fps,
+  perf_test::PrintResult("WaylandClientPerfTests", "", "BlurSigma0", fps,
                          "frames/s", true);
 
   start_time = base::Time::Now();
-  client.Run(0, 5, kMaxSigma, kOffscreen, kTestFrames);
+  client.Run(5, 5, max_sigma(), kOffscreen, kTestFrames);
   time_delta = base::Time::Now() - start_time;
   fps = kTestFrames / time_delta.InSecondsF();
-  perf_test::PrintResult("WaylandClientPerfTests", "", "BlurSigma0x5", fps,
+  perf_test::PrintResult("WaylandClientPerfTests", "", "BlurSigma5", fps,
                          "frames/s", true);
 
   start_time = base::Time::Now();
-  client.Run(0, 10, kMaxSigma, kOffscreen, kTestFrames);
+  client.Run(15, 15, max_sigma(), kOffscreen, kTestFrames);
   time_delta = base::Time::Now() - start_time;
   fps = kTestFrames / time_delta.InSecondsF();
-  perf_test::PrintResult("WaylandClientPerfTests", "", "BlurSigma0x10", fps,
+  perf_test::PrintResult("WaylandClientPerfTests", "", "BlurSigma15", fps,
                          "frames/s", true);
 
   start_time = base::Time::Now();
-  client.Run(0, 25, kMaxSigma, kOffscreen, kTestFrames);
+  client.Run(30, 30, max_sigma(), kOffscreen, kTestFrames);
   time_delta = base::Time::Now() - start_time;
   fps = kTestFrames / time_delta.InSecondsF();
-  perf_test::PrintResult("WaylandClientPerfTests", "", "BlurSigma0x25", fps,
+  perf_test::PrintResult("WaylandClientPerfTests", "", "BlurSigma30", fps,
                          "frames/s", true);
 
   start_time = base::Time::Now();
-  client.Run(0, 50, kMaxSigma, kOffscreen, kTestFrames);
+  client.Run(50, 50, max_sigma(), kOffscreen, kTestFrames);
   time_delta = base::Time::Now() - start_time;
   fps = kTestFrames / time_delta.InSecondsF();
-  perf_test::PrintResult("WaylandClientPerfTests", "", "BlurSigma0x50", fps,
+  perf_test::PrintResult("WaylandClientPerfTests", "", "BlurSigma50", fps,
+                         "frames/s", true);
+}
+
+TEST_P(WaylandClientBlurPerfTests, BlurSigmaY) {
+  const int kWarmUpFrames = 20;
+  const int kTestFrames = 600;
+  const bool kOffscreen = true;
+
+  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+  exo::wayland::clients::ClientBase::InitParams params;
+  EXPECT_TRUE(params.FromCommandLine(*command_line));
+
+  exo::wayland::clients::Blur client;
+  EXPECT_TRUE(client.Init(params));
+
+  client.Run(0, 0, 0, false, kWarmUpFrames);
+
+  auto start_time = base::Time::Now();
+  client.Run(0, 0, max_sigma(), kOffscreen, kTestFrames);
+  auto time_delta = base::Time::Now() - start_time;
+  float fps = kTestFrames / time_delta.InSecondsF();
+  perf_test::PrintResult("WaylandClientPerfTests", "", "BlurSigmaY0", fps,
                          "frames/s", true);
 
   start_time = base::Time::Now();
-  client.Run(5, 5, kMaxSigma, kOffscreen, kTestFrames);
+  client.Run(0, 5, max_sigma(), kOffscreen, kTestFrames);
   time_delta = base::Time::Now() - start_time;
   fps = kTestFrames / time_delta.InSecondsF();
-  perf_test::PrintResult("WaylandClientPerfTests", "", "BlurSigma5x5", fps,
+  perf_test::PrintResult("WaylandClientPerfTests", "", "BlurSigmaY5", fps,
                          "frames/s", true);
 
   start_time = base::Time::Now();
-  client.Run(15, 15, kMaxSigma, kOffscreen, kTestFrames);
+  client.Run(0, 10, max_sigma(), kOffscreen, kTestFrames);
   time_delta = base::Time::Now() - start_time;
   fps = kTestFrames / time_delta.InSecondsF();
-  perf_test::PrintResult("WaylandClientPerfTests", "", "BlurSigma15x15", fps,
+  perf_test::PrintResult("WaylandClientPerfTests", "", "BlurSigmaY10", fps,
                          "frames/s", true);
 
   start_time = base::Time::Now();
-  client.Run(30, 30, kMaxSigma, kOffscreen, kTestFrames);
+  client.Run(0, 25, max_sigma(), kOffscreen, kTestFrames);
   time_delta = base::Time::Now() - start_time;
   fps = kTestFrames / time_delta.InSecondsF();
-  perf_test::PrintResult("WaylandClientPerfTests", "", "BlurSigma30x30", fps,
+  perf_test::PrintResult("WaylandClientPerfTests", "", "BlurSigmaY25", fps,
                          "frames/s", true);
 
   start_time = base::Time::Now();
-  client.Run(50, 50, kMaxSigma, kOffscreen, kTestFrames);
+  client.Run(0, 50, max_sigma(), kOffscreen, kTestFrames);
   time_delta = base::Time::Now() - start_time;
   fps = kTestFrames / time_delta.InSecondsF();
-  perf_test::PrintResult("WaylandClientPerfTests", "", "BlurSigma50x50", fps,
+  perf_test::PrintResult("WaylandClientPerfTests", "", "BlurSigmaY50", fps,
                          "frames/s", true);
 }
 
diff --git a/content/browser/compositor/gpu_process_transport_factory.cc b/content/browser/compositor/gpu_process_transport_factory.cc
index dff2818a..66f70d4 100644
--- a/content/browser/compositor/gpu_process_transport_factory.cc
+++ b/content/browser/compositor/gpu_process_transport_factory.cc
@@ -563,8 +563,11 @@
       } else if (capabilities.surfaceless) {
 #if defined(OS_MACOSX)
         const auto& gpu_feature_info = context_provider->GetGpuFeatureInfo();
-        bool disable_overlay_ca_layers = gpu_feature_info.IsWorkaroundEnabled(
-            gpu::DISABLE_OVERLAY_CA_LAYERS);
+        bool disable_overlay_ca_layers =
+            gpu_feature_info.IsWorkaroundEnabled(
+                gpu::DISABLE_OVERLAY_CA_LAYERS) ||
+            gpu_feature_info.IsWorkaroundEnabled(
+                gpu::DISABLE_GPU_MEMORY_BUFFERS_AS_RENDER_TARGETS);
         display_output_surface = std::make_unique<GpuOutputSurfaceMac>(
             compositor->widget(), context_provider, data->surface_handle,
             vsync_callback,
diff --git a/content/browser/manifest/manifest_browsertest.cc b/content/browser/manifest/manifest_browsertest.cc
index f5e684e4..d6864db5 100644
--- a/content/browser/manifest/manifest_browsertest.cc
+++ b/content/browser/manifest/manifest_browsertest.cc
@@ -10,7 +10,9 @@
 #include "base/path_service.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
+#include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents.h"
+#include "content/public/common/associated_interface_provider.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/manifest.h"
 #include "content/public/test/browser_test_utils.h"
@@ -21,7 +23,7 @@
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "net/test/embedded_test_server/http_request.h"
 #include "net/test/embedded_test_server/http_response.h"
-
+#include "third_party/WebKit/public/platform/modules/manifest/manifest_manager.mojom.h"
 
 namespace content {
 
@@ -93,7 +95,17 @@
     return manifest_url_;
   }
 
-  unsigned int console_error_count() const {
+  int GetConsoleErrorCount() const {
+    // The IPCs reporting console errors are not FIFO with the manifest IPCs.
+    // Waiting for a round-trip channel-associated message will wait until any
+    // already enqueued channel-associated IPCs arrive at the browser process.
+    blink::mojom::ManifestManagerAssociatedPtr ptr;
+    shell()
+        ->web_contents()
+        ->GetMainFrame()
+        ->GetRemoteAssociatedInterfaces()
+        ->GetInterface(&ptr);
+    ptr.FlushForTesting();
     return console_error_count_;
   }
 
@@ -170,7 +182,7 @@
   GetManifestAndWait();
   EXPECT_TRUE(manifest().IsEmpty());
   EXPECT_TRUE(manifest_url().is_empty());
-  EXPECT_EQ(0u, console_error_count());
+  EXPECT_EQ(0, GetConsoleErrorCount());
   EXPECT_TRUE(reported_manifest_urls().empty());
   ASSERT_EQ(1u, manifests_reported_when_favicon_url_updated().size());
   EXPECT_EQ(0u, manifests_reported_when_favicon_url_updated()[0]);
@@ -186,7 +198,7 @@
   GetManifestAndWait();
   EXPECT_TRUE(manifest().IsEmpty());
   EXPECT_FALSE(manifest_url().is_empty());
-  EXPECT_EQ(0u, console_error_count());
+  EXPECT_EQ(0, GetConsoleErrorCount());
   ASSERT_EQ(1u, reported_manifest_urls().size());
   EXPECT_EQ(manifest_url(), reported_manifest_urls()[0]);
   EXPECT_EQ(0u, manifests_reported_when_favicon_url_updated().size());
@@ -203,7 +215,7 @@
   GetManifestAndWait();
   EXPECT_TRUE(manifest().IsEmpty());
   EXPECT_FALSE(manifest_url().is_empty());
-  EXPECT_EQ(0u, console_error_count());
+  EXPECT_EQ(0, GetConsoleErrorCount());
   ASSERT_EQ(1u, reported_manifest_urls().size());
   EXPECT_EQ(manifest_url(), reported_manifest_urls()[0]);
   ASSERT_EQ(1u, manifests_reported_when_favicon_url_updated().size());
@@ -221,7 +233,7 @@
   GetManifestAndWait();
   EXPECT_TRUE(manifest().IsEmpty());
   EXPECT_FALSE(manifest_url().is_empty());
-  EXPECT_EQ(1u, console_error_count());
+  EXPECT_EQ(1, GetConsoleErrorCount());
   ASSERT_EQ(1u, reported_manifest_urls().size());
   EXPECT_EQ(manifest_url(), reported_manifest_urls()[0]);
   ASSERT_EQ(1u, manifests_reported_when_favicon_url_updated().size());
@@ -241,7 +253,7 @@
   EXPECT_FALSE(manifest().IsEmpty());
   EXPECT_FALSE(manifest_url().is_empty());
 
-  EXPECT_EQ(0u, console_error_count());
+  EXPECT_EQ(0, GetConsoleErrorCount());
   ASSERT_EQ(1u, reported_manifest_urls().size());
   EXPECT_EQ(manifest_url(), reported_manifest_urls()[0]);
   ASSERT_EQ(1u, manifests_reported_when_favicon_url_updated().size());
@@ -301,7 +313,7 @@
     EXPECT_EQ(0u, manifests_reported_when_favicon_url_updated()[0]);
   }
 
-  EXPECT_EQ(0u, console_error_count());
+  EXPECT_EQ(0, GetConsoleErrorCount());
 }
 
 // If a page's manifest lives in a different origin, it should follow the CORS
@@ -326,7 +338,7 @@
   EXPECT_TRUE(manifest().IsEmpty());
   EXPECT_FALSE(manifest_url().is_empty());
   // 1 error for CORS violation
-  EXPECT_EQ(1u, console_error_count());
+  EXPECT_EQ(1, GetConsoleErrorCount());
   expected_manifest_urls.push_back(manifest_url());
   EXPECT_EQ(expected_manifest_urls, reported_manifest_urls());
 
@@ -365,7 +377,7 @@
   GetManifestAndWait();
   EXPECT_FALSE(manifest().IsEmpty());
   EXPECT_FALSE(manifest_url().is_empty());
-  EXPECT_EQ(0u, console_error_count());
+  EXPECT_EQ(0, GetConsoleErrorCount());
   ASSERT_EQ(1u, reported_manifest_urls().size());
   EXPECT_EQ(manifest_url(), reported_manifest_urls()[0]);
   ASSERT_EQ(1u, manifests_reported_when_favicon_url_updated().size());
@@ -394,7 +406,7 @@
   EXPECT_TRUE(manifest().IsEmpty());
   EXPECT_FALSE(manifest_url().is_empty());
   // 1 error for mixed-content check violation
-  EXPECT_EQ(1u, console_error_count());
+  EXPECT_EQ(1, GetConsoleErrorCount());
   ASSERT_EQ(1u, reported_manifest_urls().size());
   EXPECT_EQ(manifest_url(), reported_manifest_urls()[0]);
   ASSERT_EQ(1u, manifests_reported_when_favicon_url_updated().size());
@@ -412,7 +424,7 @@
   GetManifestAndWait();
   EXPECT_TRUE(manifest().IsEmpty());
   EXPECT_FALSE(manifest_url().is_empty());
-  EXPECT_EQ(6u, console_error_count());
+  EXPECT_EQ(6, GetConsoleErrorCount());
   ASSERT_EQ(1u, reported_manifest_urls().size());
   EXPECT_EQ(manifest_url(), reported_manifest_urls()[0]);
   ASSERT_EQ(1u, manifests_reported_when_favicon_url_updated().size());
@@ -432,7 +444,7 @@
     GetManifestAndWait();
     EXPECT_FALSE(manifest().IsEmpty());
     EXPECT_FALSE(manifest_url().is_empty());
-    EXPECT_EQ(0u, console_error_count());
+    EXPECT_EQ(0, GetConsoleErrorCount());
     expected_manifest_urls.push_back(manifest_url());
     EXPECT_EQ(expected_manifest_urls, reported_manifest_urls());
     ASSERT_EQ(1u, manifests_reported_when_favicon_url_updated().size());
@@ -447,7 +459,7 @@
 
     GetManifestAndWait();
     EXPECT_TRUE(manifest().IsEmpty());
-    EXPECT_EQ(0u, console_error_count());
+    EXPECT_EQ(0, GetConsoleErrorCount());
     EXPECT_TRUE(manifest_url().is_empty());
     EXPECT_EQ(expected_manifest_urls, reported_manifest_urls());
     ASSERT_EQ(2u, manifests_reported_when_favicon_url_updated().size());
@@ -463,7 +475,7 @@
     GetManifestAndWait();
     EXPECT_FALSE(manifest().IsEmpty());
     EXPECT_FALSE(manifest_url().is_empty());
-    EXPECT_EQ(0u, console_error_count());
+    EXPECT_EQ(0, GetConsoleErrorCount());
     expected_manifest_urls.push_back(manifest_url());
     EXPECT_EQ(expected_manifest_urls, reported_manifest_urls());
     ASSERT_EQ(3u, manifests_reported_when_favicon_url_updated().size());
@@ -489,7 +501,7 @@
   GetManifestAndWait();
   EXPECT_FALSE(manifest().IsEmpty());
   EXPECT_FALSE(manifest_url().is_empty());
-  EXPECT_EQ(0u, console_error_count());
+  EXPECT_EQ(0, GetConsoleErrorCount());
   ASSERT_EQ(1u, reported_manifest_urls().size());
   EXPECT_EQ(manifest_url(), reported_manifest_urls()[0]);
   ASSERT_EQ(2u, manifests_reported_when_favicon_url_updated().size());
@@ -516,7 +528,7 @@
   GetManifestAndWait();
   EXPECT_FALSE(manifest().IsEmpty());
   EXPECT_FALSE(manifest_url().is_empty());
-  EXPECT_EQ(0u, console_error_count());
+  EXPECT_EQ(0, GetConsoleErrorCount());
   ASSERT_EQ(1u, reported_manifest_urls().size());
   EXPECT_EQ(manifest_url(), reported_manifest_urls()[0]);
   ASSERT_EQ(2u, manifests_reported_when_favicon_url_updated().size());
@@ -576,7 +588,7 @@
   GetManifestAndWait();
   EXPECT_FALSE(manifest().IsEmpty());
   EXPECT_FALSE(manifest_url().is_empty());
-  EXPECT_EQ(0u, console_error_count());
+  EXPECT_EQ(0, GetConsoleErrorCount());
   ASSERT_EQ(1u, reported_manifest_urls().size());
   EXPECT_EQ(manifest_url(), reported_manifest_urls()[0]);
   ASSERT_EQ(1u, manifests_reported_when_favicon_url_updated().size());
@@ -636,7 +648,7 @@
   GetManifestAndWait();
   EXPECT_FALSE(manifest().IsEmpty());
   EXPECT_FALSE(manifest_url().is_empty());
-  EXPECT_EQ(0u, console_error_count());
+  EXPECT_EQ(0, GetConsoleErrorCount());
   ASSERT_EQ(1u, reported_manifest_urls().size());
   EXPECT_EQ(manifest_url(), reported_manifest_urls()[0]);
   ASSERT_EQ(1u, manifests_reported_when_favicon_url_updated().size());
diff --git a/content/browser/manifest/manifest_manager_host.cc b/content/browser/manifest/manifest_manager_host.cc
index 7fa23f0..3bbb810a 100644
--- a/content/browser/manifest/manifest_manager_host.cc
+++ b/content/browser/manifest/manifest_manager_host.cc
@@ -10,8 +10,8 @@
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents.h"
-#include "content/public/common/associated_interface_provider.h"
 #include "content/public/common/manifest.h"
+#include "services/service_manager/public/cpp/interface_provider.h"
 
 namespace content {
 
@@ -44,7 +44,7 @@
 
   if (!manifest_manager_) {
     manifest_manager_frame_ = web_contents()->GetMainFrame();
-    manifest_manager_frame_->GetRemoteAssociatedInterfaces()->GetInterface(
+    manifest_manager_frame_->GetRemoteInterfaces()->GetInterface(
         &manifest_manager_);
     manifest_manager_.set_connection_error_handler(base::BindOnce(
         &ManifestManagerHost::OnConnectionError, base::Unretained(this)));
diff --git a/content/browser/manifest/manifest_manager_host.h b/content/browser/manifest/manifest_manager_host.h
index b94cbdb5..f753e93 100644
--- a/content/browser/manifest/manifest_manager_host.h
+++ b/content/browser/manifest/manifest_manager_host.h
@@ -54,7 +54,7 @@
   void ManifestUrlChanged(const base::Optional<GURL>& manifest_url) override;
 
   RenderFrameHost* manifest_manager_frame_ = nullptr;
-  blink::mojom::ManifestManagerAssociatedPtr manifest_manager_;
+  blink::mojom::ManifestManagerPtr manifest_manager_;
   CallbackMap callbacks_;
 
   WebContentsFrameBindingSet<mojom::ManifestUrlChangeObserver>
diff --git a/content/renderer/manifest/manifest_manager.cc b/content/renderer/manifest/manifest_manager.cc
index 55d0aa82..93b9f09 100644
--- a/content/renderer/manifest/manifest_manager.cc
+++ b/content/renderer/manifest/manifest_manager.cc
@@ -198,7 +198,7 @@
 }
 
 void ManifestManager::BindToRequest(
-    blink::mojom::ManifestManagerAssociatedRequest request) {
+    blink::mojom::ManifestManagerRequest request) {
   bindings_.AddBinding(this, std::move(request));
 }
 
diff --git a/content/renderer/manifest/manifest_manager.h b/content/renderer/manifest/manifest_manager.h
index 5b7d3f2e..41101ad4 100644
--- a/content/renderer/manifest/manifest_manager.h
+++ b/content/renderer/manifest/manifest_manager.h
@@ -16,7 +16,7 @@
 #include "content/public/common/manifest.h"
 #include "content/public/renderer/render_frame_observer.h"
 #include "content/renderer/manifest/manifest_debug_info.h"
-#include "mojo/public/cpp/bindings/associated_binding_set.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
 #include "third_party/WebKit/public/platform/modules/manifest/manifest_manager.mojom.h"
 
 class GURL;
@@ -53,7 +53,7 @@
   void DidCommitProvisionalLoad(bool is_new_navigation,
                                 bool is_same_document_navigation) override;
 
-  void BindToRequest(blink::mojom::ManifestManagerAssociatedRequest request);
+  void BindToRequest(blink::mojom::ManifestManagerRequest request);
 
  private:
   enum ResolveState {
@@ -106,7 +106,7 @@
 
   std::vector<GetManifestCallback> pending_callbacks_;
 
-  mojo::AssociatedBindingSet<blink::mojom::ManifestManager> bindings_;
+  mojo::BindingSet<blink::mojom::ManifestManager> bindings_;
 
   base::WeakPtrFactory<ManifestManager> weak_factory_;
 
diff --git a/content/renderer/pepper/ppb_graphics_3d_impl.cc b/content/renderer/pepper/ppb_graphics_3d_impl.cc
index 39ad952ff..eb41e82c 100644
--- a/content/renderer/pepper/ppb_graphics_3d_impl.cc
+++ b/content/renderer/pepper/ppb_graphics_3d_impl.cc
@@ -24,6 +24,7 @@
 #include "content/renderer/render_view_impl.h"
 #include "gpu/GLES2/gl2extchromium.h"
 #include "gpu/command_buffer/common/gles2_cmd_utils.h"
+#include "gpu/config/gpu_driver_bug_workaround_type.h"
 #include "gpu/ipc/client/command_buffer_proxy_impl.h"
 #include "gpu/ipc/client/gpu_channel_host.h"
 #include "ppapi/c/ppp_graphics_3d.h"
@@ -49,10 +50,11 @@
       bound_to_instance_(false),
       commit_pending_(false),
       has_alpha_(false),
-      use_image_chromium_(
+      image_chromium_enabled_(
           !base::CommandLine::ForCurrentProcess()->HasSwitch(
               switches::kDisablePepper3DImageChromium) &&
           base::FeatureList::IsEnabled(features::kPepper3DImageChromium)),
+      use_image_chromium_(false),
       weak_ptr_factory_(this) {}
 
 PPB_Graphics3D_Impl::~PPB_Graphics3D_Impl() {
@@ -253,6 +255,11 @@
   has_alpha_ = requested_attribs.alpha_size > 0;
 
   gpu::gles2::ContextCreationAttribHelper attrib_helper = requested_attribs;
+  // At this point we have a GPU channel so we can see whether
+  // features have been blacklisted.
+  use_image_chromium_ = image_chromium_enabled_ &&
+                        !channel->gpu_feature_info().IsWorkaroundEnabled(
+                            gpu::DISABLE_GPU_MEMORY_BUFFERS_AS_RENDER_TARGETS);
   attrib_helper.should_use_native_gmb_for_backbuffer = use_image_chromium_;
   attrib_helper.context_type = gpu::gles2::CONTEXT_TYPE_OPENGLES2;
 
diff --git a/content/renderer/pepper/ppb_graphics_3d_impl.h b/content/renderer/pepper/ppb_graphics_3d_impl.h
index 8d6a17a..54374af 100644
--- a/content/renderer/pepper/ppb_graphics_3d_impl.h
+++ b/content/renderer/pepper/ppb_graphics_3d_impl.h
@@ -118,7 +118,8 @@
 #endif
 
   bool has_alpha_;
-  const bool use_image_chromium_;
+  const bool image_chromium_enabled_;
+  bool use_image_chromium_;
   std::unique_ptr<gpu::CommandBufferProxyImpl> command_buffer_;
 
   base::WeakPtrFactory<PPB_Graphics3D_Impl> weak_ptr_factory_;
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 16e6396b..ce13f5a 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -6944,8 +6944,8 @@
         &RenderFrameImpl::OnHostZoomClientRequest, weak_factory_.GetWeakPtr()));
 
     // Web manifests are only requested for main frames.
-    GetAssociatedInterfaceRegistry()->AddInterface(base::Bind(
-        &ManifestManager::BindToRequest, base::Unretained(manifest_manager_)));
+    registry_.AddInterface(base::Bind(&ManifestManager::BindToRequest,
+                                      base::Unretained(manifest_manager_)));
   }
 }
 
diff --git a/gpu/command_buffer/service/feature_info.cc b/gpu/command_buffer/service/feature_info.cc
index babc44b0..773ba87b 100644
--- a/gpu/command_buffer/service/feature_info.cc
+++ b/gpu/command_buffer/service/feature_info.cc
@@ -431,10 +431,13 @@
   // so the extension string is always exposed.
   AddExtensionString("GL_OES_vertex_array_object");
 
-// Texture storage image is only usable with native gpu memory buffer support.
+// Texture storage image is only usable with native gpu memory buffer support,
+// and should be disabled if we aren't supposed to use GMBs as render targets.
 #if defined(OS_MACOSX) || (defined(OS_LINUX) && defined(USE_OZONE))
-  feature_flags_.chromium_texture_storage_image = true;
-  AddExtensionString("GL_CHROMIUM_texture_storage_image");
+  if (!workarounds_.disable_gpu_memory_buffers_as_render_targets) {
+    feature_flags_.chromium_texture_storage_image = true;
+    AddExtensionString("GL_CHROMIUM_texture_storage_image");
+  }
 #endif
 
   if (!disallowed_features_.gpu_memory_manager)
diff --git a/gpu/config/gpu_driver_bug_list.json b/gpu/config/gpu_driver_bug_list.json
index 3d9ef51d..053fcc6 100644
--- a/gpu/config/gpu_driver_bug_list.json
+++ b/gpu/config/gpu_driver_bug_list.json
@@ -2653,6 +2653,23 @@
       "features": [
         "disable_program_caching_for_transform_feedback"
       ]
+    },
+    {
+      "id": 244,
+      "description": "Rendering to IOSurfaces via OpenGL is broken on NVIDIA GPUs on High Sierra",
+      "cr_bugs": [773705, 778770],
+      "os": {
+        "type": "macosx",
+        "version": {
+          "op": ">=",
+          "value": "10.13"
+        }
+      },
+      "vendor_id": "0x10de",
+      "multi_gpu_category": "any",
+      "features": [
+        "disable_gpu_memory_buffers_as_render_targets"
+      ]
     }
   ]
 }
diff --git a/gpu/config/gpu_driver_bug_workaround_type.h b/gpu/config/gpu_driver_bug_workaround_type.h
index ce8b6ef..d64c9bc 100644
--- a/gpu/config/gpu_driver_bug_workaround_type.h
+++ b/gpu/config/gpu_driver_bug_workaround_type.h
@@ -71,6 +71,8 @@
          disable_framebuffer_cmaa)                           \
   GPU_OP(DISABLE_GL_RGB_FORMAT,                              \
          disable_gl_rgb_format)                              \
+  GPU_OP(DISABLE_GPU_MEMORY_BUFFERS_AS_RENDER_TARGETS,       \
+         disable_gpu_memory_buffers_as_render_targets)       \
   GPU_OP(DISABLE_LARGER_THAN_SCREEN_OVERLAYS,                \
          disable_larger_than_screen_overlays)                \
   GPU_OP(DISABLE_NON_EMPTY_POST_SUB_BUFFERS_FOR_ONSCREEN_SURFACES, \
diff --git a/gpu/config/software_rendering_list.json b/gpu/config/software_rendering_list.json
index 5381783..52a6db44 100644
--- a/gpu/config/software_rendering_list.json
+++ b/gpu/config/software_rendering_list.json
@@ -1554,24 +1554,6 @@
       "features": [
         "accelerated_webgl2"
       ]
-    },
-    {
-      "id": 150,
-      "description": "Macs with NVidia GPUs experience rendering issues on High Sierra",
-      "cr_bugs": [773705],
-      "os": {
-        "type": "macosx",
-        "version": {
-          "op": ">=",
-          "value": "10.13"
-        }
-      },
-      "vendor_id": "0x10de",
-      "multi_gpu_category": "any",
-      "features": [
-        "accelerated_2d_canvas",
-        "gpu_rasterization"
-      ]
     }
   ]
 }
diff --git a/ios/chrome/browser/net/cookies_egtest.mm b/ios/chrome/browser/net/cookies_egtest.mm
index 035728e..7261971 100644
--- a/ios/chrome/browser/net/cookies_egtest.mm
+++ b/ios/chrome/browser/net/cookies_egtest.mm
@@ -134,7 +134,7 @@
 
   // Finally, closes all incognito tabs while still in normal tab.
   // Checks that incognito cookie is gone.
-  chrome_test_util::CloseAllIncognitoTabs();
+  GREYAssert(chrome_test_util::CloseAllIncognitoTabs(), @"Tabs did not close");
   chrome_test_util::OpenNewTab();
   [ChromeEarlGrey
       loadURL:web::test::HttpServer::MakeUrl(kTestUrlIncognitoBrowsing)];
@@ -162,7 +162,7 @@
                   @"Only one cookie should be found in incognito mode.");
 
   // Closes all incognito tabs and switch back to a normal tab.
-  chrome_test_util::CloseAllIncognitoTabs();
+  GREYAssert(chrome_test_util::CloseAllIncognitoTabs(), @"Tabs did not close");
   chrome_test_util::OpenNewTab();
   [ChromeEarlGrey
       loadURL:web::test::HttpServer::MakeUrl(kTestUrlNormalBrowsing)];
@@ -207,7 +207,7 @@
 
   // Closes all incognito tabs and then switching back to a normal tab. Verifies
   // that the cookie set earlier is still there.
-  chrome_test_util::CloseAllIncognitoTabs();
+  GREYAssert(chrome_test_util::CloseAllIncognitoTabs(), @"Tabs did not close");
   chrome_test_util::OpenNewTab();
   [ChromeEarlGrey
       loadURL:web::test::HttpServer::MakeUrl(kTestUrlNormalBrowsing)];
diff --git a/ios/chrome/browser/ui/bookmarks/bookmarks_new_generation_egtest.mm b/ios/chrome/browser/ui/bookmarks/bookmarks_new_generation_egtest.mm
index 51328ef..1b8fc9ef 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmarks_new_generation_egtest.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmarks_new_generation_egtest.mm
@@ -821,7 +821,7 @@
                  @"Incognito tab count should be 1");
 
   // Close the incognito tab to go back to normal mode.
-  chrome_test_util::CloseAllIncognitoTabs();
+  GREYAssert(chrome_test_util::CloseAllIncognitoTabs(), @"Tabs did not close");
 
   // The following verifies the selected bookmarks are open in the same order as
   // in folder.
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_egtest.mm b/ios/chrome/browser/ui/ntp/new_tab_page_egtest.mm
index 9d02046..ca135dc1 100644
--- a/ios/chrome/browser/ui/ntp/new_tab_page_egtest.mm
+++ b/ios/chrome/browser/ui/ntp/new_tab_page_egtest.mm
@@ -132,7 +132,7 @@
   SelectNewTabPagePanel(ntp_home::INCOGNITO_PANEL);
   WaitForHistoryToDisappear();
   chrome_test_util::VerifyAccessibilityForCurrentScreen();
-  chrome_test_util::CloseAllIncognitoTabs();
+  GREYAssert(chrome_test_util::CloseAllIncognitoTabs(), @"Tabs did not close");
 }
 
 // Tests rotating the device when the NTP's omnibox is pinned to the top of the
diff --git a/ios/chrome/browser/ui/settings/settings_egtest.mm b/ios/chrome/browser/ui/settings/settings_egtest.mm
index 4856dd5..3083037 100644
--- a/ios/chrome/browser/ui/settings/settings_egtest.mm
+++ b/ios/chrome/browser/ui/settings/settings_egtest.mm
@@ -616,7 +616,7 @@
 
   [[EarlGrey selectElementWithMatcher:NavigationBarDoneButton()]
       performAction:grey_tap()];
-  chrome_test_util::CloseAllIncognitoTabs();
+  GREYAssert(chrome_test_util::CloseAllIncognitoTabs(), @"Tabs did not close");
 }
 
 // Verifies the UI elements are accessible on the Settings page.
diff --git a/ios/chrome/test/app/tab_test_util.h b/ios/chrome/test/app/tab_test_util.h
index 31359851..6b9e658 100644
--- a/ios/chrome/test/app/tab_test_util.h
+++ b/ios/chrome/test/app/tab_test_util.h
@@ -7,6 +7,8 @@
 
 #import <Foundation/Foundation.h>
 
+#include "base/compiler_specific.h"
+
 @class Tab;
 
 namespace chrome_test_util {
@@ -65,7 +67,7 @@
 void EvictOtherTabModelTabs();
 
 // Closes all incognito tabs. Return YES on success.
-BOOL CloseAllIncognitoTabs();
+BOOL CloseAllIncognitoTabs() WARN_UNUSED_RESULT;
 
 // Returns the number of main tabs currently evicted.
 NSUInteger GetEvictedMainTabCount();
diff --git a/media/base/audio_bus_perftest.cc b/media/base/audio_bus_perftest.cc
index db8e47df..2140a228 100644
--- a/media/base/audio_bus_perftest.cc
+++ b/media/base/audio_bus_perftest.cc
@@ -7,6 +7,7 @@
 
 #include "base/time/time.h"
 #include "media/base/audio_bus.h"
+#include "media/base/audio_sample_types.h"
 #include "media/base/fake_audio_render_callback.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/perf/perf_test.h"
@@ -16,31 +17,27 @@
 static const int kBenchmarkIterations = 20;
 static const int kSampleRate = 48000;
 
-template <typename T>
+template <typename T, class SampleTraits>
 void RunInterleaveBench(AudioBus* bus, const std::string& trace_name) {
   const int frame_size = bus->frames() * bus->channels();
   std::unique_ptr<T[]> interleaved(new T[frame_size]);
-  const int byte_size = sizeof(T);
 
   base::TimeTicks start = base::TimeTicks::Now();
-  for (int i = 0; i < kBenchmarkIterations; ++i) {
-    bus->ToInterleaved(bus->frames(), byte_size, interleaved.get());
-  }
+  for (int i = 0; i < kBenchmarkIterations; ++i)
+    bus->ToInterleaved<SampleTraits>(bus->frames(), interleaved.get());
   double total_time_milliseconds =
       (base::TimeTicks::Now() - start).InMillisecondsF();
-  perf_test::PrintResult(
-      "audio_bus_to_interleaved", "", trace_name,
-      total_time_milliseconds / kBenchmarkIterations, "ms", true);
+  perf_test::PrintResult("audio_bus_to_interleaved", "", trace_name,
+                         total_time_milliseconds / kBenchmarkIterations, "ms",
+                         true);
 
   start = base::TimeTicks::Now();
-  for (int i = 0; i < kBenchmarkIterations; ++i) {
-    bus->FromInterleaved(interleaved.get(), bus->frames(), byte_size);
-  }
-  total_time_milliseconds =
-      (base::TimeTicks::Now() - start).InMillisecondsF();
-  perf_test::PrintResult(
-      "audio_bus_from_interleaved", "", trace_name,
-      total_time_milliseconds / kBenchmarkIterations, "ms", true);
+  for (int i = 0; i < kBenchmarkIterations; ++i)
+    bus->FromInterleaved<SampleTraits>(interleaved.get(), bus->frames());
+  total_time_milliseconds = (base::TimeTicks::Now() - start).InMillisecondsF();
+  perf_test::PrintResult("audio_bus_from_interleaved", "", trace_name,
+                         total_time_milliseconds / kBenchmarkIterations, "ms",
+                         true);
 }
 
 // Benchmark the FromInterleaved() and ToInterleaved() methods.
@@ -49,9 +46,10 @@
   FakeAudioRenderCallback callback(0.2, kSampleRate);
   callback.Render(base::TimeDelta(), base::TimeTicks::Now(), 0, bus.get());
 
-  RunInterleaveBench<int8_t>(bus.get(), "int8_t");
-  RunInterleaveBench<int16_t>(bus.get(), "int16_t");
-  RunInterleaveBench<int32_t>(bus.get(), "int32_t");
+  // Only benchmark these two types since they're the only commonly used ones.
+  RunInterleaveBench<int16_t, SignedInt16SampleTypeTraits>(bus.get(),
+                                                           "int16_t");
+  RunInterleaveBench<float, Float32SampleTypeTraits>(bus.get(), "float");
 }
 
-} // namespace media
+}  // namespace media
diff --git a/third_party/WebKit/Source/core/editing/GranularityStrategy.cpp b/third_party/WebKit/Source/core/editing/GranularityStrategy.cpp
index c266733..da309c6 100644
--- a/third_party/WebKit/Source/core/editing/GranularityStrategy.cpp
+++ b/third_party/WebKit/Source/core/editing/GranularityStrategy.cpp
@@ -111,7 +111,7 @@
   if (state_ == StrategyState::kCleared)
     state_ = StrategyState::kExpanding;
 
-  VisiblePosition old_offset_extent_position = selection.VisibleExtent();
+  const VisiblePosition& old_offset_extent_position = selection.VisibleExtent();
   IntPoint old_extent_location = PositionLocation(old_offset_extent_position);
 
   IntPoint old_offset_extent_point =
@@ -263,7 +263,7 @@
         offset_extent_before_middle ? bound_before_extent : bound_after_extent;
     // Update the offset if selection expanded in word granularity.
     if (new_selection_extent.DeepEquivalent() !=
-            selection.VisibleExtent().DeepEquivalent() &&
+            old_offset_extent_position.DeepEquivalent() &&
         ((new_extent_base_order > 0 && !offset_extent_before_middle) ||
          (new_extent_base_order < 0 && offset_extent_before_middle))) {
       offset_ = PositionLocation(new_selection_extent).X() - extent_point.X();
@@ -273,7 +273,7 @@
   // Only update the state if the selection actually changed as a result of
   // this move.
   if (new_selection_extent.DeepEquivalent() !=
-      selection.VisibleExtent().DeepEquivalent())
+      old_offset_extent_position.DeepEquivalent())
     state_ = this_move_shrunk_selection ? StrategyState::kShrinking
                                         : StrategyState::kExpanding;
 
diff --git a/third_party/WebKit/Source/modules/permissions/ClipboardPermissionDescriptor.idl b/third_party/WebKit/Source/modules/permissions/ClipboardPermissionDescriptor.idl
index db0ec40..b351a623 100644
--- a/third_party/WebKit/Source/modules/permissions/ClipboardPermissionDescriptor.idl
+++ b/third_party/WebKit/Source/modules/permissions/ClipboardPermissionDescriptor.idl
@@ -3,5 +3,5 @@
 // found in the LICENSE file.
 
 dictionary ClipboardPermissionDescriptor : PermissionDescriptor {
-    required boolean allowWithoutGesture;
+    boolean allowWithoutGesture = false;
 };
diff --git a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.cpp b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.cpp
index 8adb90bc..b18e529 100644
--- a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.cpp
+++ b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.cpp
@@ -32,6 +32,8 @@
 #include "gpu/command_buffer/client/gles2_interface.h"
 #include "gpu/command_buffer/client/gpu_memory_buffer_manager.h"
 #include "gpu/command_buffer/common/capabilities.h"
+#include "gpu/config/gpu_driver_bug_workaround_type.h"
+#include "gpu/config/gpu_feature_info.h"
 #include "platform/Histogram.h"
 #include "platform/WebTaskRunner.h"
 #include "platform/graphics/AcceleratedStaticBitmapImage.h"
@@ -197,6 +199,16 @@
     DCHECK(context_provider_wrapper_);
     DCHECK(
         !context_provider_wrapper_->ContextProvider()->IsSoftwareRendering());
+    // See whether the use of GpuMemoryBuffers was blacklisted since
+    // the time the browser determined whether to use the feature
+    // based on the command line flags. This is the only way to avoid
+    // race conditions when determining whether to use this feature.
+    use_gpu_memory_buffers_ =
+        RuntimeEnabledFeatures::Canvas2dImageChromiumEnabled() &&
+        !context_provider_wrapper_->ContextProvider()
+             ->GetGpuFeatureInfo()
+             .IsWorkaroundEnabled(
+                 gpu::DISABLE_GPU_MEMORY_BUFFERS_AS_RENDER_TARGETS);
   }
   // Used by browser tests to detect the use of a Canvas2DLayerBridge.
   TRACE_EVENT_INSTANT0("test_gpu", "Canvas2DLayerBridgeCreation",
@@ -209,7 +221,7 @@
 Canvas2DLayerBridge::~Canvas2DLayerBridge() {
   BeginDestruction();
   DCHECK(destruction_in_progress_);
-  if (RuntimeEnabledFeatures::Canvas2dImageChromiumEnabled())
+  if (use_gpu_memory_buffers_)
     ClearCHROMIUMImageCache();
   layer_.reset();
 }
@@ -376,7 +388,7 @@
   if (!image_id)
     return nullptr;
 
-  GLuint texture_id;
+  GLuint texture_id = 0;
   gl->GenTextures(1, &texture_id);
   GLenum target = GC3D_TEXTURE_RECTANGLE_ARB;
   gl->BindTexture(target, texture_id);
@@ -423,7 +435,7 @@
   if (!skia_image || !skia_image->getTexture())
     return false;
 
-  if (RuntimeEnabledFeatures::Canvas2dImageChromiumEnabled()) {
+  if (use_gpu_memory_buffers_) {
     if (PrepareGpuMemoryBufferMailboxFromImage(skia_image.get(), mailbox_info,
                                                out_mailbox))
       return true;
@@ -552,7 +564,7 @@
   hibernation_image_ = temp_hibernation_surface->makeImageSnapshot();
   ResetSurface();
   layer_->ClearTexture();
-  if (RuntimeEnabledFeatures::Canvas2dImageChromiumEnabled())
+  if (use_gpu_memory_buffers_)
     ClearCHROMIUMImageCache();
   // shouldBeDirectComposited() may have changed.
   if (image_buffer_)
@@ -1030,24 +1042,21 @@
                  ->GetGraphicsResetStatusKHR() != GL_NO_ERROR);
   }
 
-  if (RuntimeEnabledFeatures::Canvas2dImageChromiumEnabled()) {
-    scoped_refptr<ImageInfo>& info = released_mailbox_info->image_info_;
-    if (info) {
-      if (lost_resource || context_or_layer_bridge_lost) {
-        DeleteCHROMIUMImage(context_provider_wrapper,
-                            std::move(info->gpu_memory_buffer_),
-                            info->image_id_, info->texture_id_);
-      } else {
-        layer_bridge->image_info_cache_.push_back(info);
-      }
+  scoped_refptr<ImageInfo>& info = released_mailbox_info->image_info_;
+  if (info) {
+    if (lost_resource || context_or_layer_bridge_lost) {
+      DeleteCHROMIUMImage(context_provider_wrapper,
+                          std::move(info->gpu_memory_buffer_), info->image_id_,
+                          info->texture_id_);
+    } else {
+      layer_bridge->image_info_cache_.push_back(info);
     }
   }
 
   // Invalidate texture state in case the compositor altered it since the
   // copy-on-write.
   if (released_mailbox_info->image_) {
-    if (RuntimeEnabledFeatures::Canvas2dImageChromiumEnabled())
-      DCHECK(!released_mailbox_info->image_info_);
+    DCHECK(!released_mailbox_info->image_info_);
     bool layer_bridge_with_valid_context =
         layer_bridge && !context_or_layer_bridge_lost;
     if (layer_bridge_with_valid_context || !layer_bridge) {
diff --git a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.h b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.h
index e5741625..6eb59ac5 100644
--- a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.h
+++ b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.h
@@ -257,6 +257,7 @@
   bool dont_use_idle_scheduling_for_testing_ = false;
   bool did_draw_since_last_flush_ = false;
   bool did_draw_since_last_gpu_flush_ = false;
+  bool use_gpu_memory_buffers_ = false;
 
   friend class Canvas2DLayerBridgeTest;
   friend class CanvasRenderingContext2DTest;
diff --git a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridgeTest.cpp b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridgeTest.cpp
index fd84131..804be84 100644
--- a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridgeTest.cpp
+++ b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridgeTest.cpp
@@ -99,6 +99,7 @@
 class FakeGLES2InterfaceWithImageSupport : public FakeGLES2Interface {
  public:
   MOCK_METHOD0(Flush, void());
+  MOCK_METHOD2(GenTextures, void(GLsizei, GLuint*));
 
   GLuint CreateImageCHROMIUM(ClientBuffer, GLsizei, GLsizei, GLenum) override {
     return ++create_image_count_;
@@ -1068,14 +1069,17 @@
 }
 
 TEST_F(Canvas2DLayerBridgeTest, DeleteGpuMemoryBufferAfterTeardown) {
-#if defined(OS_MACOSX) || defined(OS_CHROMEOS)
   ScopedCanvas2dImageChromiumForTest canvas_2d_image_chromium(true);
-#endif
   ScopedTestingPlatformSupport<FakePlatformSupport> platform;
 
   viz::TextureMailbox texture_mailbox;
   std::unique_ptr<viz::SingleReleaseCallback> release_callback;
 
+  // Texture id just needs to be non-zero for image creation to work.
+  const GLint texture_id = 1;
+  EXPECT_CALL(gl_, GenTextures(1, _))
+      .WillOnce(testing::SetArgPointee<1>(texture_id));
+
   {
     Canvas2DLayerBridgePtr bridge(WTF::WrapUnique(new Canvas2DLayerBridge(
         IntSize(300, 150), 0, Canvas2DLayerBridge::kForceAccelerationForTesting,
@@ -1083,15 +1087,12 @@
     bridge->PrepareTextureMailbox(&texture_mailbox, &release_callback);
   }
 
+  ::testing::Mock::VerifyAndClearExpectations(&gl_);
+
   bool lost_resource = false;
   release_callback->Run(gpu::SyncToken(), lost_resource);
-#if defined(OS_MACOSX) || defined(OS_CHROMEOS)
   EXPECT_EQ(1u, gl_.CreateImageCount());
   EXPECT_EQ(1u, gl_.DestroyImageCount());
-#else
-  EXPECT_EQ(0u, gl_.CreateImageCount());
-  EXPECT_EQ(0u, gl_.DestroyImageCount());
-#endif
 }
 
 TEST_F(Canvas2DLayerBridgeTest, NoUnnecessaryFlushes) {
diff --git a/third_party/WebKit/Source/platform/graphics/DEPS b/third_party/WebKit/Source/platform/graphics/DEPS
index 7a8b27a..7d2d339 100644
--- a/third_party/WebKit/Source/platform/graphics/DEPS
+++ b/third_party/WebKit/Source/platform/graphics/DEPS
@@ -16,6 +16,8 @@
     "+gpu/command_buffer/common/capabilities.h",
     "+gpu/command_buffer/common/mailbox.h",
     "+gpu/command_buffer/common/sync_token.h",
+    "+gpu/config/gpu_driver_bug_workaround_type.h",
+    "+gpu/config/gpu_feature_info.h",
     "+media/base/media_switches.h",
     "+media/base/video_frame.h",
     "+services/viz/public/interfaces",
diff --git a/third_party/WebKit/Source/platform/graphics/gpu/DEPS b/third_party/WebKit/Source/platform/graphics/gpu/DEPS
index edeb8e5..e883a8a 100644
--- a/third_party/WebKit/Source/platform/graphics/gpu/DEPS
+++ b/third_party/WebKit/Source/platform/graphics/gpu/DEPS
@@ -1,7 +1,4 @@
 include_rules = [
     "+gpu/command_buffer/client/gles2_interface_stub.h",
-    "+gpu/command_buffer/common/capabilities.h",
     "+gpu/command_buffer/common/gpu_memory_buffer_support.h",
-    "+gpu/config/gpu_driver_bug_workaround_type.h",
-    "+gpu/config/gpu_feature_info.h"
 ]
diff --git a/third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.cpp b/third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.cpp
index a903e61..45449524 100644
--- a/third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.cpp
+++ b/third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.cpp
@@ -1401,9 +1401,15 @@
 }
 
 bool DrawingBuffer::ShouldUseChromiumImage() {
+  // See whether the use of GpuMemoryBuffers was blacklisted since the
+  // time the browser determined whether to use the feature based on
+  // the command line flags. This is the only way to avoid race
+  // conditions when determining whether to use this feature.
   return RuntimeEnabledFeatures::WebGLImageChromiumEnabled() &&
          chromium_image_usage_ == kAllowChromiumImage &&
-         Platform::Current()->GetGpuMemoryBufferManager();
+         Platform::Current()->GetGpuMemoryBufferManager() &&
+         !ContextProvider()->GetGpuFeatureInfo().IsWorkaroundEnabled(
+             gpu::DISABLE_GPU_MEMORY_BUFFERS_AS_RENDER_TARGETS);
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/common/device_memory/approximated_device_memory.cc b/third_party/WebKit/common/device_memory/approximated_device_memory.cc
index aeaa1492..cef87cf 100644
--- a/third_party/WebKit/common/device_memory/approximated_device_memory.cc
+++ b/third_party/WebKit/common/device_memory/approximated_device_memory.cc
@@ -28,8 +28,8 @@
 
 // static
 void ApproximatedDeviceMemory::CalculateAndSetApproximatedDeviceMemory() {
-  // The calculations in this method are described in the specifcations:
-  // https://github.com/WICG/device-memory.
+  // The calculations in this method are described in the specification:
+  // https://w3c.github.io/device-memory/.
   DCHECK_GT(physical_memory_mb_, 0);
   int lower_bound = physical_memory_mb_;
   int power = 0;
@@ -52,8 +52,8 @@
   else
     approximated_device_memory_gb_ = static_cast<float>(upper_bound) / 1024.0;
 
-  // The exact value beyond 8GB is irrelvant, hence we max-limit the reported
-  // value to 8GB.
+  // Max-limit the reported value to 8GB to reduce fingerprintability of
+  // high-spec machines.
   if (approximated_device_memory_gb_ > 8)
     approximated_device_memory_gb_ = 8.0;
 }
diff --git a/third_party/WebKit/common/device_memory/approximated_device_memory.h b/third_party/WebKit/common/device_memory/approximated_device_memory.h
index eaa0259..1f91c26a 100644
--- a/third_party/WebKit/common/device_memory/approximated_device_memory.h
+++ b/third_party/WebKit/common/device_memory/approximated_device_memory.h
@@ -16,8 +16,8 @@
   // Caches the device's physical memory in static members.
   static void BLINK_COMMON_EXPORT Initialize();
 
-  // Returns an approximation of the physical memory rounded to to the most
-  // significant 2-bits. This information is provided to web-developers to allow
+  // Returns an approximation of the physical memory rounded to the most
+  // significant bit. This information is provided to web-developers to allow
   // them to customize the experience of their page to the possible available
   // device memory.
   static float BLINK_COMMON_EXPORT GetApproximatedDeviceMemory();
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 7becba43..e7c649e 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -91796,6 +91796,14 @@
   </summary>
 </histogram>
 
+<histogram name="Webapp.AddToHomescreenDialog.Timeout" units="ms">
+  <owner>dominickn@chromium.org</owner>
+  <summary>
+    Records the number of milliseconds that the add to homescreen dialog
+    required to check installability eligibility.
+  </summary>
+</histogram>
+
 <histogram name="Webapp.Install.DisplayMode" enum="WebAppDisplayMode">
   <owner>piotrs@chromium.org</owner>
   <summary>
diff --git a/ui/base/ui_base_features.cc b/ui/base/ui_base_features.cc
index 2795104..226d90f 100644
--- a/ui/base/ui_base_features.cc
+++ b/ui/base/ui_base_features.cc
@@ -12,9 +12,16 @@
     "DirectManipulationStylus", base::FEATURE_ENABLED_BY_DEFAULT};
 #endif  // defined(OS_WIN)
 
-// Applies the material design mode passed via --top-chrome-md to elements
-// throughout Chrome (not just top Chrome).
+// Applies the material design mode to elements throughout Chrome (not just top
+// Chrome).
 const base::Feature kSecondaryUiMd = {"SecondaryUiMd",
-                                      base::FEATURE_DISABLED_BY_DEFAULT};
+// Enabled by default on Windows and Desktop Linux. http://crbug.com/775847.
+// TODO(tapted): Also enable on Mac when http://crbug.com/780409 is fixed.
+#if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS))
+                                      base::FEATURE_ENABLED_BY_DEFAULT
+#else
+                                      base::FEATURE_DISABLED_BY_DEFAULT
+#endif
+};
 
 }  // namespace features
diff --git a/ui/message_center/fake_message_center.cc b/ui/message_center/fake_message_center.cc
index 2f91888..f6a12d4 100644
--- a/ui/message_center/fake_message_center.cc
+++ b/ui/message_center/fake_message_center.cc
@@ -77,6 +77,9 @@
                                            bool by_user) {
 }
 
+void FakeMessageCenter::RemoveNotificationsForNotifierId(
+    const NotifierId& notifier_id) {}
+
 void FakeMessageCenter::RemoveAllNotifications(bool by_user, RemoveType type) {}
 
 void FakeMessageCenter::SetNotificationIcon(const std::string& notification_id,
@@ -109,15 +112,7 @@
 void FakeMessageCenter::DisplayedNotification(const std::string& id,
                                               const DisplaySource source) {}
 
-void FakeMessageCenter::SetNotifierSettingsProvider(
-    std::unique_ptr<NotifierSettingsProvider> provider) {}
-
-NotifierSettingsProvider* FakeMessageCenter::GetNotifierSettingsProvider() {
-  return nullptr;
-}
-
-void FakeMessageCenter::SetQuietMode(bool in_quiet_mode) {
-}
+void FakeMessageCenter::SetQuietMode(bool in_quiet_mode) {}
 
 void FakeMessageCenter::SetLockedState(bool locked) {}
 
diff --git a/ui/message_center/fake_message_center.h b/ui/message_center/fake_message_center.h
index fd4b1be..7991b175 100644
--- a/ui/message_center/fake_message_center.h
+++ b/ui/message_center/fake_message_center.h
@@ -39,6 +39,7 @@
       std::unique_ptr<Notification> new_notification) override;
 
   void RemoveNotification(const std::string& id, bool by_user) override;
+  void RemoveNotificationsForNotifierId(const NotifierId& notifier_id) override;
   void RemoveAllNotifications(bool by_user, RemoveType type) override;
   void SetNotificationIcon(const std::string& notification_id,
                            const gfx::Image& image) override;
@@ -57,9 +58,6 @@
                               bool mark_notification_as_read) override;
   void DisplayedNotification(const std::string& id,
                              const DisplaySource source) override;
-  void SetNotifierSettingsProvider(
-      std::unique_ptr<NotifierSettingsProvider> provider) override;
-  NotifierSettingsProvider* GetNotifierSettingsProvider() override;
   void SetQuietMode(bool in_quiet_mode) override;
   void SetLockedState(bool locked) override;
   void EnterQuietModeWithExpire(const base::TimeDelta& expires_in) override;
diff --git a/ui/message_center/message_center.h b/ui/message_center/message_center.h
index 99add0d..55480b78 100644
--- a/ui/message_center/message_center.h
+++ b/ui/message_center/message_center.h
@@ -42,7 +42,6 @@
 class MessageCenterObserver;
 class MessageCenterImplTest;
 class NotificationBlocker;
-class NotifierSettingsProvider;
 
 class MESSAGE_CENTER_EXPORT MessageCenter {
  public:
@@ -105,6 +104,8 @@
 
   // Removes an existing notification.
   virtual void RemoveNotification(const std::string& id, bool by_user) = 0;
+  virtual void RemoveNotificationsForNotifierId(
+      const NotifierId& notifier_id) = 0;
   virtual void RemoveAllNotifications(bool by_user, RemoveType type) = 0;
 
   // Sets the icon image. Icon appears at the top-left of the notification.
@@ -151,12 +152,6 @@
       const std::string& id,
       const DisplaySource source) = 0;
 
-  // Setter/getter of notifier settings provider. The getter may return null
-  // for tests, and will always be null on non-ChromeOS.
-  virtual void SetNotifierSettingsProvider(
-      std::unique_ptr<NotifierSettingsProvider> provider) = 0;
-  virtual NotifierSettingsProvider* GetNotifierSettingsProvider() = 0;
-
   // This can be called to change the quiet mode state (without a timeout).
   virtual void SetQuietMode(bool in_quiet_mode) = 0;
 
diff --git a/ui/message_center/message_center_impl.cc b/ui/message_center/message_center_impl.cc
index 67ce2fac..6cc3505 100644
--- a/ui/message_center/message_center_impl.cc
+++ b/ui/message_center/message_center_impl.cc
@@ -153,14 +153,6 @@
     observer.OnBlockingStateChanged(blocker);
 }
 
-void MessageCenterImpl::NotifierEnabledChanged(
-    const NotifierId& notifier_id, bool enabled) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  if (!enabled) {
-    RemoveNotificationsForNotifierId(notifier_id);
-  }
-}
-
 void MessageCenterImpl::SetVisibility(Visibility visibility) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   DCHECK(!iterating_);
@@ -604,19 +596,6 @@
   }
 }
 
-void MessageCenterImpl::SetNotifierSettingsProvider(
-    std::unique_ptr<NotifierSettingsProvider> provider) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(!settings_provider_);
-  settings_provider_ = std::move(provider);
-  settings_provider_->AddObserver(this);
-}
-
-NotifierSettingsProvider* MessageCenterImpl::GetNotifierSettingsProvider() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  return settings_provider_.get();
-}
-
 void MessageCenterImpl::SetQuietMode(bool in_quiet_mode) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   if (in_quiet_mode != notification_list_->quiet_mode()) {
diff --git a/ui/message_center/message_center_impl.h b/ui/message_center/message_center_impl.h
index ef99d53..4b25c9b 100644
--- a/ui/message_center/message_center_impl.h
+++ b/ui/message_center/message_center_impl.h
@@ -33,8 +33,7 @@
 // The default implementation of MessageCenter.
 class MESSAGE_CENTER_EXPORT MessageCenterImpl
     : public MessageCenter,
-      public NotificationBlocker::Observer,
-      public message_center::NotifierSettingsObserver {
+      public NotificationBlocker::Observer {
  public:
   MessageCenterImpl();
   ~MessageCenterImpl() override;
@@ -60,6 +59,7 @@
       const std::string& old_id,
       std::unique_ptr<Notification> new_notification) override;
   void RemoveNotification(const std::string& id, bool by_user) override;
+  void RemoveNotificationsForNotifierId(const NotifierId& notifier_id) override;
   void RemoveAllNotifications(bool by_user, RemoveType type) override;
   void SetNotificationIcon(const std::string& notification_id,
                            const gfx::Image& image) override;
@@ -76,9 +76,6 @@
                               bool mark_notification_as_read) override;
   void DisplayedNotification(const std::string& id,
                              const DisplaySource source) override;
-  void SetNotifierSettingsProvider(
-      std::unique_ptr<NotifierSettingsProvider> provider) override;
-  NotifierSettingsProvider* GetNotifierSettingsProvider() override;
   void SetQuietMode(bool in_quiet_mode) override;
   void SetLockedState(bool locked) override;
   void EnterQuietModeWithExpire(const base::TimeDelta& expires_in) override;
@@ -90,10 +87,6 @@
   // NotificationBlocker::Observer overrides:
   void OnBlockingStateChanged(NotificationBlocker* blocker) override;
 
-  // message_center::NotifierSettingsObserver overrides:
-  void NotifierEnabledChanged(const NotifierId& notifier_id,
-                              bool enabled) override;
-
   // Unexposed methods:
   void AddNotificationImmediately(std::unique_ptr<Notification> notification);
   void UpdateNotificationImmediately(
@@ -119,7 +112,6 @@
 
   Notification* GetLatestNotificationIncludingQueued(
       const std::string& id) const;
-  void RemoveNotificationsForNotifierId(const NotifierId& notifier_id);
 
   THREAD_CHECKER(thread_checker_);
 
@@ -128,8 +120,6 @@
   base::ObserverList<MessageCenterObserver> observer_list_;
   std::unique_ptr<PopupTimersController> popup_timers_controller_;
   std::unique_ptr<base::OneShotTimer> quiet_mode_timer_;
-  // Null on !ChromeOS.
-  std::unique_ptr<NotifierSettingsProvider> settings_provider_;
   std::vector<NotificationBlocker*> blockers_;
   std::unique_ptr<ChangeQueue> notification_change_queue_;
 
diff --git a/ui/message_center/message_center_impl_unittest.cc b/ui/message_center/message_center_impl_unittest.cc
index 8aa2e18c..3198015 100644
--- a/ui/message_center/message_center_impl_unittest.cc
+++ b/ui/message_center/message_center_impl_unittest.cc
@@ -94,9 +94,6 @@
   }
 
   MessageCenter* message_center() const { return message_center_; }
-  NotifierSettingsObserver* notifier_settings_observer() const {
-    return static_cast<NotifierSettingsObserver*>(message_center_impl());
-  }
   MessageCenterImpl* message_center_impl() const {
     return reinterpret_cast<MessageCenterImpl*>(message_center_);
   }
@@ -737,24 +734,19 @@
       CreateSimpleNotificationWithNotifierId("id2-5", "app2")));
   ASSERT_EQ(8u, message_center()->NotificationCount());
 
-  // Enabling an extension should have no effect on the count.
-  notifier_settings_observer()->NotifierEnabledChanged(
-      NotifierId(NotifierId::APPLICATION, "app1"), true);
-  ASSERT_EQ(8u, message_center()->NotificationCount());
-
   // Removing all of app2's notifications should only leave app1's.
-  notifier_settings_observer()->NotifierEnabledChanged(
-      NotifierId(NotifierId::APPLICATION, "app2"), false);
+  message_center()->RemoveNotificationsForNotifierId(
+      NotifierId(NotifierId::APPLICATION, "app2"));
   ASSERT_EQ(3u, message_center()->NotificationCount());
 
   // Removal operations should be idempotent.
-  notifier_settings_observer()->NotifierEnabledChanged(
-      NotifierId(NotifierId::APPLICATION, "app2"), false);
+  message_center()->RemoveNotificationsForNotifierId(
+      NotifierId(NotifierId::APPLICATION, "app2"));
   ASSERT_EQ(3u, message_center()->NotificationCount());
 
   // Now we remove the remaining notifications.
-  notifier_settings_observer()->NotifierEnabledChanged(
-      NotifierId(NotifierId::APPLICATION, "app1"), false);
+  message_center()->RemoveNotificationsForNotifierId(
+      NotifierId(NotifierId::APPLICATION, "app1"));
   ASSERT_EQ(0u, message_center()->NotificationCount());
 }
 
diff --git a/ui/message_center/message_center_tray.h b/ui/message_center/message_center_tray.h
index 7377d3b..28e4724 100644
--- a/ui/message_center/message_center_tray.h
+++ b/ui/message_center/message_center_tray.h
@@ -20,6 +20,7 @@
 namespace message_center {
 
 class MessageCenter;
+class Notification;
 
 // Class that observes a MessageCenter. Manages the popup and message center
 // bubbles. Tells the MessageCenterTrayHost when the tray is changed, as well
diff --git a/ui/message_center/mojo/BUILD.gn b/ui/message_center/mojo/BUILD.gn
index a19b11a..d970d869 100644
--- a/ui/message_center/mojo/BUILD.gn
+++ b/ui/message_center/mojo/BUILD.gn
@@ -7,6 +7,7 @@
 mojom("mojo") {
   sources = [
     "notification.mojom",
+    "notifier_id.mojom",
   ]
 
   public_deps = [
@@ -31,6 +32,8 @@
   sources = [
     "notification_struct_traits.cc",
     "notification_struct_traits.h",
+    "notifier_id_struct_traits.cc",
+    "notifier_id_struct_traits.h",
   ]
 
   public_deps = [
diff --git a/ui/message_center/mojo/notifier_id.mojom b/ui/message_center/mojo/notifier_id.mojom
new file mode 100644
index 0000000..cf7a9a6
--- /dev/null
+++ b/ui/message_center/mojo/notifier_id.mojom
@@ -0,0 +1,26 @@
+// 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.
+
+module message_center.mojom;
+
+import "mojo/common/string16.mojom";
+import "url/mojo/url.mojom";
+
+// Equivalent to message_center::NotifierId::NotifierType. Used in UMA, so it
+// should not be reordered.
+enum NotifierType {
+  APPLICATION,
+  ARC_APPLICATION,
+  WEB_PAGE,
+  SYSTEM_COMPONENT,
+  SIZE,
+};
+
+// Equivalent to message_center::NotifierId.
+struct NotifierId {
+  NotifierType type;
+  string id;
+  url.mojom.Url url;
+  string profile_id;
+};
diff --git a/ui/message_center/mojo/notifier_id.typemap b/ui/message_center/mojo/notifier_id.typemap
new file mode 100644
index 0000000..8ac9e00
--- /dev/null
+++ b/ui/message_center/mojo/notifier_id.typemap
@@ -0,0 +1,14 @@
+# 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.
+
+mojom = "//ui/message_center/mojo/notifier_id.mojom"
+public_headers = [ "//ui/message_center/notifier_settings.h" ]
+traits_headers = [ "//ui/message_center/mojo/notifier_id_struct_traits.h" ]
+deps = [
+  "//ui/message_center/mojo:struct_traits",
+]
+type_mappings = [
+  "message_center.mojom.NotifierId=message_center::NotifierId",
+  "message_center.mojom.NotifierType=message_center::NotifierId::NotifierType",
+]
diff --git a/ui/message_center/mojo/notifier_id_struct_traits.cc b/ui/message_center/mojo/notifier_id_struct_traits.cc
new file mode 100644
index 0000000..424df767
--- /dev/null
+++ b/ui/message_center/mojo/notifier_id_struct_traits.cc
@@ -0,0 +1,47 @@
+// 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 "ui/message_center/mojo/notifier_id_struct_traits.h"
+
+#include "mojo/common/common_custom_types_struct_traits.h"
+#include "url/mojo/url_gurl_struct_traits.h"
+
+namespace mojo {
+
+using NotifierIdStructTraits =
+    StructTraits<message_center::mojom::NotifierIdDataView,
+                 message_center::NotifierId>;
+
+// static
+const message_center::NotifierId::NotifierType& NotifierIdStructTraits::type(
+    const message_center::NotifierId& n) {
+  return n.type;
+}
+
+// static
+const std::string& NotifierIdStructTraits::id(
+    const message_center::NotifierId& n) {
+  return n.id;
+}
+
+// static
+const GURL& NotifierIdStructTraits::url(const message_center::NotifierId& n) {
+  return n.url;
+}
+
+//  static
+const std::string& NotifierIdStructTraits::profile_id(
+    const message_center::NotifierId& n) {
+  return n.profile_id;
+}
+
+// static
+bool NotifierIdStructTraits::Read(
+    message_center::mojom::NotifierIdDataView data,
+    message_center::NotifierId* out) {
+  return data.ReadType(&out->type) && data.ReadId(&out->id) &&
+         data.ReadUrl(&out->url) && data.ReadProfileId(&out->profile_id);
+}
+
+}  // namespace mojo
diff --git a/ui/message_center/mojo/notifier_id_struct_traits.h b/ui/message_center/mojo/notifier_id_struct_traits.h
new file mode 100644
index 0000000..ccdf946
--- /dev/null
+++ b/ui/message_center/mojo/notifier_id_struct_traits.h
@@ -0,0 +1,71 @@
+// 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 UI_MESSAGE_CENTER_NOTIFIER_ID_STRUCT_TRAITS_H_
+#define UI_MESSAGE_CENTER_NOTIFIER_ID_STRUCT_TRAITS_H_
+
+#include "ui/message_center/mojo/notifier_id.mojom-shared.h"
+#include "ui/message_center/notifier_settings.h"
+
+namespace mojo {
+
+template <>
+struct EnumTraits<message_center::mojom::NotifierType,
+                  message_center::NotifierId::NotifierType> {
+  static message_center::mojom::NotifierType ToMojom(
+      message_center::NotifierId::NotifierType input) {
+    switch (input) {
+      case message_center::NotifierId::APPLICATION:
+        return message_center::mojom::NotifierType::APPLICATION;
+      case message_center::NotifierId::ARC_APPLICATION:
+        return message_center::mojom::NotifierType::ARC_APPLICATION;
+      case message_center::NotifierId::WEB_PAGE:
+        return message_center::mojom::NotifierType::WEB_PAGE;
+      case message_center::NotifierId::SYSTEM_COMPONENT:
+        return message_center::mojom::NotifierType::SYSTEM_COMPONENT;
+      case message_center::NotifierId::SIZE:
+        break;
+    }
+    NOTREACHED();
+    return message_center::mojom::NotifierType::SIZE;
+  }
+
+  static bool FromMojom(message_center::mojom::NotifierType input,
+                        message_center::NotifierId::NotifierType* out) {
+    switch (input) {
+      case message_center::mojom::NotifierType::APPLICATION:
+        *out = message_center::NotifierId::APPLICATION;
+        return true;
+      case message_center::mojom::NotifierType::ARC_APPLICATION:
+        *out = message_center::NotifierId::ARC_APPLICATION;
+        return true;
+      case message_center::mojom::NotifierType::WEB_PAGE:
+        *out = message_center::NotifierId::WEB_PAGE;
+        return true;
+      case message_center::mojom::NotifierType::SYSTEM_COMPONENT:
+        *out = message_center::NotifierId::SYSTEM_COMPONENT;
+        return true;
+      case message_center::mojom::NotifierType::SIZE:
+        break;
+    }
+    NOTREACHED();
+    return false;
+  }
+};
+
+template <>
+struct StructTraits<message_center::mojom::NotifierIdDataView,
+                    message_center::NotifierId> {
+  static const message_center::NotifierId::NotifierType& type(
+      const message_center::NotifierId& n);
+  static const std::string& id(const message_center::NotifierId& n);
+  static const GURL& url(const message_center::NotifierId& n);
+  static const std::string& profile_id(const message_center::NotifierId& n);
+  static bool Read(message_center::mojom::NotifierIdDataView data,
+                   message_center::NotifierId* out);
+};
+
+}  // namespace mojo
+
+#endif  // UI_MESSAGE_CENTER_NOTIFIER_ID_STRUCT_TRAITS_H_
diff --git a/ui/message_center/mojo/typemaps.gni b/ui/message_center/mojo/typemaps.gni
index 211a0d7..a7f5b3d 100644
--- a/ui/message_center/mojo/typemaps.gni
+++ b/ui/message_center/mojo/typemaps.gni
@@ -2,4 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-typemaps = [ "//ui/message_center/mojo/notification.typemap" ]
+typemaps = [
+  "//ui/message_center/mojo/notification.typemap",
+  "//ui/message_center/mojo/notifier_id.typemap",
+]
diff --git a/ui/message_center/notifier_settings.cc b/ui/message_center/notifier_settings.cc
index 9165a971..8e2fd90 100644
--- a/ui/message_center/notifier_settings.cc
+++ b/ui/message_center/notifier_settings.cc
@@ -8,6 +8,8 @@
 
 namespace message_center {
 
+NotifierId::NotifierId() : type(SYSTEM_COMPONENT) {}
+
 NotifierId::NotifierId(NotifierType type,
                        const std::string& id)
     : type(type),
@@ -20,10 +22,6 @@
     : type(WEB_PAGE),
       url(url) {}
 
-NotifierId::NotifierId()
-    : type(SYSTEM_COMPONENT) {
-}
-
 NotifierId::NotifierId(const NotifierId& other) = default;
 
 bool NotifierId::operator==(const NotifierId& other) const {
@@ -52,15 +50,4 @@
   return id < other.id;
 }
 
-NotifierUiData::NotifierUiData(const NotifierId& notifier_id,
-                               const base::string16& name,
-                               bool has_advanced_settings,
-                               bool enabled)
-    : notifier_id(notifier_id),
-      name(name),
-      has_advanced_settings(has_advanced_settings),
-      enabled(enabled) {}
-
-NotifierUiData::~NotifierUiData() {}
-
 }  // namespace message_center
diff --git a/ui/message_center/notifier_settings.h b/ui/message_center/notifier_settings.h
index 7f870e8..80edfe8 100644
--- a/ui/message_center/notifier_settings.h
+++ b/ui/message_center/notifier_settings.h
@@ -10,40 +10,18 @@
 #include <string>
 #include <vector>
 
-#include "base/gtest_prod_util.h"
 #include "base/macros.h"
 #include "base/strings/string16.h"
 #include "ui/gfx/image/image.h"
 #include "ui/message_center/message_center_export.h"
 #include "url/gurl.h"
 
-class MessageCenterNotificationsTest;
-class MessageCenterTrayBridgeTest;
-
-namespace ash {
-class WebNotificationTrayTest;
-}
-
 namespace message_center {
-namespace test {
-class MessagePopupCollectionTest;
-}
-
-class MessageCenterNotificationManagerTest;
-class Notification;
-class NotifierSettingsDelegate;
-class NotifierSettingsProvider;
-
-// Brings up the settings dialog and returns a weak reference to the delegate,
-// which is typically the view. If the dialog already exists, it is brought to
-// the front, otherwise it is created.
-MESSAGE_CENTER_EXPORT NotifierSettingsDelegate* ShowSettings(
-    NotifierSettingsProvider* provider,
-    gfx::NativeView context);
 
 // A struct that identifies the source of notifications. For example, a web page
 // might send multiple notifications but they'd all have the same NotifierId.
-// TODO(estade): rename to Notifier.
+// TODO(estade): rename to Notifier. Rename file to notifier.h. Move to public
+// directory.
 struct MESSAGE_CENTER_EXPORT NotifierId {
   // This enum is being used for histogram reporting and the elements should not
   // be re-ordered.
@@ -55,6 +33,9 @@
     SIZE,
   };
 
+  // Default constructor needed for generated mojom files and tests.
+  NotifierId();
+
   // Constructor for non WEB_PAGE type.
   NotifierId(NotifierType type, const std::string& id);
 
@@ -78,90 +59,6 @@
   // The identifier of the profile where the notification is created. This is
   // used for ChromeOS multi-profile support and can be empty.
   std::string profile_id;
-
- private:
-  friend class MessageCenterNotificationManagerTest;
-  friend class MessageCenterTrayTest;
-  friend class Notification;
-  friend class NotificationControllerTest;
-  friend class PopupCollectionTest;
-  friend class TrayViewControllerTest;
-  friend class ::MessageCenterNotificationsTest;
-  friend class ::MessageCenterTrayBridgeTest;
-  friend class ash::WebNotificationTrayTest;
-  friend class test::MessagePopupCollectionTest;
-  FRIEND_TEST_ALL_PREFIXES(PopupControllerTest, Creation);
-  FRIEND_TEST_ALL_PREFIXES(NotificationListTest, UnreadCountNoNegative);
-  FRIEND_TEST_ALL_PREFIXES(NotificationListTest, TestHasNotificationOfType);
-
-  // The default constructor which doesn't specify the notifier. Used for tests.
-  NotifierId();
-};
-
-// A struct to hold UI information about notifiers. The data is used by
-// NotifierSettingsView.
-struct MESSAGE_CENTER_EXPORT NotifierUiData {
-  NotifierUiData(const NotifierId& notifier_id,
-                 const base::string16& name,
-                 bool has_advanced_settings,
-                 bool enabled);
-  ~NotifierUiData();
-
-  NotifierId notifier_id;
-
-  // The human-readable name of the notifier such like the extension name.
-  // It can be empty.
-  base::string16 name;
-
-  // True if the notifier should have an affordance for advanced settings.
-  bool has_advanced_settings;
-
-  // True if the source is allowed to send notifications. True is default.
-  bool enabled;
-
-  // The icon image of the notifier. The extension icon or favicon.
-  gfx::Image icon;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(NotifierUiData);
-};
-
-// An observer class implemented by the view of the NotifierSettings to get
-// notified when the controller has changed data.
-class MESSAGE_CENTER_EXPORT NotifierSettingsObserver {
- public:
-  // Called when an icon in the controller has been updated.
-  virtual void UpdateIconImage(const NotifierId& notifier_id,
-                               const gfx::Image& icon){};
-
-  // Called when a notifier is enabled or disabled.
-  virtual void NotifierEnabledChanged(const NotifierId& notifier_id,
-                                      bool enabled){};
-};
-
-// A class used by NotifierSettingsView to integrate with a setting system
-// for the clients of this module.
-class MESSAGE_CENTER_EXPORT NotifierSettingsProvider {
- public:
-  virtual ~NotifierSettingsProvider() {}
-
-  // Sets the delegate.
-  virtual void AddObserver(NotifierSettingsObserver* observer) = 0;
-  virtual void RemoveObserver(NotifierSettingsObserver* observer) = 0;
-
-  // Provides the current notifier list in |notifiers|.
-  virtual void GetNotifierList(
-      std::vector<std::unique_ptr<NotifierUiData>>* notifiers) = 0;
-
-  // Called when the |enabled| for the given notifier has been changed by user
-  // operation.
-  virtual void SetNotifierEnabled(const NotifierId& notifier_id,
-                                  bool enabled) = 0;
-
-  // Called upon request for more information about a particular notifier.
-  virtual void OnNotifierAdvancedSettingsRequested(
-      const NotifierId& notifier_id,
-      const std::string* notification_id) = 0;
 };
 
 }  // namespace message_center
diff --git a/ui/message_center/views/message_center_controller.h b/ui/message_center/views/message_center_controller.h
index 6df5fa33..312346c 100644
--- a/ui/message_center/views/message_center_controller.h
+++ b/ui/message_center/views/message_center_controller.h
@@ -8,12 +8,12 @@
 #include <memory>
 #include <string>
 
-#include "base/strings/string16.h"
 #include "ui/base/models/menu_model.h"
-#include "ui/message_center/notifier_settings.h"
 
 namespace message_center {
 
+class Notification;
+
 // Interface used by views to report clicks and other user actions. The views
 // by themselves do not know how to perform those operations, they ask
 // MessageCenterController to do them. Implemented by MessageCenterView and