typecd: Add session_manager proxy

Add a session_manager proxy implementation which can handle D-BUS
signals being generated by session-manager and call the relevant
functions on registered observers. Register this proxy on init
so that the daemon can receive session manager D-Bus signals.

BUG=b:171839508
TEST=cros deploy <DUT> typecd; verify that session state information and
lock screen updates are received by typecd using LOG prints.

Change-Id: I4b2a9d48d4af22a69e765c61668d58298d67dd97
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform2/+/2508220
Tested-by: Prashant Malani <pmalani@chromium.org>
Reviewed-by: Benson Leung <bleung@google.com>
Commit-Queue: Prashant Malani <pmalani@chromium.org>
diff --git a/typecd/BUILD.gn b/typecd/BUILD.gn
index a906df4..e7f628f 100644
--- a/typecd/BUILD.gn
+++ b/typecd/BUILD.gn
@@ -15,6 +15,7 @@
   pkg_deps = [
     "libbrillo",
     "libchrome",
+    "libsession_manager-client",
     "libudev",
     "re2",
   ]
@@ -38,6 +39,7 @@
     "peripheral.cc",
     "port.cc",
     "port_manager.cc",
+    "session_manager_proxy.cc",
     "udev_monitor.cc",
     "utils.cc",
   ]
diff --git a/typecd/daemon.cc b/typecd/daemon.cc
index c21c878..658523a 100644
--- a/typecd/daemon.cc
+++ b/typecd/daemon.cc
@@ -26,6 +26,12 @@
     return -1;
   }
 
+  // Register the session_manager proxy.
+  session_manager_proxy_ = std::make_unique<SessionManagerProxy>(bus_);
+
+  // TODO(b/171839508): Get the initial screen state at boot.
+  // TODO(b/171839508): Register the PortManager with |session_manager_proxy_|.
+
   // Add any observers to |udev_monitor_| here.
   udev_monitor_->AddObserver(port_manager_.get());
 
diff --git a/typecd/daemon.h b/typecd/daemon.h
index 4c91a18..c3b7838 100644
--- a/typecd/daemon.h
+++ b/typecd/daemon.h
@@ -11,6 +11,7 @@
 #include <brillo/daemons/dbus_daemon.h>
 
 #include "typecd/port_manager.h"
+#include "typecd/session_manager_proxy.h"
 #include "typecd/udev_monitor.h"
 
 namespace typecd {
@@ -29,6 +30,7 @@
  private:
   std::unique_ptr<UdevMonitor> udev_monitor_;
   std::unique_ptr<PortManager> port_manager_;
+  std::unique_ptr<SessionManagerProxy> session_manager_proxy_;
   base::WeakPtrFactory<Daemon> weak_factory_;
 };
 
diff --git a/typecd/session_manager_observer_interface.h b/typecd/session_manager_observer_interface.h
new file mode 100644
index 0000000..67916fb
--- /dev/null
+++ b/typecd/session_manager_observer_interface.h
@@ -0,0 +1,34 @@
+// Copyright 2020 The Chromium OS 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 TYPECD_SESSION_MANAGER_OBSERVER_INTERFACE_H_
+#define TYPECD_SESSION_MANAGER_OBSERVER_INTERFACE_H_
+
+#include "base/observer_list_types.h"
+
+namespace typecd {
+
+// An interface class for observing events from the session manager.
+// A derived class of this class should override the event methods
+// that it would like to observe.
+class SessionManagerObserverInterface : public base::CheckedObserver {
+ public:
+  virtual ~SessionManagerObserverInterface() = default;
+
+  // This method is called when the screen is locked.
+  virtual void OnScreenIsLocked() = 0;
+
+  // This method is called when the screen is unlocked.
+  virtual void OnScreenIsUnlocked() = 0;
+
+  // This method is called when a session has started.
+  virtual void OnSessionStarted() = 0;
+
+  // This method is called when a session has stopped.
+  virtual void OnSessionStopped() = 0;
+};
+
+}  // namespace typecd
+
+#endif  // TYPECD_SESSION_MANAGER_OBSERVER_INTERFACE_H_
diff --git a/typecd/session_manager_proxy.cc b/typecd/session_manager_proxy.cc
new file mode 100644
index 0000000..07b0b8a
--- /dev/null
+++ b/typecd/session_manager_proxy.cc
@@ -0,0 +1,66 @@
+// Copyright 2020 The Chromium OS 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 "typecd/session_manager_proxy.h"
+
+#include <base/bind.h>
+
+namespace typecd {
+
+namespace {
+
+void OnSignalConnected(const std::string& interface,
+                       const std::string& signal,
+                       bool success) {
+  if (!success) {
+    LOG(ERROR) << "Could not connect to signal " << signal << " on interface "
+               << interface;
+  }
+}
+
+}  // namespace
+
+SessionManagerProxy::SessionManagerProxy(scoped_refptr<dbus::Bus> bus)
+    : proxy_(bus), weak_ptr_factory_(this) {
+  proxy_.RegisterScreenIsLockedSignalHandler(
+      base::BindRepeating(&SessionManagerProxy::OnScreenIsLocked,
+                          weak_ptr_factory_.GetWeakPtr()),
+      base::BindOnce(&OnSignalConnected));
+  proxy_.RegisterScreenIsUnlockedSignalHandler(
+      base::BindRepeating(&SessionManagerProxy::OnScreenIsUnlocked,
+                          weak_ptr_factory_.GetWeakPtr()),
+      base::BindOnce(&OnSignalConnected));
+  proxy_.RegisterSessionStateChangedSignalHandler(
+      base::BindRepeating(&SessionManagerProxy::OnSessionStateChanged,
+                          weak_ptr_factory_.GetWeakPtr()),
+      base::BindOnce(&OnSignalConnected));
+}
+
+void SessionManagerProxy::AddObserver(
+    SessionManagerObserverInterface* observer) {
+  CHECK(observer) << "Invalid observer object";
+  observer_list_.AddObserver(observer);
+}
+
+void SessionManagerProxy::OnScreenIsLocked() {
+  for (SessionManagerObserverInterface& observer : observer_list_)
+    observer.OnScreenIsLocked();
+}
+
+void SessionManagerProxy::OnScreenIsUnlocked() {
+  for (SessionManagerObserverInterface& observer : observer_list_)
+    observer.OnScreenIsUnlocked();
+}
+
+void SessionManagerProxy::OnSessionStateChanged(const std::string& state) {
+  if (state == "started") {
+    for (SessionManagerObserverInterface& observer : observer_list_)
+      observer.OnSessionStarted();
+  } else if (state == "stopped") {
+    for (SessionManagerObserverInterface& observer : observer_list_)
+      observer.OnSessionStopped();
+  }
+}
+
+}  // namespace typecd
diff --git a/typecd/session_manager_proxy.h b/typecd/session_manager_proxy.h
new file mode 100644
index 0000000..9f07c44
--- /dev/null
+++ b/typecd/session_manager_proxy.h
@@ -0,0 +1,49 @@
+// Copyright 2020 The Chromium OS 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 TYPECD_SESSION_MANAGER_PROXY_H_
+#define TYPECD_SESSION_MANAGER_PROXY_H_
+
+#include <string>
+
+#include <base/memory/ref_counted.h>
+#include <base/memory/weak_ptr.h>
+#include <base/observer_list.h>
+#include <dbus/bus.h>
+#include <session_manager/dbus-proxies.h>
+
+#include "typecd/session_manager_observer_interface.h"
+
+namespace typecd {
+
+// A proxy class that listens to DBus signals from the session manager and
+// notifies a list of registered observers for events.
+class SessionManagerProxy {
+ public:
+  explicit SessionManagerProxy(scoped_refptr<dbus::Bus> bus);
+
+  ~SessionManagerProxy() = default;
+
+  void AddObserver(SessionManagerObserverInterface* observer);
+
+ private:
+  // Handles the ScreenIsLocked DBus signal.
+  void OnScreenIsLocked();
+
+  // Handles the ScreenIsUnlocked DBus signal.
+  void OnScreenIsUnlocked();
+
+  // Handles the SessionStateChanged DBus signal.
+  void OnSessionStateChanged(const std::string& state);
+
+  org::chromium::SessionManagerInterfaceProxy proxy_;
+  base::ObserverList<SessionManagerObserverInterface> observer_list_;
+  base::WeakPtrFactory<SessionManagerProxy> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(SessionManagerProxy);
+};
+
+}  // namespace typecd
+
+#endif  // TYPECD_SESSION_MANAGER_PROXY_H_