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/libs/vr/libdvrcommon/revision.cpp b/libs/vr/libdvrcommon/revision.cpp
new file mode 100644
index 0000000..ae8603f
--- /dev/null
+++ b/libs/vr/libdvrcommon/revision.cpp
@@ -0,0 +1,175 @@
+#include "private/dvr/revision.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <base/logging.h>
+
+#include "revision_path.h"
+
+namespace {
+
+// Allows quicker access to the product revision. If non-zero, then
+// the product revision file has already been processed.
+static bool global_product_revision_processed = false;
+
+static bool global_serial_number_processed = false;
+
+// The product.
+static DvrProduct global_product = DVR_PRODUCT_UNKNOWN;
+
+// The revision.
+static DvrRevision global_revision = DVR_REVISION_UNKNOWN;
+
+// Maximum size of the product revision string.
+constexpr int kProductRevisionStringSize = 32;
+
+// Maximum size of the serial number.
+constexpr int kSerialNumberStringSize = 32;
+
+// The product revision string.
+static char global_product_revision_str[kProductRevisionStringSize + 1] = "";
+
+// The serial number string
+static char global_serial_number[kSerialNumberStringSize + 1] = "";
+
+// Product and revision combinations.
+struct DvrProductRevision {
+  const char* str;
+  DvrProduct product;
+  DvrRevision revision;
+};
+
+// Null-terminated list of all product and revision combinations.
+static constexpr DvrProductRevision kProductRevisions[] = {
+    {"a00-p1", DVR_PRODUCT_A00, DVR_REVISION_P1},
+    {"a00-p2", DVR_PRODUCT_A00, DVR_REVISION_P2},
+    {"a00-p3", DVR_PRODUCT_A00, DVR_REVISION_P3},
+    {"twilight-p1", DVR_PRODUCT_A65R, DVR_REVISION_P1},
+    {"twilight-p2", DVR_PRODUCT_A65R, DVR_REVISION_P2},
+    {NULL, DVR_PRODUCT_UNKNOWN, DVR_REVISION_UNKNOWN}};
+
+// Read the product revision string, and store the global data.
+static void process_product_revision() {
+  int fd;
+  ssize_t read_rc;
+  const DvrProductRevision* product_revision = kProductRevisions;
+
+  // Of course in a multi-threaded environment, for a few microseconds
+  // during process startup, it is possible that this function will be
+  // called and execute fully multiple times. That is why the product
+  // revision string is statically allocated.
+
+  if (global_product_revision_processed)
+    return;
+
+  // Whether there was a failure or not, we don't want to do this again.
+  // Upon failure it's most likely to fail again anyway.
+
+  fd = open(dvr_product_revision_file_path(), O_RDONLY);
+  if (fd < 0) {
+    PLOG(ERROR) << "Could not open '" << dvr_product_revision_file_path()
+                << "' to get product revision";
+    global_product_revision_processed = true;
+    return;
+  }
+
+  read_rc = read(fd, global_product_revision_str, kProductRevisionStringSize);
+  if (read_rc <= 0) {
+    PLOG(ERROR) << "Could not read from '" << dvr_product_revision_file_path()
+                << "'";
+    global_product_revision_processed = true;
+    return;
+  }
+
+  close(fd);
+
+  global_product_revision_str[read_rc] = '\0';
+
+  while (product_revision->str) {
+    if (!strcmp(product_revision->str, global_product_revision_str))
+      break;
+    product_revision++;
+  }
+
+  if (product_revision->str) {
+    global_product = product_revision->product;
+    global_revision = product_revision->revision;
+  } else {
+    LOG(ERROR) << "Unable to match '" << global_product_revision_str
+               << "' to a product/revision.";
+  }
+
+  global_product_revision_processed = true;
+}
+
+}  // anonymous namespace
+
+extern "C" DvrProduct dvr_get_product() {
+  process_product_revision();
+  return global_product;
+}
+
+extern "C" DvrRevision dvr_get_revision() {
+  process_product_revision();
+  return global_revision;
+}
+
+extern "C" const char* dvr_get_product_revision_str() {
+  process_product_revision();
+  return global_product_revision_str;
+}
+
+extern "C" const char* dvr_get_serial_number() {
+  process_product_revision();
+  if (global_product == DVR_PRODUCT_A00) {
+    if (!global_serial_number_processed) {
+#ifdef DVR_HOST
+      global_serial_number_processed = true;
+#else
+      int width = 4;
+      uintptr_t addr = 0x00074138;
+      uintptr_t endaddr = addr + width - 1;
+
+      int fd = open("/dev/mem", O_RDWR | O_SYNC);
+      if (fd < 0) {
+        if (errno == EPERM)
+          global_serial_number_processed = true;
+        fprintf(stderr, "cannot open /dev/mem\n");
+        return global_serial_number;
+      }
+
+      off64_t mmap_start = addr & ~(PAGE_SIZE - 1);
+      size_t mmap_size = endaddr - mmap_start + 1;
+      mmap_size = (mmap_size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
+
+      void* page = mmap64(0, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd,
+                          mmap_start);
+
+      if (page == MAP_FAILED) {
+        global_serial_number_processed = true;
+        fprintf(stderr, "cannot mmap region\n");
+        close(fd);
+        return global_serial_number;
+      }
+
+      uint32_t* x =
+          reinterpret_cast<uint32_t*>((((uintptr_t)page) + (addr & 4095)));
+      snprintf(global_serial_number, kSerialNumberStringSize, "%08x", *x);
+      global_serial_number_processed = true;
+
+      munmap(page, mmap_size);
+      close(fd);
+#endif
+    }
+    return global_serial_number;
+  } else {
+    return nullptr;
+  }
+}