Refactor ozone DrmDisplayHostManager for pluggable messaging

Modify DrmDisplayHostManager in Ozone so that messaging can be be
dynamically configured as IPC or thread-hop as will be needed
by MUS.

BUG=558602

Review URL: https://codereview.chromium.org/1587503002

Cr-Commit-Position: refs/heads/master@{#369568}
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index 4755771e..c89fbfa2 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -178,7 +178,7 @@
         r"^net[\\\/]url_request[\\\/]test_url_fetcher_factory\.cc$",
         r"^remoting[\\\/]host[\\\/]gnubby_auth_handler_posix\.cc$",
         r"^ui[\\\/]ozone[\\\/]platform[\\\/]drm[\\\/]host[\\\/]"
-            "drm_display_host_manager\.cc$",
+            "drm_display_host_manager_core\.cc$",
       ),
     ),
     (
diff --git a/ui/ozone/platform/drm/BUILD.gn b/ui/ozone/platform/drm/BUILD.gn
index a3bbbd22..6758a88 100644
--- a/ui/ozone/platform/drm/BUILD.gn
+++ b/ui/ozone/platform/drm/BUILD.gn
@@ -98,6 +98,8 @@
     "host/drm_display_host.h",
     "host/drm_display_host_manager.cc",
     "host/drm_display_host_manager.h",
+    "host/drm_display_host_manager_core.cc",
+    "host/drm_display_host_manager_core.h",
     "host/drm_gpu_platform_support_host.cc",
     "host/drm_gpu_platform_support_host.h",
     "host/drm_native_display_delegate.cc",
diff --git a/ui/ozone/platform/drm/gbm.gypi b/ui/ozone/platform/drm/gbm.gypi
index 3a73d9e..26c7029 100644
--- a/ui/ozone/platform/drm/gbm.gypi
+++ b/ui/ozone/platform/drm/gbm.gypi
@@ -82,7 +82,7 @@
         'gpu/drm_gpu_platform_support.cc',
         'gpu/drm_gpu_platform_support.h',
         'gpu/drm_overlay_validator.cc',
-	'gpu/drm_overlay_validator.h',
+        'gpu/drm_overlay_validator.h',
         'gpu/drm_thread.cc',
         'gpu/drm_thread.h',
         'gpu/drm_thread_message_proxy.cc',
@@ -132,6 +132,8 @@
         'host/drm_display_host.h',
         'host/drm_display_host_manager.cc',
         'host/drm_display_host_manager.h',
+        'host/drm_display_host_manager_core.cc',
+        'host/drm_display_host_manager_core.h',
         'host/drm_gpu_platform_support_host.cc',
         'host/drm_gpu_platform_support_host.h',
         'host/drm_native_display_delegate.cc',
diff --git a/ui/ozone/platform/drm/host/drm_display_host_manager.cc b/ui/ozone/platform/drm/host/drm_display_host_manager.cc
index 752da4c..ba43cdc 100644
--- a/ui/ozone/platform/drm/host/drm_display_host_manager.cc
+++ b/ui/ozone/platform/drm/host/drm_display_host_manager.cc
@@ -4,379 +4,59 @@
 
 #include "ui/ozone/platform/drm/host/drm_display_host_manager.h"
 
-#include <fcntl.h>
-#include <stddef.h>
-#include <xf86drm.h>
-#include <utility>
-
-#include "base/files/file_enumerator.h"
-#include "base/files/file_util.h"
 #include "base/thread_task_runner_handle.h"
-#include "base/threading/thread_restrictions.h"
-#include "base/threading/worker_pool.h"
-#include "ui/display/types/display_snapshot.h"
-#include "ui/events/ozone/device/device_event.h"
-#include "ui/events/ozone/device/device_manager.h"
-#include "ui/ozone/common/display_util.h"
 #include "ui/ozone/common/gpu/ozone_gpu_messages.h"
-#include "ui/ozone/platform/drm/common/drm_util.h"
-#include "ui/ozone/platform/drm/host/drm_device_handle.h"
 #include "ui/ozone/platform/drm/host/drm_display_host.h"
 #include "ui/ozone/platform/drm/host/drm_gpu_platform_support_host.h"
 #include "ui/ozone/platform/drm/host/drm_native_display_delegate.h"
 
 namespace ui {
 
-namespace {
-
-typedef base::Callback<void(const base::FilePath&,
-                            const base::FilePath&,
-                            scoped_ptr<DrmDeviceHandle>)>
-    OnOpenDeviceReplyCallback;
-
-const char kDefaultGraphicsCardPattern[] = "/dev/dri/card%d";
-const char kVgemDevDriCardPath[] = "/dev/dri/";
-const char kVgemSysCardPath[] = "/sys/bus/platform/devices/vgem/drm/";
-
-const char* kDisplayActionString[] = {
-    "ADD",
-    "REMOVE",
-    "CHANGE",
-};
-
-// Find sysfs device path for the given device path.
-base::FilePath MapDevPathToSysPath(const base::FilePath& device_path) {
-  // |device_path| looks something like /dev/dri/card0. We take the basename of
-  // that (card0) and append it to /sys/class/drm. /sys/class/drm/card0 is a
-  // symlink that points to something like
-  // /sys/devices/pci0000:00/0000:00:02.0/0000:05:00.0/drm/card0, which exposes
-  // some metadata about the attached device.
-  return base::MakeAbsoluteFilePath(
-      base::FilePath("/sys/class/drm").Append(device_path.BaseName()));
-}
-
-void OpenDeviceOnWorkerThread(
-    const base::FilePath& device_path,
-    const scoped_refptr<base::TaskRunner>& reply_runner,
-    const OnOpenDeviceReplyCallback& callback) {
-  base::FilePath sys_path = MapDevPathToSysPath(device_path);
-
-  scoped_ptr<DrmDeviceHandle> handle(new DrmDeviceHandle());
-  handle->Initialize(device_path, sys_path);
-  reply_runner->PostTask(FROM_HERE,
-                         base::Bind(callback, device_path, sys_path,
-                                    base::Passed(std::move(handle))));
-}
-
-base::FilePath GetPrimaryDisplayCardPath() {
-  struct drm_mode_card_res res;
-  for (int i = 0; /* end on first card# that does not exist */; i++) {
-    std::string card_path = base::StringPrintf(kDefaultGraphicsCardPattern, i);
-
-    if (access(card_path.c_str(), F_OK) != 0)
-      break;
-
-    int fd = open(card_path.c_str(), O_RDWR | O_CLOEXEC);
-    if (fd < 0) {
-      VPLOG(1) << "Failed to open '" << card_path << "'";
-      continue;
-    }
-
-    memset(&res, 0, sizeof(struct drm_mode_card_res));
-    int ret = drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res);
-    close(fd);
-    if (ret == 0 && res.count_crtcs > 0) {
-      return base::FilePath(card_path);
-    }
-
-    VPLOG_IF(1, ret) << "Failed to get DRM resources for '" << card_path << "'";
-  }
-
-  LOG(FATAL) << "Failed to open primary graphics device.";
-  return base::FilePath();  // Not reached.
-}
-
-base::FilePath GetVgemCardPath() {
-  base::FileEnumerator file_iter(base::FilePath(kVgemSysCardPath), false,
-                                 base::FileEnumerator::DIRECTORIES,
-                                 FILE_PATH_LITERAL("card*"));
-
-  while (!file_iter.Next().empty()) {
-    // Inspect the card%d directories in the directory and extract the filename.
-    std::string vgem_card_path =
-        kVgemDevDriCardPath + file_iter.GetInfo().GetName().BaseName().value();
-    DVLOG(1) << "VGEM card path is " << vgem_card_path;
-    return base::FilePath(vgem_card_path);
-  }
-  DVLOG(1) << "Don't support VGEM";
-  return base::FilePath();
-}
-
-class FindDrmDisplayHostById {
- public:
-  explicit FindDrmDisplayHostById(int64_t display_id)
-      : display_id_(display_id) {}
-
-  bool operator()(const scoped_ptr<DrmDisplayHost>& display) const {
-    return display->snapshot()->display_id() == display_id_;
-  }
-
- private:
-  int64_t display_id_;
-};
-
-}  // namespace
-
 DrmDisplayHostManager::DrmDisplayHostManager(
     DrmGpuPlatformSupportHost* proxy,
     DeviceManager* device_manager,
     InputControllerEvdev* input_controller)
-    : proxy_(proxy),
-      device_manager_(device_manager),
-      input_controller_(input_controller),
-      primary_graphics_card_path_(GetPrimaryDisplayCardPath()),
-      weak_ptr_factory_(this) {
-  {
-    // First device needs to be treated specially. We need to open this
-    // synchronously since the GPU process will need it to initialize the
-    // graphics state.
-    base::ThreadRestrictions::ScopedAllowIO allow_io;
-
-    base::FilePath primary_graphics_card_path_sysfs =
-        MapDevPathToSysPath(primary_graphics_card_path_);
-
-    primary_drm_device_handle_.reset(new DrmDeviceHandle());
-    if (!primary_drm_device_handle_->Initialize(
-            primary_graphics_card_path_, primary_graphics_card_path_sysfs)) {
-      LOG(FATAL) << "Failed to open primary graphics card";
-      return;
-    }
-    drm_devices_[primary_graphics_card_path_] =
-        primary_graphics_card_path_sysfs;
-
-    vgem_card_path_ = GetVgemCardPath();
-  }
-
-  device_manager_->AddObserver(this);
-  proxy_->RegisterHandler(this);
-
-  ScopedVector<HardwareDisplayControllerInfo> display_infos =
-      GetAvailableDisplayControllerInfos(primary_drm_device_handle_->fd());
-  has_dummy_display_ = !display_infos.empty();
-  for (size_t i = 0; i < display_infos.size(); ++i) {
-    displays_.push_back(make_scoped_ptr(new DrmDisplayHost(
-        proxy_, CreateDisplaySnapshotParams(
-                    display_infos[i], primary_drm_device_handle_->fd(),
-                    primary_drm_device_handle_->sys_path(), 0, gfx::Point()),
-        true /* is_dummy */)));
-  }
-}
+    : sender_(new HostManagerIPC(proxy, this)),
+      core_(new DrmDisplayHostManagerCore(sender_.get(),
+                                          device_manager,
+                                          input_controller)) {}
 
 DrmDisplayHostManager::~DrmDisplayHostManager() {
-  device_manager_->RemoveObserver(this);
-  proxy_->UnregisterHandler(this);
 }
 
 DrmDisplayHost* DrmDisplayHostManager::GetDisplay(int64_t display_id) {
-  auto it = std::find_if(displays_.begin(), displays_.end(),
-                         FindDrmDisplayHostById(display_id));
-  if (it == displays_.end())
-    return nullptr;
-
-  return it->get();
+  return core_->GetDisplay(display_id);
 }
 
 void DrmDisplayHostManager::AddDelegate(DrmNativeDisplayDelegate* delegate) {
-  DCHECK(!delegate_);
-  delegate_ = delegate;
+  core_->AddDelegate(delegate);
 }
 
 void DrmDisplayHostManager::RemoveDelegate(DrmNativeDisplayDelegate* delegate) {
-  DCHECK_EQ(delegate_, delegate);
-  delegate_ = nullptr;
+  core_->RemoveDelegate(delegate);
 }
 
 void DrmDisplayHostManager::TakeDisplayControl(
     const DisplayControlCallback& callback) {
-  if (display_control_change_pending_) {
-    LOG(ERROR) << "TakeDisplayControl called while change already pending";
-    callback.Run(false);
-    return;
-  }
-
-  if (!display_externally_controlled_) {
-    LOG(ERROR) << "TakeDisplayControl called while display already owned";
-    callback.Run(true);
-    return;
-  }
-
-  take_display_control_callback_ = callback;
-  display_control_change_pending_ = true;
-
-  if (!proxy_->Send(new OzoneGpuMsg_TakeDisplayControl()))
-    OnTakeDisplayControl(false);
+  core_->TakeDisplayControl(callback);
 }
 
 void DrmDisplayHostManager::RelinquishDisplayControl(
     const DisplayControlCallback& callback) {
-  if (display_control_change_pending_) {
-    LOG(ERROR)
-        << "RelinquishDisplayControl called while change already pending";
-    callback.Run(false);
-    return;
-  }
-
-  if (display_externally_controlled_) {
-    LOG(ERROR) << "RelinquishDisplayControl called while display not owned";
-    callback.Run(true);
-    return;
-  }
-
-  relinquish_display_control_callback_ = callback;
-  display_control_change_pending_ = true;
-
-  if (!proxy_->Send(new OzoneGpuMsg_RelinquishDisplayControl()))
-    OnRelinquishDisplayControl(false);
+  core_->RelinquishDisplayControl(callback);
 }
 
 void DrmDisplayHostManager::UpdateDisplays(
     const GetDisplaysCallback& callback) {
-  get_displays_callback_ = callback;
-  if (!proxy_->Send(new OzoneGpuMsg_RefreshNativeDisplays())) {
-    get_displays_callback_.Reset();
-    RunUpdateDisplaysCallback(callback);
-  }
-}
-
-void DrmDisplayHostManager::OnDeviceEvent(const DeviceEvent& event) {
-  if (event.device_type() != DeviceEvent::DISPLAY)
-    return;
-
-  event_queue_.push(DisplayEvent(event.action_type(), event.path()));
-  ProcessEvent();
-}
-
-void DrmDisplayHostManager::ProcessEvent() {
-  while (!event_queue_.empty() && !task_pending_) {
-    DisplayEvent event = event_queue_.front();
-    event_queue_.pop();
-    VLOG(1) << "Got display event " << kDisplayActionString[event.action_type]
-            << " for " << event.path.value();
-    switch (event.action_type) {
-      case DeviceEvent::ADD:
-        if (event.path == vgem_card_path_)
-          continue;
-        if (drm_devices_.find(event.path) == drm_devices_.end()) {
-          task_pending_ = base::WorkerPool::PostTask(
-              FROM_HERE,
-              base::Bind(&OpenDeviceOnWorkerThread, event.path,
-                         base::ThreadTaskRunnerHandle::Get(),
-                         base::Bind(&DrmDisplayHostManager::OnAddGraphicsDevice,
-                                    weak_ptr_factory_.GetWeakPtr())),
-              false /* task_is_slow */);
-        }
-        break;
-      case DeviceEvent::CHANGE:
-        task_pending_ = base::ThreadTaskRunnerHandle::Get()->PostTask(
-            FROM_HERE,
-            base::Bind(&DrmDisplayHostManager::OnUpdateGraphicsDevice,
-                       weak_ptr_factory_.GetWeakPtr()));
-        break;
-      case DeviceEvent::REMOVE:
-        DCHECK(event.path != primary_graphics_card_path_)
-            << "Removing primary graphics card";
-        DCHECK(event.path != vgem_card_path_) << "Removing VGEM device";
-        auto it = drm_devices_.find(event.path);
-        if (it != drm_devices_.end()) {
-          task_pending_ = base::ThreadTaskRunnerHandle::Get()->PostTask(
-              FROM_HERE,
-              base::Bind(&DrmDisplayHostManager::OnRemoveGraphicsDevice,
-                         weak_ptr_factory_.GetWeakPtr(), it->second));
-          drm_devices_.erase(it);
-        }
-        break;
-    }
-  }
-}
-
-void DrmDisplayHostManager::OnAddGraphicsDevice(
-    const base::FilePath& dev_path,
-    const base::FilePath& sys_path,
-    scoped_ptr<DrmDeviceHandle> handle) {
-  if (handle->IsValid()) {
-    drm_devices_[dev_path] = sys_path;
-    proxy_->Send(new OzoneGpuMsg_AddGraphicsDevice(
-        sys_path, base::FileDescriptor(handle->PassFD())));
-    NotifyDisplayDelegate();
-  }
-
-  task_pending_ = false;
-  ProcessEvent();
-}
-
-void DrmDisplayHostManager::OnUpdateGraphicsDevice() {
-  NotifyDisplayDelegate();
-  task_pending_ = false;
-  ProcessEvent();
-}
-
-void DrmDisplayHostManager::OnRemoveGraphicsDevice(
-    const base::FilePath& sys_path) {
-  proxy_->Send(new OzoneGpuMsg_RemoveGraphicsDevice(sys_path));
-  NotifyDisplayDelegate();
-  task_pending_ = false;
-  ProcessEvent();
+  core_->UpdateDisplays(callback);
 }
 
 void DrmDisplayHostManager::OnChannelEstablished(
     int host_id,
     scoped_refptr<base::SingleThreadTaskRunner> send_runner,
     const base::Callback<void(IPC::Message*)>& send_callback) {
-  // If in the middle of a configuration, just respond with the old list of
-  // displays. This is fine, since after the DRM resources are initialized and
-  // IPC-ed to the GPU NotifyDisplayDelegate() is called to let the display
-  // delegate know that the display configuration changed and it needs to
-  // update it again.
-  if (!get_displays_callback_.is_null()) {
-    base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE,
-        base::Bind(&DrmDisplayHostManager::RunUpdateDisplaysCallback,
-                   weak_ptr_factory_.GetWeakPtr(), get_displays_callback_));
-    get_displays_callback_.Reset();
-  }
-
-  // Signal that we're taking DRM master since we're going through the
-  // initialization process again and we'll take all the available resources.
-  if (!take_display_control_callback_.is_null())
-    OnTakeDisplayControl(true);
-
-  if (!relinquish_display_control_callback_.is_null())
-    OnRelinquishDisplayControl(false);
-
-  scoped_ptr<DrmDeviceHandle> handle = std::move(primary_drm_device_handle_);
-  {
-    base::ThreadRestrictions::ScopedAllowIO allow_io;
-
-    drm_devices_.clear();
-    drm_devices_[primary_graphics_card_path_] =
-        MapDevPathToSysPath(primary_graphics_card_path_);
-
-    if (!handle) {
-      handle.reset(new DrmDeviceHandle());
-      if (!handle->Initialize(primary_graphics_card_path_,
-                              drm_devices_[primary_graphics_card_path_]))
-        LOG(FATAL) << "Failed to open primary graphics card";
-    }
-  }
-
-  // Send the primary device first since this is used to initialize graphics
-  // state.
-  proxy_->Send(new OzoneGpuMsg_AddGraphicsDevice(
-      drm_devices_[primary_graphics_card_path_],
-      base::FileDescriptor(handle->PassFD())));
-
-  device_manager_->ScanDevices(this);
-  NotifyDisplayDelegate();
+  // The GPU thread may be in a different or the same process.
+  core_->GpuThreadStarted();
 }
 
 void DrmDisplayHostManager::OnChannelDestroyed(int host_id) {
@@ -401,110 +81,72 @@
 
 void DrmDisplayHostManager::OnUpdateNativeDisplays(
     const std::vector<DisplaySnapshot_Params>& params) {
-  std::vector<scoped_ptr<DrmDisplayHost>> old_displays;
-  displays_.swap(old_displays);
-  for (size_t i = 0; i < params.size(); ++i) {
-    auto it = std::find_if(old_displays.begin(), old_displays.end(),
-                           FindDrmDisplayHostById(params[i].display_id));
-    if (it == old_displays.end()) {
-      displays_.push_back(make_scoped_ptr(
-          new DrmDisplayHost(proxy_, params[i], false /* is_dummy */)));
-    } else {
-      (*it)->UpdateDisplaySnapshot(params[i]);
-      displays_.push_back(std::move(*it));
-      old_displays.erase(it);
-    }
-  }
-
-  if (!get_displays_callback_.is_null()) {
-    base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE,
-        base::Bind(&DrmDisplayHostManager::RunUpdateDisplaysCallback,
-                   weak_ptr_factory_.GetWeakPtr(), get_displays_callback_));
-    get_displays_callback_.Reset();
-  }
+  core_->GpuHasUpdatedNativeDisplays(params);
 }
 
 void DrmDisplayHostManager::OnDisplayConfigured(int64_t display_id,
                                                 bool status) {
-  DrmDisplayHost* display = GetDisplay(display_id);
-  if (display)
-    display->OnDisplayConfigured(status);
-  else
-    LOG(ERROR) << "Couldn't find display with id=" << display_id;
+  core_->GpuConfiguredDisplay(display_id, status);
 }
 
 void DrmDisplayHostManager::OnHDCPStateReceived(int64_t display_id,
                                                 bool status,
                                                 HDCPState state) {
-  DrmDisplayHost* display = GetDisplay(display_id);
-  if (display)
-    display->OnHDCPStateReceived(status, state);
-  else
-    LOG(ERROR) << "Couldn't find display with id=" << display_id;
+  core_->GpuReceivedHDCPState(display_id, status, state);
 }
 
 void DrmDisplayHostManager::OnHDCPStateUpdated(int64_t display_id,
                                                bool status) {
-  DrmDisplayHost* display = GetDisplay(display_id);
-  if (display)
-    display->OnHDCPStateUpdated(status);
-  else
-    LOG(ERROR) << "Couldn't find display with id=" << display_id;
+  core_->GpuUpdatedHDCPState(display_id, status);
 }
 
 void DrmDisplayHostManager::OnTakeDisplayControl(bool status) {
-  if (take_display_control_callback_.is_null()) {
-    LOG(ERROR) << "No callback for take display control";
-    return;
-  }
-
-  DCHECK(display_externally_controlled_);
-  DCHECK(display_control_change_pending_);
-
-  if (status) {
-    input_controller_->SetInputDevicesEnabled(true);
-    display_externally_controlled_ = false;
-  }
-
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::Bind(take_display_control_callback_, status));
-  take_display_control_callback_.Reset();
-  display_control_change_pending_ = false;
+  core_->GpuTookDisplayControl(status);
 }
 
 void DrmDisplayHostManager::OnRelinquishDisplayControl(bool status) {
-  if (relinquish_display_control_callback_.is_null()) {
-    LOG(ERROR) << "No callback for relinquish display control";
-    return;
-  }
-
-  DCHECK(!display_externally_controlled_);
-  DCHECK(display_control_change_pending_);
-
-  if (status) {
-    input_controller_->SetInputDevicesEnabled(false);
-    display_externally_controlled_ = true;
-  }
-
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::Bind(relinquish_display_control_callback_, status));
-  relinquish_display_control_callback_.Reset();
-  display_control_change_pending_ = false;
+  core_->GpuRelinquishedDisplayControl(status);
 }
 
-void DrmDisplayHostManager::RunUpdateDisplaysCallback(
-    const GetDisplaysCallback& callback) const {
-  std::vector<DisplaySnapshot*> snapshots;
-  for (const auto& display : displays_)
-    snapshots.push_back(display->snapshot());
+DrmDisplayHostManager::HostManagerIPC::HostManagerIPC(
+    DrmGpuPlatformSupportHost* proxy,
+    DrmDisplayHostManager* parent)
+    : proxy_(proxy), parent_(parent) {}
 
-  callback.Run(snapshots);
+DrmDisplayHostManager::HostManagerIPC::~HostManagerIPC() {
+  proxy_->UnregisterHandler(parent_);
 }
 
-void DrmDisplayHostManager::NotifyDisplayDelegate() const {
-  if (delegate_)
-    delegate_->OnConfigurationChanged();
+void DrmDisplayHostManager::HostManagerIPC::RegisterHandler() {
+  proxy_->RegisterHandler(parent_);
+}
+
+DrmGpuPlatformSupportHost*
+DrmDisplayHostManager::HostManagerIPC::GetGpuPlatformSupportHost() {
+  return proxy_;
+}
+
+bool DrmDisplayHostManager::HostManagerIPC::RefreshNativeDisplays() {
+  return proxy_->Send(new OzoneGpuMsg_RefreshNativeDisplays());
+}
+
+bool DrmDisplayHostManager::HostManagerIPC::TakeDisplayControl() {
+  return proxy_->Send(new OzoneGpuMsg_TakeDisplayControl());
+}
+
+bool DrmDisplayHostManager::HostManagerIPC::RelinquishDisplayControl() {
+  return proxy_->Send(new OzoneGpuMsg_RelinquishDisplayControl());
+}
+
+bool DrmDisplayHostManager::HostManagerIPC::AddGraphicsDevice(
+    const base::FilePath& path,
+    base::FileDescriptor fd) {
+  return proxy_->Send(new OzoneGpuMsg_AddGraphicsDevice(path, fd));
+}
+
+bool DrmDisplayHostManager::HostManagerIPC::RemoveGraphicsDevice(
+    const base::FilePath& path) {
+  return proxy_->Send(new OzoneGpuMsg_RemoveGraphicsDevice(path));
 }
 
 }  // namespace ui
diff --git a/ui/ozone/platform/drm/host/drm_display_host_manager.h b/ui/ozone/platform/drm/host/drm_display_host_manager.h
index f1481b7..1079e19 100644
--- a/ui/ozone/platform/drm/host/drm_display_host_manager.h
+++ b/ui/ozone/platform/drm/host/drm_display_host_manager.h
@@ -7,31 +7,21 @@
 
 #include <stdint.h>
 
-#include <map>
-#include <queue>
-
-#include "base/files/scoped_file.h"
-#include "base/macros.h"
-#include "base/memory/scoped_vector.h"
-#include "base/memory/weak_ptr.h"
+#include "base/memory/scoped_ptr.h"
 #include "ui/display/types/native_display_delegate.h"
-#include "ui/events/ozone/device/device_event.h"
-#include "ui/events/ozone/device/device_event_observer.h"
-#include "ui/events/ozone/evdev/event_factory_evdev.h"
+#include "ui/ozone/platform/drm/host/drm_display_host_manager_core.h"
 #include "ui/ozone/public/gpu_platform_support_host.h"
 
 namespace ui {
 
 class DeviceManager;
-class DrmDeviceHandle;
 class DrmDisplayHost;
 class DrmGpuPlatformSupportHost;
 class DrmNativeDisplayDelegate;
 
 struct DisplaySnapshot_Params;
 
-class DrmDisplayHostManager : public DeviceEventObserver,
-                              public GpuPlatformSupportHost {
+class DrmDisplayHostManager : public GpuPlatformSupportHost {
  public:
   DrmDisplayHostManager(DrmGpuPlatformSupportHost* proxy,
                         DeviceManager* device_manager,
@@ -39,7 +29,6 @@
   ~DrmDisplayHostManager() override;
 
   DrmDisplayHost* GetDisplay(int64_t display_id);
-
   void AddDelegate(DrmNativeDisplayDelegate* delegate);
   void RemoveDelegate(DrmNativeDisplayDelegate* delegate);
 
@@ -47,98 +36,53 @@
   void RelinquishDisplayControl(const DisplayControlCallback& callback);
   void UpdateDisplays(const GetDisplaysCallback& callback);
 
-  // DeviceEventObserver overrides:
-  void OnDeviceEvent(const DeviceEvent& event) override;
-
-  // GpuPlatformSupportHost:
+  // IPC::Listener (by way of GpuPlatformSupportHost) overrides:
   void OnChannelEstablished(
       int host_id,
       scoped_refptr<base::SingleThreadTaskRunner> send_runner,
       const base::Callback<void(IPC::Message*)>& send_callback) override;
   void OnChannelDestroyed(int host_id) override;
-
-  // IPC::Listener overrides:
   bool OnMessageReceived(const IPC::Message& message) override;
 
  private:
-  struct DisplayEvent {
-    DisplayEvent(DeviceEvent::ActionType action_type,
-                 const base::FilePath& path)
-        : action_type(action_type), path(path) {}
+  // Concrete implementation of sending messages to the GPU thread hosted
+  // functionality.
+  class HostManagerIPC : public DrmDisplayHostManagerProxy {
+   public:
+    HostManagerIPC(DrmGpuPlatformSupportHost* proxy,
+                   DrmDisplayHostManager* parent);
+    ~HostManagerIPC() override;
 
-    DeviceEvent::ActionType action_type;
-    base::FilePath path;
+    void RegisterHandler() override;
+    DrmGpuPlatformSupportHost* GetGpuPlatformSupportHost() override;
+    bool TakeDisplayControl() override;
+    bool RefreshNativeDisplays() override;
+    bool RelinquishDisplayControl() override;
+    bool AddGraphicsDevice(const base::FilePath& path,
+                           base::FileDescriptor fd) override;
+    bool RemoveGraphicsDevice(const base::FilePath& path) override;
+
+   private:
+    DrmGpuPlatformSupportHost* proxy_;
+    DrmDisplayHostManager* parent_;
+
+    DISALLOW_COPY_AND_ASSIGN(HostManagerIPC);
   };
 
+  // IPC Entry points.
   void OnUpdateNativeDisplays(
       const std::vector<DisplaySnapshot_Params>& displays);
   void OnDisplayConfigured(int64_t display_id, bool status);
-
-  void ProcessEvent();
-
-  // Called as a result of finishing to process the display hotplug event. These
-  // are responsible for dequing the event and scheduling the next event.
-  void OnAddGraphicsDevice(const base::FilePath& path,
-                           const base::FilePath& sysfs_path,
-                           scoped_ptr<DrmDeviceHandle> handle);
-  void OnUpdateGraphicsDevice();
-  void OnRemoveGraphicsDevice(const base::FilePath& path);
-
   void OnHDCPStateReceived(int64_t display_id, bool status, HDCPState state);
   void OnHDCPStateUpdated(int64_t display_id, bool status);
-
   void OnTakeDisplayControl(bool status);
   void OnRelinquishDisplayControl(bool status);
 
-  void RunUpdateDisplaysCallback(const GetDisplaysCallback& callback) const;
+  // Sends messages to the GPU thread.
+  scoped_ptr<HostManagerIPC> sender_;
 
-  void NotifyDisplayDelegate() const;
-
-  DrmGpuPlatformSupportHost* proxy_;  // Not owned.
-  DeviceManager* device_manager_;     // Not owned.
-  InputControllerEvdev* input_controller_;  // Not owned.
-
-  DrmNativeDisplayDelegate* delegate_ = nullptr;  // Not owned.
-
-  // File path for the primary graphics card which is opened by default in the
-  // GPU process. We'll avoid opening this in hotplug events since it will race
-  // with the GPU process trying to open it and aquire DRM master.
-  base::FilePath primary_graphics_card_path_;
-
-  // File path for virtual gem (VGEM) device.
-  base::FilePath vgem_card_path_;
-
-  // Keeps track if there is a dummy display. This happens on initialization
-  // when there is no connection to the GPU to update the displays.
-  bool has_dummy_display_ = false;
-
-  std::vector<scoped_ptr<DrmDisplayHost>> displays_;
-
-  GetDisplaysCallback get_displays_callback_;
-
-  bool display_externally_controlled_ = false;
-  bool display_control_change_pending_ = false;
-  DisplayControlCallback take_display_control_callback_;
-  DisplayControlCallback relinquish_display_control_callback_;
-
-  // Used to serialize display event processing. This is done since
-  // opening/closing DRM devices cannot be done on the UI thread and are handled
-  // on a worker thread. Thus, we need to queue events in order to process them
-  // in the correct order.
-  std::queue<DisplayEvent> event_queue_;
-
-  // True if a display event is currently being processed on a worker thread.
-  bool task_pending_ = false;
-
-  // Keeps track of all the active DRM devices. The key is the device path, the
-  // value is the sysfs path which has been resolved from the device path.
-  std::map<base::FilePath, base::FilePath> drm_devices_;
-
-  // This is used to cache the primary DRM device until the channel is
-  // established.
-  scoped_ptr<DrmDeviceHandle> primary_drm_device_handle_;
-
-  base::WeakPtrFactory<DrmDisplayHostManager> weak_ptr_factory_;
+  // Implementation without messaging functionality.
+  scoped_ptr<DrmDisplayHostManagerCore> core_;
 
   DISALLOW_COPY_AND_ASSIGN(DrmDisplayHostManager);
 };
diff --git a/ui/ozone/platform/drm/host/drm_display_host_manager_core.cc b/ui/ozone/platform/drm/host/drm_display_host_manager_core.cc
new file mode 100644
index 0000000..5d17cc4
--- /dev/null
+++ b/ui/ozone/platform/drm/host/drm_display_host_manager_core.cc
@@ -0,0 +1,490 @@
+// 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 "ui/ozone/platform/drm/host/drm_display_host_manager_core.h"
+
+#include <fcntl.h>
+#include <stddef.h>
+#include <xf86drm.h>
+#include <utility>
+
+#include "base/files/file_enumerator.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/threading/worker_pool.h"
+#include "ui/display/types/display_snapshot.h"
+#include "ui/events/ozone/device/device_event.h"
+#include "ui/events/ozone/device/device_manager.h"
+#include "ui/ozone/common/display_util.h"
+#include "ui/ozone/common/gpu/ozone_gpu_messages.h"
+#include "ui/ozone/platform/drm/common/drm_util.h"
+#include "ui/ozone/platform/drm/host/drm_device_handle.h"
+#include "ui/ozone/platform/drm/host/drm_display_host.h"
+#include "ui/ozone/platform/drm/host/drm_gpu_platform_support_host.h"
+#include "ui/ozone/platform/drm/host/drm_native_display_delegate.h"
+
+namespace ui {
+
+namespace {
+
+typedef base::Callback<void(const base::FilePath&,
+                            const base::FilePath&,
+                            scoped_ptr<DrmDeviceHandle>)>
+    OnOpenDeviceReplyCallback;
+
+const char kDefaultGraphicsCardPattern[] = "/dev/dri/card%d";
+const char kVgemDevDriCardPath[] = "/dev/dri/";
+const char kVgemSysCardPath[] = "/sys/bus/platform/devices/vgem/drm/";
+
+const char* kDisplayActionString[] = {
+    "ADD", "REMOVE", "CHANGE",
+};
+
+// Find sysfs device path for the given device path.
+base::FilePath MapDevPathToSysPath(const base::FilePath& device_path) {
+  // |device_path| looks something like /dev/dri/card0. We take the basename of
+  // that (card0) and append it to /sys/class/drm. /sys/class/drm/card0 is a
+  // symlink that points to something like
+  // /sys/devices/pci0000:00/0000:00:02.0/0000:05:00.0/drm/card0, which exposes
+  // some metadata about the attached device.
+  return base::MakeAbsoluteFilePath(
+      base::FilePath("/sys/class/drm").Append(device_path.BaseName()));
+}
+
+void OpenDeviceOnWorkerThread(
+    const base::FilePath& device_path,
+    const scoped_refptr<base::TaskRunner>& reply_runner,
+    const OnOpenDeviceReplyCallback& callback) {
+  base::FilePath sys_path = MapDevPathToSysPath(device_path);
+
+  scoped_ptr<DrmDeviceHandle> handle(new DrmDeviceHandle());
+  handle->Initialize(device_path, sys_path);
+  reply_runner->PostTask(FROM_HERE,
+                         base::Bind(callback, device_path, sys_path,
+                                    base::Passed(std::move(handle))));
+}
+
+base::FilePath GetPrimaryDisplayCardPath() {
+  struct drm_mode_card_res res;
+  for (int i = 0; /* end on first card# that does not exist */; i++) {
+    std::string card_path = base::StringPrintf(kDefaultGraphicsCardPattern, i);
+
+    if (access(card_path.c_str(), F_OK) != 0)
+      break;
+
+    int fd = open(card_path.c_str(), O_RDWR | O_CLOEXEC);
+    if (fd < 0) {
+      VPLOG(1) << "Failed to open '" << card_path << "'";
+      continue;
+    }
+
+    memset(&res, 0, sizeof(struct drm_mode_card_res));
+    int ret = drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res);
+    close(fd);
+    if (ret == 0 && res.count_crtcs > 0) {
+      return base::FilePath(card_path);
+    }
+
+    VPLOG_IF(1, ret) << "Failed to get DRM resources for '" << card_path << "'";
+  }
+
+  LOG(FATAL) << "Failed to open primary graphics device.";
+  return base::FilePath();  // Not reached.
+}
+
+base::FilePath GetVgemCardPath() {
+  base::FileEnumerator file_iter(base::FilePath(kVgemSysCardPath), false,
+                                 base::FileEnumerator::DIRECTORIES,
+                                 FILE_PATH_LITERAL("card*"));
+
+  while (!file_iter.Next().empty()) {
+    // Inspect the card%d directories in the directory and extract the filename.
+    std::string vgem_card_path =
+        kVgemDevDriCardPath + file_iter.GetInfo().GetName().BaseName().value();
+    DVLOG(1) << "VGEM card path is " << vgem_card_path;
+    return base::FilePath(vgem_card_path);
+  }
+  DVLOG(1) << "Don't support VGEM";
+  return base::FilePath();
+}
+
+class FindDrmDisplayHostById {
+ public:
+  explicit FindDrmDisplayHostById(int64_t display_id)
+      : display_id_(display_id) {}
+
+  bool operator()(const scoped_ptr<DrmDisplayHost>& display) const {
+    return display->snapshot()->display_id() == display_id_;
+  }
+
+ private:
+  int64_t display_id_;
+};
+
+}  // namespace
+
+DrmDisplayHostManagerProxy::~DrmDisplayHostManagerProxy() {}
+
+DrmDisplayHostManagerCore::DrmDisplayHostManagerCore(
+    DrmDisplayHostManagerProxy* proxy,
+    DeviceManager* device_manager,
+    InputControllerEvdev* input_controller)
+    : proxy_(proxy),
+      device_manager_(device_manager),
+      input_controller_(input_controller),
+      primary_graphics_card_path_(GetPrimaryDisplayCardPath()),
+      weak_ptr_factory_(this) {
+  {
+    // First device needs to be treated specially. We need to open this
+    // synchronously since the GPU process will need it to initialize the
+    // graphics state.
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
+
+    base::FilePath primary_graphics_card_path_sysfs =
+        MapDevPathToSysPath(primary_graphics_card_path_);
+
+    primary_drm_device_handle_.reset(new DrmDeviceHandle());
+    if (!primary_drm_device_handle_->Initialize(
+            primary_graphics_card_path_, primary_graphics_card_path_sysfs)) {
+      LOG(FATAL) << "Failed to open primary graphics card";
+      return;
+    }
+    drm_devices_[primary_graphics_card_path_] =
+        primary_graphics_card_path_sysfs;
+
+    vgem_card_path_ = GetVgemCardPath();
+  }
+
+  device_manager_->AddObserver(this);
+  proxy_->RegisterHandler();
+
+  ScopedVector<HardwareDisplayControllerInfo> display_infos =
+      GetAvailableDisplayControllerInfos(primary_drm_device_handle_->fd());
+  has_dummy_display_ = !display_infos.empty();
+  for (size_t i = 0; i < display_infos.size(); ++i) {
+    displays_.push_back(make_scoped_ptr(new DrmDisplayHost(
+        proxy_->GetGpuPlatformSupportHost(),
+        CreateDisplaySnapshotParams(
+            display_infos[i], primary_drm_device_handle_->fd(),
+            primary_drm_device_handle_->sys_path(), 0, gfx::Point()),
+        true /* is_dummy */)));
+  }
+}
+
+DrmDisplayHostManagerCore::~DrmDisplayHostManagerCore() {
+  device_manager_->RemoveObserver(this);
+}
+
+DrmDisplayHost* DrmDisplayHostManagerCore::GetDisplay(int64_t display_id) {
+  auto it = std::find_if(displays_.begin(), displays_.end(),
+                         FindDrmDisplayHostById(display_id));
+  if (it == displays_.end())
+    return nullptr;
+
+  return it->get();
+}
+
+void DrmDisplayHostManagerCore::AddDelegate(
+    DrmNativeDisplayDelegate* delegate) {
+  DCHECK(!delegate_);
+  delegate_ = delegate;
+}
+
+void DrmDisplayHostManagerCore::RemoveDelegate(
+    DrmNativeDisplayDelegate* delegate) {
+  DCHECK_EQ(delegate_, delegate);
+  delegate_ = nullptr;
+}
+
+void DrmDisplayHostManagerCore::TakeDisplayControl(
+    const DisplayControlCallback& callback) {
+  if (display_control_change_pending_) {
+    LOG(ERROR) << "TakeDisplayControl called while change already pending";
+    callback.Run(false);
+    return;
+  }
+
+  if (!display_externally_controlled_) {
+    LOG(ERROR) << "TakeDisplayControl called while display already owned";
+    callback.Run(true);
+    return;
+  }
+
+  take_display_control_callback_ = callback;
+  display_control_change_pending_ = true;
+
+  if (!proxy_->TakeDisplayControl())
+    GpuTookDisplayControl(false);
+}
+
+void DrmDisplayHostManagerCore::RelinquishDisplayControl(
+    const DisplayControlCallback& callback) {
+  if (display_control_change_pending_) {
+    LOG(ERROR)
+        << "RelinquishDisplayControl called while change already pending";
+    callback.Run(false);
+    return;
+  }
+
+  if (display_externally_controlled_) {
+    LOG(ERROR) << "RelinquishDisplayControl called while display not owned";
+    callback.Run(true);
+    return;
+  }
+
+  relinquish_display_control_callback_ = callback;
+  display_control_change_pending_ = true;
+
+  if (!proxy_->RelinquishDisplayControl())
+    GpuRelinquishedDisplayControl(false);
+}
+
+void DrmDisplayHostManagerCore::UpdateDisplays(
+    const GetDisplaysCallback& callback) {
+  get_displays_callback_ = callback;
+  if (!proxy_->RefreshNativeDisplays()) {
+    get_displays_callback_.Reset();
+    RunUpdateDisplaysCallback(callback);
+  }
+}
+
+void DrmDisplayHostManagerCore::OnDeviceEvent(const DeviceEvent& event) {
+  if (event.device_type() != DeviceEvent::DISPLAY)
+    return;
+
+  event_queue_.push(DisplayEvent(event.action_type(), event.path()));
+  ProcessEvent();
+}
+
+void DrmDisplayHostManagerCore::ProcessEvent() {
+  while (!event_queue_.empty() && !task_pending_) {
+    DisplayEvent event = event_queue_.front();
+    event_queue_.pop();
+    VLOG(1) << "Got display event " << kDisplayActionString[event.action_type]
+            << " for " << event.path.value();
+    switch (event.action_type) {
+      case DeviceEvent::ADD:
+        if (event.path == vgem_card_path_)
+          continue;
+        if (drm_devices_.find(event.path) == drm_devices_.end()) {
+          task_pending_ = base::WorkerPool::PostTask(
+              FROM_HERE,
+              base::Bind(
+                  &OpenDeviceOnWorkerThread, event.path,
+                  base::ThreadTaskRunnerHandle::Get(),
+                  base::Bind(&DrmDisplayHostManagerCore::OnAddGraphicsDevice,
+                             weak_ptr_factory_.GetWeakPtr())),
+              false /* task_is_slow */);
+        }
+        break;
+      case DeviceEvent::CHANGE:
+        task_pending_ = base::ThreadTaskRunnerHandle::Get()->PostTask(
+            FROM_HERE,
+            base::Bind(&DrmDisplayHostManagerCore::OnUpdateGraphicsDevice,
+                       weak_ptr_factory_.GetWeakPtr()));
+        break;
+      case DeviceEvent::REMOVE:
+        DCHECK(event.path != primary_graphics_card_path_)
+            << "Removing primary graphics card";
+        DCHECK(event.path != vgem_card_path_) << "Removing VGEM device";
+        auto it = drm_devices_.find(event.path);
+        if (it != drm_devices_.end()) {
+          task_pending_ = base::ThreadTaskRunnerHandle::Get()->PostTask(
+              FROM_HERE,
+              base::Bind(&DrmDisplayHostManagerCore::OnRemoveGraphicsDevice,
+                         weak_ptr_factory_.GetWeakPtr(), it->second));
+          drm_devices_.erase(it);
+        }
+        break;
+    }
+  }
+}
+
+void DrmDisplayHostManagerCore::OnAddGraphicsDevice(
+    const base::FilePath& dev_path,
+    const base::FilePath& sys_path,
+    scoped_ptr<DrmDeviceHandle> handle) {
+  if (handle->IsValid()) {
+    drm_devices_[dev_path] = sys_path;
+    proxy_->AddGraphicsDevice(sys_path, base::FileDescriptor(handle->PassFD()));
+    NotifyDisplayDelegate();
+  }
+
+  task_pending_ = false;
+  ProcessEvent();
+}
+
+void DrmDisplayHostManagerCore::OnUpdateGraphicsDevice() {
+  NotifyDisplayDelegate();
+  task_pending_ = false;
+  ProcessEvent();
+}
+
+void DrmDisplayHostManagerCore::OnRemoveGraphicsDevice(
+    const base::FilePath& sys_path) {
+  proxy_->RemoveGraphicsDevice(sys_path);
+  NotifyDisplayDelegate();
+  task_pending_ = false;
+  ProcessEvent();
+}
+
+void DrmDisplayHostManagerCore::GpuThreadStarted() {
+  // If in the middle of a configuration, just respond with the old list of
+  // displays. This is fine, since after the DRM resources are initialized and
+  // IPC-ed to the GPU NotifyDisplayDelegate() is called to let the display
+  // delegate know that the display configuration changed and it needs to
+  // update it again.
+  if (!get_displays_callback_.is_null()) {
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE,
+        base::Bind(&DrmDisplayHostManagerCore::RunUpdateDisplaysCallback,
+                   weak_ptr_factory_.GetWeakPtr(), get_displays_callback_));
+    get_displays_callback_.Reset();
+  }
+
+  // Signal that we're taking DRM master since we're going through the
+  // initialization process again and we'll take all the available resources.
+  if (!take_display_control_callback_.is_null())
+    GpuTookDisplayControl(true);
+
+  if (!relinquish_display_control_callback_.is_null())
+    GpuRelinquishedDisplayControl(false);
+
+  scoped_ptr<DrmDeviceHandle> handle = std::move(primary_drm_device_handle_);
+  {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
+
+    drm_devices_.clear();
+    drm_devices_[primary_graphics_card_path_] =
+        MapDevPathToSysPath(primary_graphics_card_path_);
+
+    if (!handle) {
+      handle.reset(new DrmDeviceHandle());
+      if (!handle->Initialize(primary_graphics_card_path_,
+                              drm_devices_[primary_graphics_card_path_]))
+        LOG(FATAL) << "Failed to open primary graphics card";
+    }
+  }
+
+  // Send the primary device first since this is used to initialize graphics
+  // state.
+  proxy_->AddGraphicsDevice(drm_devices_[primary_graphics_card_path_],
+                            base::FileDescriptor(handle->PassFD()));
+
+  device_manager_->ScanDevices(this);
+  NotifyDisplayDelegate();
+}
+
+void DrmDisplayHostManagerCore::GpuHasUpdatedNativeDisplays(
+    const std::vector<DisplaySnapshot_Params>& params) {
+  std::vector<scoped_ptr<DrmDisplayHost>> old_displays;
+  displays_.swap(old_displays);
+  for (size_t i = 0; i < params.size(); ++i) {
+    auto it = std::find_if(old_displays.begin(), old_displays.end(),
+                           FindDrmDisplayHostById(params[i].display_id));
+    if (it == old_displays.end()) {
+      displays_.push_back(make_scoped_ptr(
+          new DrmDisplayHost(proxy_->GetGpuPlatformSupportHost(), params[i],
+                             false /* is_dummy */)));
+    } else {
+      (*it)->UpdateDisplaySnapshot(params[i]);
+      displays_.push_back(std::move(*it));
+      old_displays.erase(it);
+    }
+  }
+
+  if (!get_displays_callback_.is_null()) {
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE,
+        base::Bind(&DrmDisplayHostManagerCore::RunUpdateDisplaysCallback,
+                   weak_ptr_factory_.GetWeakPtr(), get_displays_callback_));
+    get_displays_callback_.Reset();
+  }
+}
+
+void DrmDisplayHostManagerCore::GpuConfiguredDisplay(int64_t display_id,
+                                                     bool status) {
+  DrmDisplayHost* display = GetDisplay(display_id);
+  if (display)
+    display->OnDisplayConfigured(status);
+  else
+    LOG(ERROR) << "Couldn't find display with id=" << display_id;
+}
+
+void DrmDisplayHostManagerCore::GpuReceivedHDCPState(int64_t display_id,
+                                                     bool status,
+                                                     HDCPState state) {
+  DrmDisplayHost* display = GetDisplay(display_id);
+  if (display)
+    display->OnHDCPStateReceived(status, state);
+  else
+    LOG(ERROR) << "Couldn't find display with id=" << display_id;
+}
+
+void DrmDisplayHostManagerCore::GpuUpdatedHDCPState(int64_t display_id,
+                                                    bool status) {
+  DrmDisplayHost* display = GetDisplay(display_id);
+  if (display)
+    display->OnHDCPStateUpdated(status);
+  else
+    LOG(ERROR) << "Couldn't find display with id=" << display_id;
+}
+
+void DrmDisplayHostManagerCore::GpuTookDisplayControl(bool status) {
+  if (take_display_control_callback_.is_null()) {
+    LOG(ERROR) << "No callback for take display control";
+    return;
+  }
+
+  DCHECK(display_externally_controlled_);
+  DCHECK(display_control_change_pending_);
+
+  if (status) {
+    input_controller_->SetInputDevicesEnabled(true);
+    display_externally_controlled_ = false;
+  }
+
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(take_display_control_callback_, status));
+  take_display_control_callback_.Reset();
+  display_control_change_pending_ = false;
+}
+
+void DrmDisplayHostManagerCore::GpuRelinquishedDisplayControl(bool status) {
+  if (relinquish_display_control_callback_.is_null()) {
+    LOG(ERROR) << "No callback for relinquish display control";
+    return;
+  }
+
+  DCHECK(!display_externally_controlled_);
+  DCHECK(display_control_change_pending_);
+
+  if (status) {
+    input_controller_->SetInputDevicesEnabled(false);
+    display_externally_controlled_ = true;
+  }
+
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(relinquish_display_control_callback_, status));
+  relinquish_display_control_callback_.Reset();
+  display_control_change_pending_ = false;
+}
+
+void DrmDisplayHostManagerCore::RunUpdateDisplaysCallback(
+    const GetDisplaysCallback& callback) const {
+  std::vector<DisplaySnapshot*> snapshots;
+  for (const auto& display : displays_)
+    snapshots.push_back(display->snapshot());
+
+  callback.Run(snapshots);
+}
+
+void DrmDisplayHostManagerCore::NotifyDisplayDelegate() const {
+  if (delegate_)
+    delegate_->OnConfigurationChanged();
+}
+
+}  // namespace ui
diff --git a/ui/ozone/platform/drm/host/drm_display_host_manager_core.h b/ui/ozone/platform/drm/host/drm_display_host_manager_core.h
new file mode 100644
index 0000000..c9f9f31
--- /dev/null
+++ b/ui/ozone/platform/drm/host/drm_display_host_manager_core.h
@@ -0,0 +1,162 @@
+// 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 UI_OZONE_PLATFORM_DRM_HOST_DRM_DISPLAY_HOST_MANAGER_CORE_H_
+#define UI_OZONE_PLATFORM_DRM_HOST_DRM_DISPLAY_HOST_MANAGER_CORE_H_
+
+#include <stdint.h>
+
+#include <map>
+#include <queue>
+
+#include "base/file_descriptor_posix.h"
+#include "base/files/scoped_file.h"
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
+#include "base/memory/weak_ptr.h"
+#include "ui/display/types/native_display_delegate.h"
+#include "ui/events/ozone/device/device_event.h"
+#include "ui/events/ozone/device/device_event_observer.h"
+#include "ui/events/ozone/evdev/event_factory_evdev.h"
+#include "ui/ozone/public/gpu_platform_support_host.h"
+
+namespace ui {
+
+class DeviceManager;
+class DrmDeviceHandle;
+class DrmDisplayHost;
+class DrmDisplayHostManagerCore;
+class DrmGpuPlatformSupportHost;
+class DrmNativeDisplayDelegate;
+
+struct DisplaySnapshot_Params;
+
+// The concrete implementation of DrmDisplayHostManagerCoreProxy contains all
+// the
+// necessary code for the DrmDisplayHostManagerCoreCore to communicate with
+// the GPU child thread whether by IPC or thead-hop.
+class DrmDisplayHostManagerProxy {
+ public:
+  virtual ~DrmDisplayHostManagerProxy();
+  virtual void RegisterHandler() = 0;
+  virtual DrmGpuPlatformSupportHost* GetGpuPlatformSupportHost() = 0;
+  virtual bool TakeDisplayControl() = 0;
+  virtual bool RefreshNativeDisplays() = 0;
+  virtual bool RelinquishDisplayControl() = 0;
+  virtual bool AddGraphicsDevice(const base::FilePath& path,
+                                 base::FileDescriptor fd) = 0;
+  virtual bool RemoveGraphicsDevice(const base::FilePath& path) = 0;
+};
+
+// The portion of the DrmDisplayHostManagerCore implementation that is agnostic
+// in how its communication with GPU-specific functionality is implemented.
+// This is used from both the IPC and the in-process versions in  MUS.
+class DrmDisplayHostManagerCore : public DeviceEventObserver {
+ public:
+  DrmDisplayHostManagerCore(DrmDisplayHostManagerProxy* proxy,
+                            DeviceManager* device_manager,
+                            InputControllerEvdev* input_controller);
+  ~DrmDisplayHostManagerCore() override;
+
+  DrmDisplayHost* GetDisplay(int64_t display_id);
+
+  // External API.
+  void AddDelegate(DrmNativeDisplayDelegate* delegate);
+  void RemoveDelegate(DrmNativeDisplayDelegate* delegate);
+  void TakeDisplayControl(const DisplayControlCallback& callback);
+  void RelinquishDisplayControl(const DisplayControlCallback& callback);
+  void UpdateDisplays(const GetDisplaysCallback& callback);
+
+  // DeviceEventObserver overrides:
+  void OnDeviceEvent(const DeviceEvent& event) override;
+
+  // Communication-free implementations of actions performed in response to
+  // messages from the GPU thread.
+  void GpuThreadStarted();
+  void GpuHasUpdatedNativeDisplays(
+      const std::vector<DisplaySnapshot_Params>& displays);
+  void GpuConfiguredDisplay(int64_t display_id, bool status);
+  void GpuReceivedHDCPState(int64_t display_id, bool status, HDCPState state);
+  void GpuUpdatedHDCPState(int64_t display_id, bool status);
+  void GpuTookDisplayControl(bool status);
+  void GpuRelinquishedDisplayControl(bool status);
+
+ private:
+  struct DisplayEvent {
+    DisplayEvent(DeviceEvent::ActionType action_type,
+                 const base::FilePath& path)
+        : action_type(action_type), path(path) {}
+
+    DeviceEvent::ActionType action_type;
+    base::FilePath path;
+  };
+
+  // Handle hotplug events sequentially.
+  void ProcessEvent();
+
+  // Called as a result of finishing to process the display hotplug event. These
+  // are responsible for dequing the event and scheduling the next event.
+  void OnAddGraphicsDevice(const base::FilePath& path,
+                           const base::FilePath& sysfs_path,
+                           scoped_ptr<DrmDeviceHandle> handle);
+  void OnUpdateGraphicsDevice();
+  void OnRemoveGraphicsDevice(const base::FilePath& path);
+
+  void RunUpdateDisplaysCallback(const GetDisplaysCallback& callback) const;
+
+  void NotifyDisplayDelegate() const;
+
+  DrmDisplayHostManagerProxy* proxy_;       // Not owned.
+  DeviceManager* device_manager_;           // Not owned.
+  InputControllerEvdev* input_controller_;  // Not owned.
+
+  DrmNativeDisplayDelegate* delegate_ = nullptr;  // Not owned.
+
+  // File path for the primary graphics card which is opened by default in the
+  // GPU process. We'll avoid opening this in hotplug events since it will race
+  // with the GPU process trying to open it and aquire DRM master.
+  base::FilePath primary_graphics_card_path_;
+
+  // File path for virtual gem (VGEM) device.
+  base::FilePath vgem_card_path_;
+
+  // Keeps track if there is a dummy display. This happens on initialization
+  // when there is no connection to the GPU to update the displays.
+  bool has_dummy_display_ = false;
+
+  std::vector<scoped_ptr<DrmDisplayHost>> displays_;
+
+  GetDisplaysCallback get_displays_callback_;
+
+  bool display_externally_controlled_ = false;
+  bool display_control_change_pending_ = false;
+  DisplayControlCallback take_display_control_callback_;
+  DisplayControlCallback relinquish_display_control_callback_;
+
+  // Used to serialize display event processing. This is done since
+  // opening/closing DRM devices cannot be done on the UI thread and are handled
+  // on a worker thread. Thus, we need to queue events in order to process them
+  // in the correct order.
+  std::queue<DisplayEvent> event_queue_;
+
+  // True if a display event is currently being processed on a worker thread.
+  bool task_pending_ = false;
+
+  // Keeps track of all the active DRM devices. The key is the device path, the
+  // value is the sysfs path which has been resolved from the device path.
+  std::map<base::FilePath, base::FilePath> drm_devices_;
+
+  // This is used to cache the primary DRM device until the channel is
+  // established.
+  scoped_ptr<DrmDeviceHandle> primary_drm_device_handle_;
+
+  base::WeakPtrFactory<DrmDisplayHostManagerCore> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(DrmDisplayHostManagerCore);
+};
+
+}  // namespace ui
+
+#endif  // UI_OZONE_PLATFORM_DRM_HOST_DRM_DISPLAY_HOST_MANAGER_CORE_H_