Add DaydreamVR native libraries and services

Upstreaming the main VR system components from master-dreamos-dev
into goog/master.

Bug: None
Test: `m -j32` succeeds. Sailfish boots and basic_vr sample app works
Change-Id: I853015872afc443aecee10411ef2d6b79184d051
diff --git a/services/vr/virtual_touchpad/Android.mk b/services/vr/virtual_touchpad/Android.mk
new file mode 100644
index 0000000..4224aaa
--- /dev/null
+++ b/services/vr/virtual_touchpad/Android.mk
@@ -0,0 +1,76 @@
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+
+# Touchpad implementation.
+
+src := \
+  EvdevInjector.cpp \
+  VirtualTouchpad.cpp
+
+shared_libs := \
+  libbase
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(src)
+LOCAL_SHARED_LIBRARIES := $(shared_libs)
+LOCAL_CPPFLAGS += -std=c++11
+LOCAL_CFLAGS += -DLOG_TAG=\"VrVirtualTouchpad\"
+LOCAL_MODULE := libvirtualtouchpad
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_STATIC_LIBRARY)
+
+
+# Touchpad unit tests.
+
+test_src_files := \
+  tests/VirtualTouchpad_test.cpp
+
+static_libs := \
+  libbase \
+  libcutils \
+  libvirtualtouchpad
+
+$(foreach file,$(test_src_files), \
+    $(eval include $(CLEAR_VARS)) \
+    $(eval LOCAL_SRC_FILES := $(file)) \
+    $(eval LOCAL_STATIC_LIBRARIES := $(static_libs)) \
+    $(eval LOCAL_SHARED_LIBRARIES := $(shared_libs)) \
+    $(eval LOCAL_CPPFLAGS += -std=c++11) \
+    $(eval LOCAL_LDLIBS := -llog) \
+    $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \
+    $(eval LOCAL_MODULE_TAGS := optional) \
+    $(eval LOCAL_CXX_STL := libc++_static) \
+    $(eval include $(BUILD_NATIVE_TEST)) \
+)
+
+
+# Service.
+
+src := \
+  main.cpp \
+  VirtualTouchpadService.cpp \
+  aidl/android/dvr/VirtualTouchpadService.aidl
+
+static_libs := \
+  libcutils \
+  libvirtualtouchpad
+
+shared_libs := \
+  libbase \
+  libbinder \
+  libutils
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(src)
+LOCAL_STATIC_LIBRARIES := $(static_libs)
+LOCAL_SHARED_LIBRARIES := $(shared_libs)
+LOCAL_CPPFLAGS += -std=c++11
+LOCAL_CFLAGS += -DLOG_TAG=\"VrVirtualTouchpad\"
+LOCAL_LDLIBS := -llog
+LOCAL_MODULE := virtual_touchpad
+LOCAL_MODULE_TAGS := optional
+LOCAL_INIT_RC := virtual_touchpad.rc
+LOCAL_MULTILIB := 64
+LOCAL_CXX_STL := libc++_static
+include $(BUILD_EXECUTABLE)
diff --git a/services/vr/virtual_touchpad/EvdevInjector.cpp b/services/vr/virtual_touchpad/EvdevInjector.cpp
new file mode 100644
index 0000000..be20c6c
--- /dev/null
+++ b/services/vr/virtual_touchpad/EvdevInjector.cpp
@@ -0,0 +1,311 @@
+#include "EvdevInjector.h"
+
+#include <cutils/log.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <linux/input.h>
+#include <string.h>
+#include <sys/fcntl.h>
+#include <unistd.h>
+
+namespace android {
+namespace dvr {
+
+int EvdevInjector::UInput::Open() {
+  errno = 0;
+  fd_.reset(open("/dev/uinput", O_WRONLY | O_NONBLOCK));
+  if (fd_.get() < 0) {
+    ALOGE("couldn't open uinput (r=%d errno=%d)", fd_.get(), errno);
+  }
+  return errno;
+}
+
+int EvdevInjector::UInput::Close() {
+  errno = 0;
+  fd_.reset();
+  return errno;
+}
+
+int EvdevInjector::UInput::Write(const void* buf, size_t count) {
+  ALOGV("UInput::Write(%zu, %02X...)", count, *static_cast<const char*>(buf));
+  errno = 0;
+  ssize_t r = write(fd_.get(), buf, count);
+  if (r != static_cast<ssize_t>(count)) {
+    ALOGE("write(%zu) failed (r=%zd errno=%d)", count, r, errno);
+  }
+  return errno;
+}
+
+int EvdevInjector::UInput::IoctlSetInt(int request, int value) {
+  ALOGV("UInput::IoctlSetInt(0x%X, 0x%X)", request, value);
+  errno = 0;
+  if (const int status = ioctl(fd_.get(), request, value)) {
+    ALOGE("ioctl(%d, 0x%X, 0x%X) failed (r=%d errno=%d)", fd_.get(), request,
+          value, status, errno);
+  }
+  return errno;
+}
+
+int EvdevInjector::UInput::IoctlVoid(int request) {
+  ALOGV("UInput::IoctlVoid(0x%X)", request);
+  errno = 0;
+  if (const int status = ioctl(fd_.get(), request)) {
+    ALOGE("ioctl(%d, 0x%X) failed (r=%d errno=%d)", fd_.get(), request, status,
+          errno);
+  }
+  return errno;
+}
+
+void EvdevInjector::Close() {
+  uinput_->Close();
+  state_ = State::CLOSED;
+}
+
+int EvdevInjector::ConfigureBegin(const char* device_name, int16_t bustype,
+                                  int16_t vendor, int16_t product,
+                                  int16_t version) {
+  ALOGV("ConfigureBegin %s 0x%04" PRIX16 " 0x%04" PRIX16 " 0x%04" PRIX16
+        " 0x%04" PRIX16 "",
+        device_name, bustype, vendor, product, version);
+  if (!device_name || strlen(device_name) >= UINPUT_MAX_NAME_SIZE) {
+    return Error(ERROR_DEVICE_NAME);
+  }
+  if (const int status = RequireState(State::NEW)) {
+    return status;
+  }
+  if (!uinput_) {
+    owned_uinput_.reset(new EvdevInjector::UInput());
+    uinput_ = owned_uinput_.get();
+  }
+  if (const int status = uinput_->Open()) {
+    // Without uinput we're dead in the water.
+    state_ = State::CLOSED;
+    return Error(status);
+  }
+  state_ = State::CONFIGURING;
+  // Initialize device setting structure.
+  memset(&uidev_, 0, sizeof(uidev_));
+  strncpy(uidev_.name, device_name, UINPUT_MAX_NAME_SIZE);
+  uidev_.id.bustype = bustype;
+  uidev_.id.vendor = vendor;
+  uidev_.id.product = product;
+  uidev_.id.version = version;
+  return 0;
+}
+
+int EvdevInjector::ConfigureInputProperty(int property) {
+  ALOGV("ConfigureInputProperty %d", property);
+  if (property < 0 || property >= INPUT_PROP_CNT) {
+    ALOGE("property 0x%X out of range [0,0x%X)", property, INPUT_PROP_CNT);
+    return Error(ERROR_PROPERTY_RANGE);
+  }
+  if (const int status = RequireState(State::CONFIGURING)) {
+    return status;
+  }
+  if (const int status = uinput_->IoctlSetInt(UI_SET_PROPBIT, property)) {
+    ALOGE("failed to set property %d", property);
+    return Error(status);
+  }
+  return 0;
+}
+
+int EvdevInjector::ConfigureKey(uint16_t key) {
+  ALOGV("ConfigureKey 0x%02" PRIX16 "", key);
+  if (key < 0 || key >= KEY_CNT) {
+    ALOGE("key 0x%X out of range [0,0x%X)", key, KEY_CNT);
+    return Error(ERROR_KEY_RANGE);
+  }
+  if (const int status = RequireState(State::CONFIGURING)) {
+    return status;
+  }
+  if (const int status = EnableEventType(EV_KEY)) {
+    return status;
+  }
+  if (const int status = uinput_->IoctlSetInt(UI_SET_KEYBIT, key)) {
+    ALOGE("failed to enable EV_KEY 0x%02" PRIX16 "", key);
+    return Error(status);
+  }
+  return 0;
+}
+
+int EvdevInjector::ConfigureAbs(uint16_t abs_type, int32_t min, int32_t max,
+                                int32_t fuzz, int32_t flat) {
+  ALOGV("ConfigureAbs 0x%" PRIX16 " %" PRId32 " %" PRId32 " %" PRId32
+        " %" PRId32 "",
+        abs_type, min, max, fuzz, flat);
+  if (abs_type < 0 || abs_type >= ABS_CNT) {
+    ALOGE("EV_ABS type 0x%" PRIX16 " out of range [0,0x%X)", abs_type, ABS_CNT);
+    return Error(ERROR_ABS_RANGE);
+  }
+  if (const int status = RequireState(State::CONFIGURING)) {
+    return status;
+  }
+  if (const int status = EnableEventType(EV_ABS)) {
+    return status;
+  }
+  if (const int status = uinput_->IoctlSetInt(UI_SET_ABSBIT, abs_type)) {
+    ALOGE("failed to enable EV_ABS 0x%" PRIX16 "", abs_type);
+    return Error(status);
+  }
+  uidev_.absmin[abs_type] = min;
+  uidev_.absmax[abs_type] = max;
+  uidev_.absfuzz[abs_type] = fuzz;
+  uidev_.absflat[abs_type] = flat;
+  return 0;
+}
+
+int EvdevInjector::ConfigureMultiTouchXY(int x0, int y0, int x1, int y1) {
+  if (const int status = ConfigureAbs(ABS_MT_POSITION_X, x0, x1, 0, 0)) {
+    return status;
+  }
+  if (const int status = ConfigureAbs(ABS_MT_POSITION_Y, y0, y1, 0, 0)) {
+    return status;
+  }
+  return 0;
+}
+
+int EvdevInjector::ConfigureAbsSlots(int slots) {
+  return ConfigureAbs(ABS_MT_SLOT, 0, slots, 0, 0);
+}
+
+int EvdevInjector::ConfigureEnd() {
+  ALOGV("ConfigureEnd:");
+  ALOGV("  name=\"%s\"", uidev_.name);
+  ALOGV("  id.bustype=0x%04" PRIX16, uidev_.id.bustype);
+  ALOGV("  id.vendor=0x%04" PRIX16, uidev_.id.vendor);
+  ALOGV("  id.product=0x%04" PRIX16, uidev_.id.product);
+  ALOGV("  id.version=0x%04" PRIX16, uidev_.id.version);
+  ALOGV("  ff_effects_max=%" PRIu32, uidev_.ff_effects_max);
+  for (int i = 0; i < ABS_CNT; ++i) {
+    if (uidev_.absmin[i]) {
+      ALOGV("  absmin[%d]=%" PRId32, i, uidev_.absmin[i]);
+    }
+    if (uidev_.absmax[i]) {
+      ALOGV("  absmax[%d]=%" PRId32, i, uidev_.absmax[i]);
+    }
+    if (uidev_.absfuzz[i]) {
+      ALOGV("  absfuzz[%d]=%" PRId32, i, uidev_.absfuzz[i]);
+    }
+    if (uidev_.absflat[i]) {
+      ALOGV("  absflat[%d]=%" PRId32, i, uidev_.absflat[i]);
+    }
+  }
+
+  if (const int status = RequireState(State::CONFIGURING)) {
+    return status;
+  }
+  // Write out device settings.
+  if (const int status = uinput_->Write(&uidev_, sizeof uidev_)) {
+    ALOGE("failed to write device settings");
+    return Error(status);
+  }
+  // Create device node.
+  if (const int status = uinput_->IoctlVoid(UI_DEV_CREATE)) {
+    ALOGE("failed to create device node");
+    return Error(status);
+  }
+  state_ = State::READY;
+  return 0;
+}
+
+int EvdevInjector::Send(uint16_t type, uint16_t code, int32_t value) {
+  ALOGV("Send(0x%" PRIX16 ", 0x%" PRIX16 ", 0x%" PRIX32 ")", type, code, value);
+  if (const int status = RequireState(State::READY)) {
+    return status;
+  }
+  struct input_event event;
+  memset(&event, 0, sizeof(event));
+  event.type = type;
+  event.code = code;
+  event.value = value;
+  if (const int status = uinput_->Write(&event, sizeof(event))) {
+    ALOGE("failed to write event 0x%" PRIX16 ", 0x%" PRIX16 ", 0x%" PRIX32,
+          type, code, value);
+    return Error(status);
+  }
+  return 0;
+}
+
+int EvdevInjector::SendSynReport() { return Send(EV_SYN, SYN_REPORT, 0); }
+
+int EvdevInjector::SendKey(uint16_t code, int32_t value) {
+  return Send(EV_KEY, code, value);
+}
+
+int EvdevInjector::SendAbs(uint16_t code, int32_t value) {
+  return Send(EV_ABS, code, value);
+}
+
+int EvdevInjector::SendMultiTouchSlot(int32_t slot) {
+  if (latest_slot_ != slot) {
+    if (const int status = SendAbs(ABS_MT_SLOT, slot)) {
+      return status;
+    }
+    latest_slot_ = slot;
+  }
+  return 0;
+}
+
+int EvdevInjector::SendMultiTouchXY(int32_t slot, int32_t id, int32_t x,
+                                    int32_t y) {
+  if (const int status = SendMultiTouchSlot(slot)) {
+    return status;
+  }
+  if (const int status = SendAbs(ABS_MT_TRACKING_ID, id)) {
+    return status;
+  }
+  if (const int status = SendAbs(ABS_MT_POSITION_X, x)) {
+    return status;
+  }
+  if (const int status = SendAbs(ABS_MT_POSITION_Y, y)) {
+    return status;
+  }
+  return 0;
+}
+
+int EvdevInjector::SendMultiTouchLift(int32_t slot) {
+  if (const int status = SendMultiTouchSlot(slot)) {
+    return status;
+  }
+  if (const int status = SendAbs(ABS_MT_TRACKING_ID, -1)) {
+    return status;
+  }
+  return 0;
+}
+
+int EvdevInjector::Error(int code) {
+  if (!error_) {
+    error_ = code;
+  }
+  return code;
+}
+
+int EvdevInjector::RequireState(State required_state) {
+  if (error_) {
+    return error_;
+  }
+  if (state_ != required_state) {
+    ALOGE("in state %d but require state %d", static_cast<int>(state_),
+          static_cast<int>(required_state));
+    return Error(ERROR_SEQUENCING);
+  }
+  return 0;
+}
+
+int EvdevInjector::EnableEventType(uint16_t type) {
+  if (const int status = RequireState(State::CONFIGURING)) {
+    return status;
+  }
+  if (enabled_event_types_.count(type) > 0) {
+    return 0;
+  }
+  if (const int status = uinput_->IoctlSetInt(UI_SET_EVBIT, type)) {
+    ALOGE("failed to enable event type 0x%X", type);
+    return Error(status);
+  }
+  enabled_event_types_.insert(type);
+  return 0;
+}
+
+}  // namespace dvr
+}  // namespace android
diff --git a/services/vr/virtual_touchpad/EvdevInjector.h b/services/vr/virtual_touchpad/EvdevInjector.h
new file mode 100644
index 0000000..1b1c4da
--- /dev/null
+++ b/services/vr/virtual_touchpad/EvdevInjector.h
@@ -0,0 +1,139 @@
+#ifndef ANDROID_DVR_EVDEV_INJECTOR_H
+#define ANDROID_DVR_EVDEV_INJECTOR_H
+
+#include <android-base/unique_fd.h>
+#include <linux/uinput.h>
+
+#include <cstdint>
+#include <memory>
+#include <unordered_set>
+
+namespace android {
+namespace dvr {
+
+// Simulated evdev input device.
+//
+class EvdevInjector {
+ public:
+  // EvdevInjector-specific error codes are negative integers; other non-zero
+  // values returned from public routines are |errno| codes from underlying I/O.
+  // EvdevInjector maintains a 'sticky' error state, similar to |errno|, so that
+  // a caller can perform a sequence of operations and check for errors at the
+  // end using |GetError()|. In general, the first such error will be recorded
+  // and will suppress effects of further device operations until |ResetError()|
+  // is called.
+  //
+  enum : int {
+    ERROR_DEVICE_NAME = -1,     // Invalid device name.
+    ERROR_PROPERTY_RANGE = -2,  // |INPUT_PROP_*| code out of range.
+    ERROR_KEY_RANGE = -3,       // |KEY_*|/|BTN_*| code out of range.
+    ERROR_ABS_RANGE = -4,       // |ABS_*| code out of range.
+    ERROR_SEQUENCING = -5,      // Configure/Send out of order.
+  };
+
+  // Key event |value| is not defined in <linux/input.h>.
+  enum : int32_t { KEY_RELEASE = 0, KEY_PRESS = 1, KEY_REPEAT = 2 };
+
+  // UInput provides a shim to intercept /dev/uinput operations
+  // just above the system call level, for testing.
+  //
+  class UInput {
+   public:
+    UInput() {}
+    virtual ~UInput() {}
+    virtual int Open();
+    virtual int Close();
+    virtual int Write(const void* buf, size_t count);
+    virtual int IoctlVoid(int request);
+    virtual int IoctlSetInt(int request, int value);
+
+   private:
+    base::unique_fd fd_;
+  };
+
+  EvdevInjector() {}
+  ~EvdevInjector() { Close(); }
+  void Close();
+
+  int GetError() const { return error_; }
+  void ResetError() { error_ = 0; }
+
+  // Configuration must be performed before sending any events.
+  // |ConfigureBegin()| must be called first, and |ConfigureEnd()| last,
+  // with zero or more other |Configure...()| calls in between in any order.
+
+  // Configure the basic evdev device properties; must be called first.
+  int ConfigureBegin(const char* device_name, int16_t bustype, int16_t vendor,
+                     int16_t product, int16_t version);
+
+  // Configure an optional input device property.
+  // @param property  One of the |INPUT_PROP_*| constants from <linux/input.h>.
+  int ConfigureInputProperty(int property);
+
+  // Configure an input key.
+  // @param key One of the |KEY_*| or |BTN_*| constants from <linux/input.h>.
+  int ConfigureKey(uint16_t key);
+
+  // Configure an absolute axis.
+  // @param abs_type One of the |KEY_*| or |BTN_*| constants from
+  // <linux/input.h>.
+  int ConfigureAbs(uint16_t abs_type, int32_t min, int32_t max, int32_t fuzz,
+                   int32_t flat);
+
+  // Configure the number of multitouch slots.
+  int ConfigureAbsSlots(int slots);
+
+  // Configure multitouch coordinate range.
+  int ConfigureMultiTouchXY(int32_t x0, int32_t y0, int32_t x1, int32_t y1);
+
+  // Complete configuration and create the input device.
+  int ConfigureEnd();
+
+  // Send various events.
+  //
+  int Send(uint16_t type, uint16_t code, int32_t value);
+  int SendSynReport();
+  int SendKey(uint16_t code, int32_t value);
+  int SendAbs(uint16_t code, int32_t value);
+  int SendMultiTouchSlot(int32_t slot);
+  int SendMultiTouchXY(int32_t slot, int32_t id, int32_t x, int32_t y);
+  int SendMultiTouchLift(int32_t slot);
+
+ protected:
+  // Must be called only between construction and ConfigureBegin().
+  inline void SetUInputForTesting(UInput* uinput) { uinput_ = uinput; }
+  // Caller must not retain pointer longer than EvdevInjector.
+  inline const uinput_user_dev* GetUiDevForTesting() const { return &uidev_; }
+
+ private:
+  // Phase to enforce that configuration is complete before events are sent.
+  enum class State { NEW, CONFIGURING, READY, CLOSED };
+
+  // Sets |error_| if it is not already set; returns |code|.
+  int Error(int code);
+
+  // Returns a nonzero error if the injector is not in the required |state|.
+  int RequireState(State state);
+
+  // Configures an event type if necessary.
+  // @param type One of the |EV_*| constants from <linux/input.h>.
+  int EnableEventType(uint16_t type);
+
+  // Active pointer to owned or testing UInput.
+  UInput* uinput_ = nullptr;
+  std::unique_ptr<UInput> owned_uinput_;
+
+  State state_ = State::NEW;
+  int error_ = 0;
+  uinput_user_dev uidev_;
+  std::unordered_set<uint16_t> enabled_event_types_;
+  int32_t latest_slot_ = -1;
+
+  EvdevInjector(const EvdevInjector&) = delete;
+  void operator=(const EvdevInjector&) = delete;
+};
+
+}  // namespace dvr
+}  // namespace android
+
+#endif  // ANDROID_DVR_EVDEV_INJECTOR_H
diff --git a/services/vr/virtual_touchpad/VirtualTouchpad.cpp b/services/vr/virtual_touchpad/VirtualTouchpad.cpp
new file mode 100644
index 0000000..b137dd7
--- /dev/null
+++ b/services/vr/virtual_touchpad/VirtualTouchpad.cpp
@@ -0,0 +1,80 @@
+#include "VirtualTouchpad.h"
+
+#include <cutils/log.h>
+#include <inttypes.h>
+#include <linux/input.h>
+
+namespace android {
+namespace dvr {
+
+namespace {
+
+// Virtual evdev device properties.
+static const char* const kDeviceName = "vr window manager virtual touchpad";
+static constexpr int16_t kDeviceBusType = BUS_VIRTUAL;
+static constexpr int16_t kDeviceVendor = 0x18D1;   // Google USB vendor ID.
+static constexpr int16_t kDeviceProduct = 0x5652;  // 'VR'
+static constexpr int16_t kDeviceVersion = 0x0001;
+static constexpr int32_t kWidth = 0x10000;
+static constexpr int32_t kHeight = 0x10000;
+static constexpr int32_t kSlots = 2;
+
+}  // anonymous namespace
+
+int VirtualTouchpad::Initialize() {
+  if (!injector_) {
+    owned_injector_.reset(new EvdevInjector());
+    injector_ = owned_injector_.get();
+  }
+  injector_->ConfigureBegin(kDeviceName, kDeviceBusType, kDeviceVendor,
+                            kDeviceProduct, kDeviceVersion);
+  injector_->ConfigureInputProperty(INPUT_PROP_DIRECT);
+  injector_->ConfigureMultiTouchXY(0, 0, kWidth - 1, kHeight - 1);
+  injector_->ConfigureAbsSlots(kSlots);
+  injector_->ConfigureKey(BTN_TOUCH);
+  injector_->ConfigureEnd();
+  return injector_->GetError();
+}
+
+int VirtualTouchpad::Touch(float x, float y, float pressure) {
+  int error = 0;
+  int32_t device_x = x * kWidth;
+  int32_t device_y = y * kHeight;
+  touches_ = ((touches_ & 1) << 1) | (pressure > 0);
+  ALOGV("(%f,%f) %f -> (%" PRId32 ",%" PRId32 ") %d",
+        x, y, pressure, device_x, device_y, touches_);
+
+  injector_->ResetError();
+  switch (touches_) {
+    case 0b00:  // Hover continues.
+      if (device_x != last_device_x_ || device_y != last_device_y_) {
+        injector_->SendMultiTouchXY(0, 0, device_x, device_y);
+        injector_->SendSynReport();
+      }
+      break;
+    case 0b01:  // Touch begins.
+      // Press.
+      injector_->SendMultiTouchXY(0, 0, device_x, device_y);
+      injector_->SendKey(BTN_TOUCH, EvdevInjector::KEY_PRESS);
+      injector_->SendSynReport();
+      break;
+    case 0b10:  // Touch ends.
+      injector_->SendKey(BTN_TOUCH, EvdevInjector::KEY_RELEASE);
+      injector_->SendMultiTouchLift(0);
+      injector_->SendSynReport();
+      break;
+    case 0b11:  // Touch continues.
+      if (device_x != last_device_x_ || device_y != last_device_y_) {
+        injector_->SendMultiTouchXY(0, 0, device_x, device_y);
+        injector_->SendSynReport();
+      }
+      break;
+  }
+  last_device_x_ = device_x;
+  last_device_y_ = device_y;
+
+  return injector_->GetError();
+}
+
+}  // namespace dvr
+}  // namespace android
diff --git a/services/vr/virtual_touchpad/VirtualTouchpad.h b/services/vr/virtual_touchpad/VirtualTouchpad.h
new file mode 100644
index 0000000..7e7801e
--- /dev/null
+++ b/services/vr/virtual_touchpad/VirtualTouchpad.h
@@ -0,0 +1,44 @@
+#ifndef ANDROID_DVR_VIRTUAL_TOUCHPAD_H
+#define ANDROID_DVR_VIRTUAL_TOUCHPAD_H
+
+#include <memory>
+
+#include "EvdevInjector.h"
+
+namespace android {
+namespace dvr {
+
+class EvdevInjector;
+
+class VirtualTouchpad {
+ public:
+  VirtualTouchpad() {}
+  int Initialize();
+  int Touch(float x, float y, float pressure);
+
+ protected:
+  // Must be called only between construction and Initialize().
+  inline void SetEvdevInjectorForTesting(EvdevInjector* injector) {
+    injector_ = injector;
+  }
+
+ private:
+  // Active pointer to |owned_injector_| or to a testing injector.
+  EvdevInjector* injector_ = nullptr;
+  std::unique_ptr<EvdevInjector> owned_injector_;
+
+  // Previous (x,y) position to suppress redundant events.
+  int32_t last_device_x_ = INT32_MIN;
+  int32_t last_device_y_ = INT32_MIN;
+
+  // Records current touch state in bit 0 and previous state in bit 1.
+  int touches_ = 0;
+
+  VirtualTouchpad(const VirtualTouchpad&) = delete;
+  void operator=(const VirtualTouchpad&) = delete;
+};
+
+}  // namespace dvr
+}  // namespace android
+
+#endif  // ANDROID_DVR_VIRTUAL_TOUCHPAD_H
diff --git a/services/vr/virtual_touchpad/VirtualTouchpadService.cpp b/services/vr/virtual_touchpad/VirtualTouchpadService.cpp
new file mode 100644
index 0000000..e5ead0e
--- /dev/null
+++ b/services/vr/virtual_touchpad/VirtualTouchpadService.cpp
@@ -0,0 +1,23 @@
+#include "VirtualTouchpadService.h"
+
+#include <binder/Status.h>
+#include <cutils/log.h>
+#include <linux/input.h>
+#include <utils/Errors.h>
+
+namespace android {
+namespace dvr {
+
+int VirtualTouchpadService::Initialize() {
+  return touchpad_.Initialize();
+}
+
+binder::Status VirtualTouchpadService::touch(float x, float y, float pressure) {
+  // Permissions check added and removed here :^)
+  const int error = touchpad_.Touch(x, y, pressure);
+  return error ? binder::Status::fromServiceSpecificError(error)
+               : binder::Status::ok();
+}
+
+}  // namespace dvr
+}  // namespace android
diff --git a/services/vr/virtual_touchpad/VirtualTouchpadService.h b/services/vr/virtual_touchpad/VirtualTouchpadService.h
new file mode 100644
index 0000000..05a2a50
--- /dev/null
+++ b/services/vr/virtual_touchpad/VirtualTouchpadService.h
@@ -0,0 +1,36 @@
+#ifndef ANDROID_DVR_VIRTUAL_TOUCHPAD_SERVICE_H
+#define ANDROID_DVR_VIRTUAL_TOUCHPAD_SERVICE_H
+
+#include <android/dvr/BnVirtualTouchpadService.h>
+
+#include "VirtualTouchpad.h"
+
+namespace android {
+namespace dvr {
+
+class VirtualTouchpadService : public BnVirtualTouchpadService {
+ public:
+  VirtualTouchpadService(VirtualTouchpad& touchpad)
+      : touchpad_(touchpad) {}
+
+  // Must be called before clients can connect.
+  // Returns 0 if initialization is successful.
+  int Initialize();
+
+  static char const* getServiceName() { return "virtual_touchpad"; }
+
+ protected:
+  // Implements IVirtualTouchpadService.
+  ::android::binder::Status touch(float x, float y, float pressure) override;
+
+ private:
+  VirtualTouchpad& touchpad_;
+
+  VirtualTouchpadService(const VirtualTouchpadService&) = delete;
+  void operator=(const VirtualTouchpadService&) = delete;
+};
+
+}  // namespace dvr
+}  // namespace android
+
+#endif  // ANDROID_DVR_VIRTUAL_TOUCHPAD_SERVICE_H
diff --git a/services/vr/virtual_touchpad/aidl/android/dvr/VirtualTouchpadService.aidl b/services/vr/virtual_touchpad/aidl/android/dvr/VirtualTouchpadService.aidl
new file mode 100644
index 0000000..da4de94
--- /dev/null
+++ b/services/vr/virtual_touchpad/aidl/android/dvr/VirtualTouchpadService.aidl
@@ -0,0 +1,16 @@
+package android.dvr;
+
+/** @hide */
+interface VirtualTouchpadService
+{
+  /**
+   * Generate a simulated touch event.
+   *
+   * @param x Horizontal touch position.
+   * @param y Vertical touch position.
+   * @param pressure Touch pressure; use 0.0 for no touch (lift or hover).
+   *
+   * Position values in the range [0.0, 1.0) map to the screen.
+   */
+  void touch(float x, float y, float pressure);
+}
diff --git a/services/vr/virtual_touchpad/main.cpp b/services/vr/virtual_touchpad/main.cpp
new file mode 100644
index 0000000..57471c5
--- /dev/null
+++ b/services/vr/virtual_touchpad/main.cpp
@@ -0,0 +1,36 @@
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <cutils/log.h>
+
+#include "VirtualTouchpadService.h"
+
+int main() {
+  ALOGI("Starting");
+  android::dvr::VirtualTouchpad touchpad;
+  android::dvr::VirtualTouchpadService touchpad_service(touchpad);
+  const int touchpad_status = touchpad_service.Initialize();
+  if (touchpad_status) {
+    ALOGE("virtual touchpad initialization failed: %d", touchpad_status);
+    exit(1);
+  }
+
+  signal(SIGPIPE, SIG_IGN);
+  android::sp<android::ProcessState> ps(android::ProcessState::self());
+  ps->setThreadPoolMaxThreadCount(4);
+  ps->startThreadPool();
+  ps->giveThreadPoolName();
+
+  android::sp<android::IServiceManager> sm(android::defaultServiceManager());
+  const android::status_t service_status =
+      sm->addService(android::String16(touchpad_service.getServiceName()),
+                     &touchpad_service, false /*allowIsolated*/);
+  if (service_status != android::OK) {
+    ALOGE("virtual touchpad service not added: %d",
+          static_cast<int>(service_status));
+    exit(2);
+  }
+
+  android::IPCThreadState::self()->joinThreadPool();
+  return 0;
+}
diff --git a/services/vr/virtual_touchpad/tests/VirtualTouchpad_test.cpp b/services/vr/virtual_touchpad/tests/VirtualTouchpad_test.cpp
new file mode 100644
index 0000000..874ef80
--- /dev/null
+++ b/services/vr/virtual_touchpad/tests/VirtualTouchpad_test.cpp
@@ -0,0 +1,233 @@
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <gtest/gtest.h>
+#include <linux/input.h>
+
+#include "EvdevInjector.h"
+#include "VirtualTouchpad.h"
+
+namespace android {
+namespace dvr {
+
+namespace {
+
+class UInputForTesting : public EvdevInjector::UInput {
+ public:
+  void WriteInputEvent(uint16_t type, uint16_t code, int32_t value) {
+    struct input_event event;
+    memset(&event, 0, sizeof(event));
+    event.type = type;
+    event.code = code;
+    event.value = value;
+    Write(&event, sizeof (event));
+  }
+};
+
+// Recording test implementation of UInput.
+//
+class UInputRecorder : public UInputForTesting {
+ public:
+  UInputRecorder() {}
+  virtual ~UInputRecorder() {}
+
+  const std::string& GetString() const { return s_; }
+  void Reset() { s_.clear(); }
+
+  // UInput overrides:
+
+  int Open() override {
+    s_ += "o;";
+    return 0;
+  }
+
+  int Close() override {
+    s_ += "c;";
+    return 0;
+  }
+
+  int Write(const void* buf, size_t count) override {
+    s_ += "w(";
+    s_ += Encode(&count, sizeof(count));
+    s_ += ",";
+    s_ += Encode(buf, count);
+    s_ += ");";
+    return 0;
+  }
+
+  int IoctlVoid(int request) override {
+    s_ += "i(";
+    s_ += Encode(&request, sizeof(request));
+    s_ += ");";
+    return 0;
+  }
+
+  int IoctlSetInt(int request, int value) override {
+    s_ += "i(";
+    s_ += Encode(&request, sizeof(request));
+    s_ += ",";
+    s_ += Encode(&value, sizeof(value));
+    s_ += ");";
+    return 0;
+  }
+
+ private:
+  std::string s_;
+
+  std::string Encode(const void* buf, size_t count) {
+    const char* in = static_cast<const char*>(buf);
+    char out[2 * count + 1];
+    for (size_t i = 0; i < count; ++i) {
+      snprintf(&out[2 * i], 3, "%02X", in[i]);
+    }
+    return out;
+  }
+};
+
+class EvdevInjectorForTesting : public EvdevInjector {
+ public:
+  EvdevInjectorForTesting(UInput& uinput) {
+    SetUInputForTesting(&uinput);
+  }
+  const uinput_user_dev* GetUiDev() const { return GetUiDevForTesting(); }
+};
+
+class VirtualTouchpadForTesting : public VirtualTouchpad {
+ public:
+  VirtualTouchpadForTesting(EvdevInjector& injector) {
+    SetEvdevInjectorForTesting(&injector);
+  }
+};
+
+void DumpDifference(const char* expect, const char* actual) {
+  printf("  common: ");
+  while (*expect && *expect == *actual) {
+    putchar(*expect);
+    ++expect;
+    ++actual;
+  }
+  printf("\n  expect: %s\n", expect);
+  printf("  actual: %s\n", actual);
+}
+
+}  // anonymous namespace
+
+class VirtualTouchpadTest : public testing::Test {
+};
+
+TEST_F(VirtualTouchpadTest, Goodness) {
+  UInputRecorder expect;
+  UInputRecorder record;
+  EvdevInjectorForTesting injector(record);
+  VirtualTouchpadForTesting touchpad(injector);
+
+  const int initialization_status = touchpad.Initialize();
+  EXPECT_EQ(0, initialization_status);
+
+  // Check some aspects of uinput_user_dev.
+  const uinput_user_dev* uidev = injector.GetUiDev();
+  for (int i = 0; i < ABS_CNT; ++i) {
+    EXPECT_EQ(0, uidev->absmin[i]);
+    EXPECT_EQ(0, uidev->absfuzz[i]);
+    EXPECT_EQ(0, uidev->absflat[i]);
+    if (i != ABS_MT_POSITION_X && i != ABS_MT_POSITION_Y && i != ABS_MT_SLOT) {
+      EXPECT_EQ(0, uidev->absmax[i]);
+    }
+  }
+  const int32_t width = 1 + uidev->absmax[ABS_MT_POSITION_X];
+  const int32_t height = 1 + uidev->absmax[ABS_MT_POSITION_Y];
+  const int32_t slots = uidev->absmax[ABS_MT_SLOT];
+
+  // Check the system calls performed by initialization.
+  // From ConfigureBegin():
+  expect.Open();
+  // From ConfigureInputProperty(INPUT_PROP_DIRECT):
+  expect.IoctlSetInt(UI_SET_PROPBIT, INPUT_PROP_DIRECT);
+  // From ConfigureMultiTouchXY(0, 0, kWidth - 1, kHeight - 1):
+  expect.IoctlSetInt(UI_SET_EVBIT, EV_ABS);
+  expect.IoctlSetInt(UI_SET_ABSBIT, ABS_MT_POSITION_X);
+  expect.IoctlSetInt(UI_SET_ABSBIT, ABS_MT_POSITION_Y);
+  // From ConfigureAbsSlots(kSlots):
+  expect.IoctlSetInt(UI_SET_ABSBIT, ABS_MT_SLOT);
+  // From ConfigureKey(BTN_TOUCH):
+  expect.IoctlSetInt(UI_SET_EVBIT, EV_KEY);
+  expect.IoctlSetInt(UI_SET_KEYBIT, BTN_TOUCH);
+  // From ConfigureEnd():
+  expect.Write(uidev, sizeof (uinput_user_dev));
+  expect.IoctlVoid(UI_DEV_CREATE);
+  EXPECT_EQ(expect.GetString(), record.GetString());
+
+  expect.Reset();
+  record.Reset();
+  int touch_status = touchpad.Touch(0, 0, 0);
+  EXPECT_EQ(0, touch_status);
+  expect.WriteInputEvent(EV_ABS, ABS_MT_SLOT, 0);
+  expect.WriteInputEvent(EV_ABS, ABS_MT_TRACKING_ID, 0);
+  expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_X, 0);
+  expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_Y, 0);
+  expect.WriteInputEvent(EV_SYN, SYN_REPORT, 0);
+  EXPECT_EQ(expect.GetString(), record.GetString());
+
+  expect.Reset();
+  record.Reset();
+  touch_status = touchpad.Touch(0.25f, 0.75f, 0.5f);
+  EXPECT_EQ(0, touch_status);
+  expect.WriteInputEvent(EV_ABS, ABS_MT_TRACKING_ID, 0);
+  expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_X, 0.25f * width);
+  expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_Y, 0.75f * height);
+  expect.WriteInputEvent(EV_KEY, BTN_TOUCH, EvdevInjector::KEY_PRESS);
+  expect.WriteInputEvent(EV_SYN, SYN_REPORT, 0);
+  EXPECT_EQ(expect.GetString(), record.GetString());
+
+  expect.Reset();
+  record.Reset();
+  touch_status = touchpad.Touch(1.0f, 1.0f, 1.0f);
+  EXPECT_EQ(0, touch_status);
+  expect.WriteInputEvent(EV_ABS, ABS_MT_TRACKING_ID, 0);
+  expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_X, width);
+  expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_Y, height);
+  expect.WriteInputEvent(EV_SYN, SYN_REPORT, 0);
+  EXPECT_EQ(expect.GetString(), record.GetString());
+
+  expect.Reset();
+  record.Reset();
+  touch_status = touchpad.Touch(0.25f, 0.75f, -0.01f);
+  EXPECT_EQ(0, touch_status);
+  expect.WriteInputEvent(EV_KEY, BTN_TOUCH, EvdevInjector::KEY_RELEASE);
+  expect.WriteInputEvent(EV_ABS, ABS_MT_TRACKING_ID, -1);
+  expect.WriteInputEvent(EV_SYN, SYN_REPORT, 0);
+  EXPECT_EQ(expect.GetString(), record.GetString());
+
+  expect.Reset();
+  record.Reset();
+}
+
+TEST_F(VirtualTouchpadTest, Badness) {
+  UInputRecorder expect;
+  UInputRecorder record;
+  EvdevInjectorForTesting injector(record);
+  VirtualTouchpadForTesting touchpad(injector);
+
+  // Touch before initialization should return an error,
+  // and should not result in any system calls.
+  expect.Reset();
+  record.Reset();
+  int touch_status = touchpad.Touch(0.25f, 0.75f, -0.01f);
+  EXPECT_NE(0, touch_status);
+  EXPECT_EQ(expect.GetString(), record.GetString());
+
+  expect.Reset();
+  record.Reset();
+  touchpad.Initialize();
+
+  // Repeated initialization should return an error,
+  // and should not result in any system calls.
+  expect.Reset();
+  record.Reset();
+  const int initialization_status = touchpad.Initialize();
+  EXPECT_NE(0, initialization_status);
+  EXPECT_EQ(expect.GetString(), record.GetString());
+}
+
+}  // namespace dvr
+}  // namespace android
diff --git a/services/vr/virtual_touchpad/virtual_touchpad.rc b/services/vr/virtual_touchpad/virtual_touchpad.rc
new file mode 100644
index 0000000..b4f9f00
--- /dev/null
+++ b/services/vr/virtual_touchpad/virtual_touchpad.rc
@@ -0,0 +1,5 @@
+service virtual_touchpad /system/bin/virtual_touchpad
+  class core
+  user system
+  group system input
+  cpuset /system