[go: nahoru, domu]

mash: remove the LockStateControllerDelegate.

This removes the LockStateControllerDelegate and mojoifys/renames it
into the ShutdownClient, which is exported by chrome.

While in the long term, we'll want to move the code that's currently in
ShutdownClient into ash (and either use CrosSettings in ash or send
messages to a dedicated CrosSettings service), the chromeos device
settings code is sufficiently intertangled with the browser process that
it isn't happening anytime soon. (See crbug.com/446937)

BUG=628792
TEST=covered by converted ash_unittests; manually tested the mojo call in non-mash ash.

Review-Url: https://codereview.chromium.org/2471643002
Cr-Commit-Position: refs/heads/master@{#429471}
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index a6aee8a..3c4266f 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -813,6 +813,8 @@
     "wm/session_state_animator.h",
     "wm/session_state_animator_impl.cc",
     "wm/session_state_animator_impl.h",
+    "wm/shutdown_client_proxy.cc",
+    "wm/shutdown_client_proxy.h",
     "wm/stacking_controller.cc",
     "wm/stacking_controller.h",
     "wm/system_gesture_event_filter.cc",
diff --git a/ash/accelerators/accelerator_controller_unittest.cc b/ash/accelerators/accelerator_controller_unittest.cc
index a249ec86..93bc0b5 100644
--- a/ash/accelerators/accelerator_controller_unittest.cc
+++ b/ash/accelerators/accelerator_controller_unittest.cc
@@ -22,6 +22,7 @@
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
+#include "ash/test/lock_state_controller_test_api.h"
 #include "ash/test/test_screenshot_delegate.h"
 #include "ash/test/test_session_state_animator.h"
 #include "ash/wm/lock_state_controller.h"
@@ -1114,7 +1115,7 @@
   ui::test::EventGenerator& generator = GetEventGenerator();
 #if defined(OS_CHROMEOS)
   // Power key (reserved) should always be handled.
-  LockStateController::TestApi test_api(
+  test::LockStateControllerTestApi test_api(
       Shell::GetInstance()->lock_state_controller());
   EXPECT_FALSE(test_api.is_animating_lock());
   generator.PressKey(ui::VKEY_POWER, ui::EF_NONE);
@@ -1164,7 +1165,7 @@
   ui::test::EventGenerator& generator = GetEventGenerator();
 #if defined(OS_CHROMEOS)
   // Power key (reserved) should always be handled.
-  LockStateController::TestApi test_api(
+  test::LockStateControllerTestApi test_api(
       Shell::GetInstance()->lock_state_controller());
   EXPECT_FALSE(test_api.is_animating_lock());
   generator.PressKey(ui::VKEY_POWER, ui::EF_NONE);
diff --git a/ash/public/interfaces/BUILD.gn b/ash/public/interfaces/BUILD.gn
index 4230aad..f634af3a 100644
--- a/ash/public/interfaces/BUILD.gn
+++ b/ash/public/interfaces/BUILD.gn
@@ -10,6 +10,7 @@
     "locale.mojom",
     "new_window.mojom",
     "shelf.mojom",
+    "shutdown.mojom",
     "system_tray.mojom",
     "volume.mojom",
     "wallpaper.mojom",
diff --git a/ash/public/interfaces/shutdown.mojom b/ash/public/interfaces/shutdown.mojom
new file mode 100644
index 0000000..e0060fb
--- /dev/null
+++ b/ash/public/interfaces/shutdown.mojom
@@ -0,0 +1,16 @@
+// Copyright 2016 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 ash.mojom;
+
+// Interface implemented by service:content_browser to activate shutdown.
+//
+// TODO(erg): Eventually, when CrosSettings is moved out of chrome into its
+// own process, this client should go away. The code which actually calls
+// shutdown should be moved into ash/, and ash should subscribe to changes
+// in CrosSettings. crbug.com/628792
+interface ShutdownClient {
+  // Requests that the system shuts down.
+  RequestShutdown();
+};
diff --git a/ash/shell.cc b/ash/shell.cc
index 201c55f9..9c211fc 100644
--- a/ash/shell.cc
+++ b/ash/shell.cc
@@ -724,7 +724,8 @@
   screen_pinning_controller_.reset(
       new ScreenPinningController(window_tree_host_manager_.get()));
 
-  lock_state_controller_.reset(new LockStateController);
+  lock_state_controller_ = base::MakeUnique<LockStateController>(
+      wm_shell_->delegate()->GetShellConnector());
   power_button_controller_.reset(
       new PowerButtonController(lock_state_controller_.get()));
 #if defined(OS_CHROMEOS)
diff --git a/ash/test/BUILD.gn b/ash/test/BUILD.gn
index 7c51996..787ef5d 100644
--- a/ash/test/BUILD.gn
+++ b/ash/test/BUILD.gn
@@ -85,6 +85,8 @@
     "cursor_manager_test_api.h",
     "immersive_fullscreen_controller_test_api.cc",
     "immersive_fullscreen_controller_test_api.h",
+    "lock_state_controller_test_api.cc",
+    "lock_state_controller_test_api.h",
     "mirror_window_test_api.cc",
     "mirror_window_test_api.h",
     "overflow_bubble_view_test_api.cc",
@@ -103,8 +105,6 @@
     "test_activation_delegate.h",
     "test_keyboard_ui.cc",
     "test_keyboard_ui.h",
-    "test_lock_state_controller_delegate.cc",
-    "test_lock_state_controller_delegate.h",
     "test_overlay_delegate.cc",
     "test_overlay_delegate.h",
     "test_screenshot_delegate.cc",
@@ -113,6 +113,8 @@
     "test_session_state_animator.h",
     "test_shell_delegate.cc",
     "test_shell_delegate.h",
+    "test_shutdown_client.cc",
+    "test_shutdown_client.h",
     "test_suite.cc",
     "test_suite.h",
     "test_suite_init.h",
@@ -135,6 +137,7 @@
   deps = [
     "//ash/common/test:test_support",
     "//ash/public/cpp",
+    "//ash/public/interfaces",
     "//ash/resources",
     "//base:i18n",
     "//base/test:test_support",
diff --git a/ash/test/lock_state_controller_test_api.cc b/ash/test/lock_state_controller_test_api.cc
new file mode 100644
index 0000000..b173468
--- /dev/null
+++ b/ash/test/lock_state_controller_test_api.cc
@@ -0,0 +1,29 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/test/lock_state_controller_test_api.h"
+
+#include <memory>
+#include <utility>
+
+#include "ash/public/interfaces/shutdown.mojom.h"
+
+namespace ash {
+namespace test {
+
+LockStateControllerTestApi::LockStateControllerTestApi(
+    LockStateController* controller)
+    : controller_(controller) {
+  DCHECK(controller);
+}
+
+LockStateControllerTestApi::~LockStateControllerTestApi() {}
+
+void LockStateControllerTestApi::SetShutdownClient(
+    std::unique_ptr<mojom::ShutdownClient> client) {
+  controller_->shutdown_client_ = std::move(client);
+}
+
+}  // namespace test
+}  // namespace ash
diff --git a/ash/test/lock_state_controller_test_api.h b/ash/test/lock_state_controller_test_api.h
new file mode 100644
index 0000000..31ca2112
--- /dev/null
+++ b/ash/test/lock_state_controller_test_api.h
@@ -0,0 +1,73 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_TEST_LOCK_STATE_CONTROLLER_TEST_API_H_
+#define ASH_TEST_LOCK_STATE_CONTROLLER_TEST_API_H_
+
+#include <memory>
+
+#include "ash/wm/lock_state_controller.h"
+#include "base/timer/elapsed_timer.h"
+#include "base/timer/timer.h"
+
+namespace ash {
+
+namespace mojom {
+class ShutdownClient;
+}
+
+namespace test {
+
+// Helper class used by tests to access internal state.
+class LockStateControllerTestApi {
+ public:
+  explicit LockStateControllerTestApi(LockStateController* controller);
+  ~LockStateControllerTestApi();
+
+  void SetShutdownClient(std::unique_ptr<mojom::ShutdownClient> client);
+
+  bool lock_fail_timer_is_running() const {
+    return controller_->lock_fail_timer_.IsRunning();
+  }
+  bool lock_to_shutdown_timer_is_running() const {
+    return controller_->lock_to_shutdown_timer_.IsRunning();
+  }
+  bool shutdown_timer_is_running() const {
+    return controller_->pre_shutdown_timer_.IsRunning();
+  }
+  bool real_shutdown_timer_is_running() const {
+    return controller_->real_shutdown_timer_.IsRunning();
+  }
+  bool is_animating_lock() const { return controller_->animating_lock_; }
+  bool is_lock_cancellable() const {
+    return controller_->CanCancelLockAnimation();
+  }
+
+  void trigger_lock_fail_timeout() {
+    controller_->OnLockFailTimeout();
+    controller_->lock_fail_timer_.Stop();
+  }
+  void trigger_lock_to_shutdown_timeout() {
+    controller_->OnLockToShutdownTimeout();
+    controller_->lock_to_shutdown_timer_.Stop();
+  }
+  void trigger_shutdown_timeout() {
+    controller_->OnPreShutdownAnimationTimeout();
+    controller_->pre_shutdown_timer_.Stop();
+  }
+  void trigger_real_shutdown_timeout() {
+    controller_->OnRealPowerTimeout();
+    controller_->real_shutdown_timer_.Stop();
+  }
+
+ private:
+  LockStateController* controller_;  // not owned
+
+  DISALLOW_COPY_AND_ASSIGN(LockStateControllerTestApi);
+};
+
+}  // namespace test
+}  // namespace ash
+
+#endif  // ASH_TEST_LOCK_STATE_CONTROLLER_TEST_API_H_
diff --git a/ash/test/test_lock_state_controller_delegate.cc b/ash/test/test_lock_state_controller_delegate.cc
deleted file mode 100644
index e9904e0..0000000
--- a/ash/test/test_lock_state_controller_delegate.cc
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ash/test/test_lock_state_controller_delegate.h"
-
-namespace ash {
-namespace test {
-
-TestLockStateControllerDelegate::TestLockStateControllerDelegate()
-    : num_shutdown_requests_(0) {}
-
-TestLockStateControllerDelegate::~TestLockStateControllerDelegate() {}
-
-void TestLockStateControllerDelegate::RequestShutdown() {
-  ++num_shutdown_requests_;
-}
-
-}  // namespace test
-}  // namespace ash
diff --git a/ash/test/test_lock_state_controller_delegate.h b/ash/test/test_lock_state_controller_delegate.h
deleted file mode 100644
index 18948303..0000000
--- a/ash/test/test_lock_state_controller_delegate.h
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef ASH_TEST_TEST_LOCK_STATE_CONTROLLER_DELEGATE_H_
-#define ASH_TEST_TEST_LOCK_STATE_CONTROLLER_DELEGATE_H_
-
-#include "ash/wm/lock_state_controller.h"
-#include "base/macros.h"
-
-namespace ash {
-namespace test {
-
-// Fake implementation of PowerButtonControllerDelegate that just logs requests
-// to lock the screen and shut down the device.
-class TestLockStateControllerDelegate : public LockStateControllerDelegate {
- public:
-  TestLockStateControllerDelegate();
-  ~TestLockStateControllerDelegate() override;
-
-  int num_shutdown_requests() const { return num_shutdown_requests_; }
-
-  // LockStateControllerDelegate implementation.
-  void RequestShutdown() override;
-
- private:
-  int num_shutdown_requests_;
-
-  DISALLOW_COPY_AND_ASSIGN(TestLockStateControllerDelegate);
-};
-
-}  // namespace test
-}  // namespace ash
-
-#endif  // ASH_TEST_TEST_LOCK_STATE_CONTROLLER_DELEGATE_H_
diff --git a/ash/test/test_shutdown_client.cc b/ash/test/test_shutdown_client.cc
new file mode 100644
index 0000000..0767d99a
--- /dev/null
+++ b/ash/test/test_shutdown_client.cc
@@ -0,0 +1,19 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/test/test_shutdown_client.h"
+
+namespace ash {
+namespace test {
+
+TestShutdownClient::TestShutdownClient() : num_shutdown_requests_(0) {}
+
+TestShutdownClient::~TestShutdownClient() {}
+
+void TestShutdownClient::RequestShutdown() {
+  ++num_shutdown_requests_;
+}
+
+}  // namespace test
+}  // namespace ash
diff --git a/ash/test/test_shutdown_client.h b/ash/test/test_shutdown_client.h
new file mode 100644
index 0000000..55c7415
--- /dev/null
+++ b/ash/test/test_shutdown_client.h
@@ -0,0 +1,35 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_TEST_TEST_SHUTDOWN_CLIENT_H_
+#define ASH_TEST_TEST_SHUTDOWN_CLIENT_H_
+
+#include "ash/public/interfaces/shutdown.mojom.h"
+#include "base/macros.h"
+
+namespace ash {
+namespace test {
+
+// Fake implementation of ShutdownClient that just logs requests to lock the
+// screen and shut down the device.
+class TestShutdownClient : public mojom::ShutdownClient {
+ public:
+  TestShutdownClient();
+  ~TestShutdownClient() override;
+
+  int num_shutdown_requests() const { return num_shutdown_requests_; }
+
+  // LockStateControllerDelegate implementation.
+  void RequestShutdown() override;
+
+ private:
+  int num_shutdown_requests_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestShutdownClient);
+};
+
+}  // namespace test
+}  // namespace ash
+
+#endif  // ASH_TEST_TEST_SHUTDOWN_CLIENT_H_
diff --git a/ash/wm/lock_state_controller.cc b/ash/wm/lock_state_controller.cc
index b0392dd..d2d8da6 100644
--- a/ash/wm/lock_state_controller.cc
+++ b/ash/wm/lock_state_controller.cc
@@ -13,9 +13,11 @@
 #include "ash/common/shell_delegate.h"
 #include "ash/common/wm_shell.h"
 #include "ash/public/cpp/shell_window_ids.h"
+#include "ash/public/interfaces/shutdown.mojom.h"
 #include "ash/shell.h"
 #include "ash/wm/session_state_animator.h"
 #include "ash/wm/session_state_animator_impl.h"
+#include "ash/wm/shutdown_client_proxy.h"
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/command_line.h"
@@ -70,12 +72,7 @@
 const int LockStateController::kLockToShutdownTimeoutMs = 150;
 const int LockStateController::kShutdownRequestDelayMs = 50;
 
-LockStateController::TestApi::TestApi(LockStateController* controller)
-    : controller_(controller) {}
-
-LockStateController::TestApi::~TestApi() {}
-
-LockStateController::LockStateController()
+LockStateController::LockStateController(service_manager::Connector* connector)
     : animator_(new SessionStateAnimatorImpl()),
       login_status_(LoginStatus::NOT_LOGGED_IN),
       system_is_locked_(false),
@@ -83,6 +80,7 @@
       shutdown_after_lock_(false),
       animating_lock_(false),
       can_cancel_lock_animation_(false),
+      shutdown_client_(base::MakeUnique<ShutdownClientProxy>(connector)),
       weak_ptr_factory_(this) {
   Shell::GetPrimaryRootWindow()->GetHost()->AddObserver(this);
 }
@@ -91,11 +89,6 @@
   Shell::GetPrimaryRootWindow()->GetHost()->RemoveObserver(this);
 }
 
-void LockStateController::SetDelegate(
-    std::unique_ptr<LockStateControllerDelegate> delegate) {
-  delegate_ = std::move(delegate);
-}
-
 void LockStateController::StartLockAnimation(bool shutdown_after_lock) {
   if (animating_lock_)
     return;
@@ -325,7 +318,15 @@
   }
 #endif
   WmShell::Get()->RecordUserMetricsAction(UMA_ACCEL_SHUT_DOWN_POWER_BUTTON);
-  delegate_->RequestShutdown();
+
+  // Connect to the browser to tell it to shutdown the computer. It will either
+  // shut down or restart the computer based on the device settings.
+  //
+  // TODO(erg): Once CrosSettings has been moved out of chrome/,
+  // LockStateController should become a preference observer of it, and we
+  // should move the current content_browser implementation here.
+  // crbug.com/628792
+  shutdown_client_->RequestShutdown();
 }
 
 void LockStateController::StartCancellableShutdownAnimation() {
diff --git a/ash/wm/lock_state_controller.h b/ash/wm/lock_state_controller.h
index a3cdbe8..388558d 100644
--- a/ash/wm/lock_state_controller.h
+++ b/ash/wm/lock_state_controller.h
@@ -22,28 +22,25 @@
 class Size;
 }
 
+namespace service_manager {
+class Connector;
+}
+
 namespace ui {
 class Layer;
 }
 
 namespace ash {
 
-namespace test {
-class LockStateControllerTest;
-class PowerButtonControllerTest;
+namespace mojom {
+class ShutdownClient;
 }
 
-// Performs system-related functions on behalf of LockStateController.
-class ASH_EXPORT LockStateControllerDelegate {
- public:
-  LockStateControllerDelegate() {}
-  virtual ~LockStateControllerDelegate() {}
-
-  virtual void RequestShutdown() = 0;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(LockStateControllerDelegate);
-};
+namespace test {
+class LockStateControllerTest;
+class LockStateControllerTestApi;
+class PowerButtonControllerTest;
+}
 
 // Displays onscreen animations and locks or suspends the system in response to
 // the power button being pressed or released.
@@ -92,58 +89,9 @@
   // the animation time to finish.
   static const int kShutdownRequestDelayMs;
 
-  // Helper class used by tests to access internal state.
-  class ASH_EXPORT TestApi {
-   public:
-    explicit TestApi(LockStateController* controller);
-
-    virtual ~TestApi();
-
-    bool lock_fail_timer_is_running() const {
-      return controller_->lock_fail_timer_.IsRunning();
-    }
-    bool lock_to_shutdown_timer_is_running() const {
-      return controller_->lock_to_shutdown_timer_.IsRunning();
-    }
-    bool shutdown_timer_is_running() const {
-      return controller_->pre_shutdown_timer_.IsRunning();
-    }
-    bool real_shutdown_timer_is_running() const {
-      return controller_->real_shutdown_timer_.IsRunning();
-    }
-    bool is_animating_lock() const { return controller_->animating_lock_; }
-    bool is_lock_cancellable() const {
-      return controller_->CanCancelLockAnimation();
-    }
-
-    void trigger_lock_fail_timeout() {
-      controller_->OnLockFailTimeout();
-      controller_->lock_fail_timer_.Stop();
-    }
-    void trigger_lock_to_shutdown_timeout() {
-      controller_->OnLockToShutdownTimeout();
-      controller_->lock_to_shutdown_timer_.Stop();
-    }
-    void trigger_shutdown_timeout() {
-      controller_->OnPreShutdownAnimationTimeout();
-      controller_->pre_shutdown_timer_.Stop();
-    }
-    void trigger_real_shutdown_timeout() {
-      controller_->OnRealPowerTimeout();
-      controller_->real_shutdown_timer_.Stop();
-    }
-
-   private:
-    LockStateController* controller_;  // not owned
-
-    DISALLOW_COPY_AND_ASSIGN(TestApi);
-  };
-
-  LockStateController();
+  explicit LockStateController(service_manager::Connector* connector);
   ~LockStateController() override;
 
-  void SetDelegate(std::unique_ptr<LockStateControllerDelegate> delegate);
-
   // Starts locking (with slow animation) that can be cancelled.
   // After locking and |kLockToShutdownTimeoutMs| StartShutdownAnimation()
   // will be called unless CancelShutdownAnimation() is called, if
@@ -208,6 +156,7 @@
  private:
   friend class test::PowerButtonControllerTest;
   friend class test::LockStateControllerTest;
+  friend class test::LockStateControllerTestApi;
 
   struct UnlockedStateProperties {
     bool wallpaper_is_hidden;
@@ -274,8 +223,6 @@
 
   std::unique_ptr<SessionStateAnimator> animator_;
 
-  std::unique_ptr<LockStateControllerDelegate> delegate_;
-
   // The current login status, or original login status from before we locked.
   LoginStatus login_status_;
 
@@ -300,6 +247,9 @@
   // How long has it been since the request to lock the screen?
   std::unique_ptr<base::ElapsedTimer> lock_duration_timer_;
 
+  // The client that we request to shut down the machine.
+  std::unique_ptr<mojom::ShutdownClient> shutdown_client_;
+
   // Started when we request that the screen be locked.  When it fires, we
   // assume that our request got dropped.
   base::OneShotTimer lock_fail_timer_;
diff --git a/ash/wm/lock_state_controller_unittest.cc b/ash/wm/lock_state_controller_unittest.cc
index 3f1501f..2647952 100644
--- a/ash/wm/lock_state_controller_unittest.cc
+++ b/ash/wm/lock_state_controller_unittest.cc
@@ -13,10 +13,11 @@
 #include "ash/common/wm_shell.h"
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
-#include "ash/test/test_lock_state_controller_delegate.h"
+#include "ash/test/lock_state_controller_test_api.h"
 #include "ash/test/test_screenshot_delegate.h"
 #include "ash/test/test_session_state_animator.h"
 #include "ash/test/test_shell_delegate.h"
+#include "ash/test/test_shutdown_client.h"
 #include "ash/wm/power_button_controller.h"
 #include "ash/wm/session_state_animator.h"
 #include "base/memory/scoped_vector.h"
@@ -49,7 +50,7 @@
   LockStateControllerTest()
       : power_button_controller_(nullptr),
         lock_state_controller_(nullptr),
-        lock_state_controller_delegate_(nullptr),
+        shutdown_client_(nullptr),
         session_manager_client_(nullptr),
         test_animator_(nullptr) {}
   ~LockStateControllerTest() override {}
@@ -60,16 +61,16 @@
         base::WrapUnique(session_manager_client_));
     AshTestBase::SetUp();
 
-    std::unique_ptr<LockStateControllerDelegate> lock_state_controller_delegate(
-        lock_state_controller_delegate_ = new TestLockStateControllerDelegate);
+    shutdown_client_ = new TestShutdownClient;
+    std::unique_ptr<TestShutdownClient> shutdown_client(shutdown_client_);
+
     test_animator_ = new TestSessionStateAnimator;
 
     lock_state_controller_ = Shell::GetInstance()->lock_state_controller();
-    lock_state_controller_->SetDelegate(
-        std::move(lock_state_controller_delegate));
     lock_state_controller_->set_animator_for_test(test_animator_);
 
-    test_api_.reset(new LockStateController::TestApi(lock_state_controller_));
+    test_api_.reset(new LockStateControllerTestApi(lock_state_controller_));
+    test_api_->SetShutdownClient(std::move(shutdown_client));
 
     power_button_controller_ = Shell::GetInstance()->power_button_controller();
 
@@ -89,7 +90,7 @@
   }
 
   int NumShutdownRequests() {
-    return lock_state_controller_delegate_->num_shutdown_requests() +
+    return shutdown_client_->num_shutdown_requests() +
            shell_delegate_->num_exit_requests();
   }
 
@@ -326,12 +327,11 @@
 
   PowerButtonController* power_button_controller_;  // not owned
   LockStateController* lock_state_controller_;      // not owned
-  TestLockStateControllerDelegate*
-      lock_state_controller_delegate_;            // not owned
+  TestShutdownClient* shutdown_client_;             // not owned
   // Ownership is passed on to chromeos::DBusThreadManager.
   chromeos::FakeSessionManagerClient* session_manager_client_;
   TestSessionStateAnimator* test_animator_;       // not owned
-  std::unique_ptr<LockStateController::TestApi> test_api_;
+  std::unique_ptr<LockStateControllerTestApi> test_api_;
   TestShellDelegate* shell_delegate_;  // not owned
 
  private:
diff --git a/ash/wm/shutdown_client_proxy.cc b/ash/wm/shutdown_client_proxy.cc
new file mode 100644
index 0000000..316df3a4
--- /dev/null
+++ b/ash/wm/shutdown_client_proxy.cc
@@ -0,0 +1,23 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/wm/shutdown_client_proxy.h"
+
+#include "ash/public/interfaces/shutdown.mojom.h"
+#include "services/service_manager/public/cpp/connector.h"
+
+namespace ash {
+
+ShutdownClientProxy::ShutdownClientProxy(service_manager::Connector* connector)
+    : connector_(connector) {}
+
+ShutdownClientProxy::~ShutdownClientProxy() {}
+
+void ShutdownClientProxy::RequestShutdown() {
+  mojom::ShutdownClientPtr client;
+  connector_->ConnectToInterface("service:content_browser", &client);
+  client->RequestShutdown();
+}
+
+}  // namespace ash
diff --git a/ash/wm/shutdown_client_proxy.h b/ash/wm/shutdown_client_proxy.h
new file mode 100644
index 0000000..df5148a
--- /dev/null
+++ b/ash/wm/shutdown_client_proxy.h
@@ -0,0 +1,37 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_WM_SHUTDOWN_CLIENT_PROXY_H_
+#define ASH_WM_SHUTDOWN_CLIENT_PROXY_H_
+
+#include "ash/public/interfaces/shutdown.mojom.h"
+#include "base/macros.h"
+
+namespace service_manager {
+class Connector;
+}
+
+namespace ash {
+
+// A ShutdownClientProxy which lazily connects to an exported
+// mojom::ShutdownClient in "service:content_browser" on each use. This exists
+// so we can replace an instance of this class with a TestShutdownClient in
+// tests.
+class ShutdownClientProxy : public mojom::ShutdownClient {
+ public:
+  explicit ShutdownClientProxy(service_manager::Connector* connector);
+  ~ShutdownClientProxy() override;
+
+  // mojom::ShutdownClient:
+  void RequestShutdown() override;
+
+ private:
+  service_manager::Connector* connector_;
+
+  DISALLOW_COPY_AND_ASSIGN(ShutdownClientProxy);
+};
+
+}  // namespace ash
+
+#endif  // ASH_WM_SHUTDOWN_CLIENT_PROXY_H_
diff --git a/chrome/app/mash/chrome_mash_content_browser_manifest_overlay.json b/chrome/app/mash/chrome_mash_content_browser_manifest_overlay.json
index 67a4b3e..9801281 100644
--- a/chrome/app/mash/chrome_mash_content_browser_manifest_overlay.json
+++ b/chrome/app/mash/chrome_mash_content_browser_manifest_overlay.json
@@ -11,6 +11,7 @@
       "provides": {
         "content_browser:ash": [
           "ash::mojom::NewWindowClient",
+          "ash::mojom::ShutdownClient",
           "ash::mojom::SystemTrayClient",
           "ash::mojom::VolumeController",
           "ash::mojom::WallpaperManager",
diff --git a/chrome/browser/chrome_content_browser_manifest_overlay.json b/chrome/browser/chrome_content_browser_manifest_overlay.json
index 6ddd9ef..8f7fec4 100644
--- a/chrome/browser/chrome_content_browser_manifest_overlay.json
+++ b/chrome/browser/chrome_content_browser_manifest_overlay.json
@@ -20,6 +20,7 @@
           "ash::mojom::LocaleNotificationController",
           "ash::mojom::NewWindowClient",
           "ash::mojom::ShelfController",
+          "ash::mojom::ShutdownClient",
           "ash::mojom::SystemTray",
           "ash::mojom::SystemTrayClient",
           "ash::mojom::WallpaperController",
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 3ad7174..4983b80d 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -1098,8 +1098,8 @@
     "power/power_prefs.h",
     "power/renderer_freezer.cc",
     "power/renderer_freezer.h",
-    "power/session_state_controller_delegate_chromeos.cc",
-    "power/session_state_controller_delegate_chromeos.h",
+    "power/shutdown_client_impl.cc",
+    "power/shutdown_client_impl.h",
     "preferences.cc",
     "preferences.h",
     "printer_detector/printer_detector.cc",
diff --git a/chrome/browser/chromeos/chrome_interface_factory.cc b/chrome/browser/chromeos/chrome_interface_factory.cc
index 297acf4..7401321 100644
--- a/chrome/browser/chromeos/chrome_interface_factory.cc
+++ b/chrome/browser/chromeos/chrome_interface_factory.cc
@@ -5,15 +5,18 @@
 #include "chrome/browser/chromeos/chrome_interface_factory.h"
 
 #include <memory>
+#include <utility>
 
 #include "ash/common/mojo_interface_factory.h"
 #include "ash/public/interfaces/new_window.mojom.h"
+#include "ash/public/interfaces/shutdown.mojom.h"
 #include "base/lazy_instance.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/weak_ptr.h"
 #include "base/threading/thread_checker.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.h"
+#include "chrome/browser/chromeos/power/shutdown_client_impl.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/ash/app_list/app_list_presenter_service.h"
@@ -123,6 +126,13 @@
                                            std::move(request));
   }
 
+  void BindRequest(ash::mojom::ShutdownClientRequest request) {
+    if (!shutdown_client_)
+      shutdown_client_ = base::MakeUnique<ShutdownClientImpl>();
+    shutdown_client_bindings_.AddBinding(shutdown_client_.get(),
+                                         std::move(request));
+  }
+
   void BindRequest(ash::mojom::SystemTrayClientRequest request) {
     system_tray_client_bindings_.AddBinding(SystemTrayClient::Get(),
                                             std::move(request));
@@ -152,6 +162,8 @@
   std::unique_ptr<ChromeLaunchable> launchable_;
   std::unique_ptr<ChromeNewWindowClient> new_window_client_;
   mojo::BindingSet<ash::mojom::NewWindowClient> new_window_client_bindings_;
+  std::unique_ptr<ShutdownClientImpl> shutdown_client_;
+  mojo::BindingSet<ash::mojom::ShutdownClient> shutdown_client_bindings_;
   mojo::BindingSet<ash::mojom::SystemTrayClient> system_tray_client_bindings_;
   std::unique_ptr<VolumeController> volume_controller_;
   std::unique_ptr<AppListPresenterService> app_list_presenter_service_;
@@ -181,6 +193,8 @@
                                                    main_thread_task_runner_);
   FactoryImpl::AddFactory<ash::mojom::NewWindowClient>(
       registry, main_thread_task_runner_);
+  FactoryImpl::AddFactory<ash::mojom::ShutdownClient>(registry,
+                                                      main_thread_task_runner_);
   FactoryImpl::AddFactory<ash::mojom::SystemTrayClient>(
       registry, main_thread_task_runner_);
   FactoryImpl::AddFactory<ash::mojom::VolumeController>(
diff --git a/chrome/browser/chromeos/power/login_lock_state_notifier.cc b/chrome/browser/chromeos/power/login_lock_state_notifier.cc
index 63a0b9d5..1be0f74b 100644
--- a/chrome/browser/chromeos/power/login_lock_state_notifier.cc
+++ b/chrome/browser/chromeos/power/login_lock_state_notifier.cc
@@ -11,7 +11,6 @@
 #include "base/logging.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/chromeos/login/lock/screen_locker.h"
-#include "chrome/browser/chromeos/power/session_state_controller_delegate_chromeos.h"
 #include "content/public/browser/notification_service.h"
 
 namespace ash {
@@ -32,10 +31,6 @@
 }  // namespace
 
 LoginLockStateNotifier::LoginLockStateNotifier() {
-  ash::Shell::GetInstance()->lock_state_controller()->SetDelegate(
-      std::unique_ptr<ash::LockStateControllerDelegate>(
-          new SessionStateControllerDelegateChromeos));
-
   registrar_.Add(this, chrome::NOTIFICATION_LOGIN_USER_CHANGED,
                  content::NotificationService::AllSources());
   registrar_.Add(this, chrome::NOTIFICATION_APP_TERMINATING,
diff --git a/chrome/browser/chromeos/power/session_state_controller_delegate_chromeos.h b/chrome/browser/chromeos/power/session_state_controller_delegate_chromeos.h
deleted file mode 100644
index 1db21ef..0000000
--- a/chrome/browser/chromeos/power/session_state_controller_delegate_chromeos.h
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_CHROMEOS_POWER_SESSION_STATE_CONTROLLER_DELEGATE_CHROMEOS_H_
-#define CHROME_BROWSER_CHROMEOS_POWER_SESSION_STATE_CONTROLLER_DELEGATE_CHROMEOS_H_
-
-#include "ash/wm/lock_state_controller.h"
-#include "base/compiler_specific.h"
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-
-namespace chromeos {
-
-class SessionStateControllerDelegateChromeos
-    : public ash::LockStateControllerDelegate {
- public:
-  SessionStateControllerDelegateChromeos();
-  ~SessionStateControllerDelegateChromeos() override;
-
- private:
-  // ash::LockStateControllerDelegate implementation.
-  void RequestShutdown() override;
-
-  base::WeakPtrFactory<SessionStateControllerDelegateChromeos> weak_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(SessionStateControllerDelegateChromeos);
-};
-
-}  // namespace chromeos
-
-#endif  // CHROME_BROWSER_CHROMEOS_POWER_SESSION_STATE_CONTROLLER_DELEGATE_CHROMEOS_H_
diff --git a/chrome/browser/chromeos/power/session_state_controller_delegate_chromeos.cc b/chrome/browser/chromeos/power/shutdown_client_impl.cc
similarity index 69%
rename from chrome/browser/chromeos/power/session_state_controller_delegate_chromeos.cc
rename to chrome/browser/chromeos/power/shutdown_client_impl.cc
index 326f22e..9799557 100644
--- a/chrome/browser/chromeos/power/session_state_controller_delegate_chromeos.cc
+++ b/chrome/browser/chromeos/power/shutdown_client_impl.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/chromeos/power/session_state_controller_delegate_chromeos.h"
+#include "chrome/browser/chromeos/power/shutdown_client_impl.h"
 
 #include "base/logging.h"
 #include "chrome/browser/chromeos/settings/cros_settings.h"
@@ -13,20 +13,15 @@
 
 namespace chromeos {
 
-SessionStateControllerDelegateChromeos::SessionStateControllerDelegateChromeos()
-    : weak_factory_(this) {
-}
+ShutdownClientImpl::ShutdownClientImpl() : weak_factory_(this) {}
 
-SessionStateControllerDelegateChromeos::
-    ~SessionStateControllerDelegateChromeos() {
-}
+ShutdownClientImpl::~ShutdownClientImpl() {}
 
-void SessionStateControllerDelegateChromeos::RequestShutdown() {
+void ShutdownClientImpl::RequestShutdown() {
   CrosSettings* cros_settings = CrosSettings::Get();
   CrosSettingsProvider::TrustedStatus status =
       cros_settings->PrepareTrustedValues(base::Bind(
-          &SessionStateControllerDelegateChromeos::RequestShutdown,
-          weak_factory_.GetWeakPtr()));
+          &ShutdownClientImpl::RequestShutdown, weak_factory_.GetWeakPtr()));
   if (status != CrosSettingsProvider::TRUSTED)
     return;
 
diff --git a/chrome/browser/chromeos/power/shutdown_client_impl.h b/chrome/browser/chromeos/power/shutdown_client_impl.h
new file mode 100644
index 0000000..10d320ff
--- /dev/null
+++ b/chrome/browser/chromeos/power/shutdown_client_impl.h
@@ -0,0 +1,30 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_POWER_SHUTDOWN_CLIENT_IMPL_H_
+#define CHROME_BROWSER_CHROMEOS_POWER_SHUTDOWN_CLIENT_IMPL_H_
+
+#include "ash/public/interfaces/shutdown.mojom.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+
+namespace chromeos {
+
+class ShutdownClientImpl : public ash::mojom::ShutdownClient {
+ public:
+  ShutdownClientImpl();
+  ~ShutdownClientImpl() override;
+
+ private:
+  // ash::mojom::ShutdownClient implementation.
+  void RequestShutdown() override;
+
+  base::WeakPtrFactory<ShutdownClientImpl> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(ShutdownClientImpl);
+};
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_POWER_SHUTDOWN_CLIENT_IMPL_H_